refactor: move inbound config
This commit is contained in:
@@ -158,9 +158,7 @@ describe("heartbeat helpers", () => {
|
||||
});
|
||||
|
||||
it("resolves heartbeat minutes with default and overrides", () => {
|
||||
const cfgBase: ClawdisConfig = {
|
||||
inbound: {},
|
||||
};
|
||||
const cfgBase: ClawdisConfig = {};
|
||||
expect(resolveReplyHeartbeatMinutes(cfgBase)).toBe(30);
|
||||
expect(
|
||||
resolveReplyHeartbeatMinutes({
|
||||
@@ -183,10 +181,10 @@ describe("resolveHeartbeatRecipients", () => {
|
||||
main: { updatedAt: now, lastChannel: "whatsapp", lastTo: "+1000" },
|
||||
});
|
||||
const cfg: ClawdisConfig = {
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1999"],
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
session: { store: store.storePath },
|
||||
};
|
||||
const result = resolveHeartbeatRecipients(cfg);
|
||||
expect(result.source).toBe("session-single");
|
||||
@@ -201,10 +199,10 @@ describe("resolveHeartbeatRecipients", () => {
|
||||
alt: { updatedAt: now - 10, lastChannel: "whatsapp", lastTo: "+2000" },
|
||||
});
|
||||
const cfg: ClawdisConfig = {
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1999"],
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
session: { store: store.storePath },
|
||||
};
|
||||
const result = resolveHeartbeatRecipients(cfg);
|
||||
expect(result.source).toBe("session-ambiguous");
|
||||
@@ -215,10 +213,10 @@ describe("resolveHeartbeatRecipients", () => {
|
||||
it("filters wildcard allowFrom when no sessions exist", async () => {
|
||||
const store = await makeSessionStore({});
|
||||
const cfg: ClawdisConfig = {
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"],
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
session: { store: store.storePath },
|
||||
};
|
||||
const result = resolveHeartbeatRecipients(cfg);
|
||||
expect(result.recipients).toHaveLength(0);
|
||||
@@ -232,10 +230,10 @@ describe("resolveHeartbeatRecipients", () => {
|
||||
main: { updatedAt: now, lastChannel: "whatsapp", lastTo: "+1000" },
|
||||
});
|
||||
const cfg: ClawdisConfig = {
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1999"],
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
session: { store: store.storePath },
|
||||
};
|
||||
const result = resolveHeartbeatRecipients(cfg, { all: true });
|
||||
expect(result.source).toBe("all");
|
||||
@@ -253,7 +251,7 @@ describe("partial reply gating", () => {
|
||||
const replyResolver = vi.fn().mockResolvedValue({ text: "final reply" });
|
||||
|
||||
const mockConfig: ClawdisConfig = {
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
};
|
||||
@@ -300,10 +298,10 @@ describe("partial reply gating", () => {
|
||||
const replyResolver = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
const mockConfig: ClawdisConfig = {
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"],
|
||||
session: { store: store.storePath, mainKey: "main" },
|
||||
},
|
||||
session: { store: store.storePath, mainKey: "main" },
|
||||
};
|
||||
|
||||
setLoadConfigMock(mockConfig);
|
||||
@@ -391,10 +389,10 @@ describe("runWebHeartbeatOnce", () => {
|
||||
const resolver = vi.fn(async () => ({ text: HEARTBEAT_TOKEN }));
|
||||
await runWebHeartbeatOnce({
|
||||
cfg: {
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1555"],
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
to: "+1555",
|
||||
verbose: false,
|
||||
@@ -414,10 +412,10 @@ describe("runWebHeartbeatOnce", () => {
|
||||
const resolver = vi.fn(async () => ({ text: "ALERT" }));
|
||||
await runWebHeartbeatOnce({
|
||||
cfg: {
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1555"],
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
to: "+1555",
|
||||
verbose: false,
|
||||
@@ -443,10 +441,10 @@ describe("runWebHeartbeatOnce", () => {
|
||||
await fs.writeFile(storePath, JSON.stringify(sessionEntries));
|
||||
await runWebHeartbeatOnce({
|
||||
cfg: {
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1999"],
|
||||
session: { store: storePath },
|
||||
},
|
||||
session: { store: storePath },
|
||||
},
|
||||
to: "+1999",
|
||||
verbose: false,
|
||||
@@ -472,13 +470,13 @@ describe("runWebHeartbeatOnce", () => {
|
||||
const sender: typeof sendMessageWhatsApp = vi.fn();
|
||||
const resolver = vi.fn(async () => ({ text: HEARTBEAT_TOKEN }));
|
||||
setLoadConfigMock({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1555"],
|
||||
session: {
|
||||
store: storePath,
|
||||
idleMinutes: 60,
|
||||
heartbeatIdleMinutes: 10,
|
||||
},
|
||||
},
|
||||
session: {
|
||||
store: storePath,
|
||||
idleMinutes: 60,
|
||||
heartbeatIdleMinutes: 10,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -509,19 +507,19 @@ describe("runWebHeartbeatOnce", () => {
|
||||
|
||||
setLoadConfigMock(() => ({
|
||||
agent: { heartbeatMinutes: 0.001 },
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+4367"],
|
||||
session: { store: storePath, idleMinutes: 60 },
|
||||
},
|
||||
session: { store: storePath, idleMinutes: 60 },
|
||||
}));
|
||||
|
||||
const replyResolver = vi.fn().mockResolvedValue({ text: HEARTBEAT_TOKEN });
|
||||
const runtime = { log: vi.fn(), error: vi.fn(), exit: vi.fn() } as never;
|
||||
const cfg: ClawdisConfig = {
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+4367"],
|
||||
session: { store: storePath, idleMinutes: 60 },
|
||||
},
|
||||
session: { store: storePath, idleMinutes: 60 },
|
||||
};
|
||||
|
||||
await runWebHeartbeatOnce({
|
||||
@@ -547,18 +545,18 @@ describe("runWebHeartbeatOnce", () => {
|
||||
|
||||
const sessionId = "override-123";
|
||||
setLoadConfigMock(() => ({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1999"],
|
||||
session: { store: storePath, idleMinutes: 60 },
|
||||
},
|
||||
session: { store: storePath, idleMinutes: 60 },
|
||||
}));
|
||||
|
||||
const resolver = vi.fn(async () => ({ text: HEARTBEAT_TOKEN }));
|
||||
const cfg: ClawdisConfig = {
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1999"],
|
||||
session: { store: storePath, idleMinutes: 60 },
|
||||
},
|
||||
session: { store: storePath, idleMinutes: 60 },
|
||||
};
|
||||
await runWebHeartbeatOnce({
|
||||
cfg,
|
||||
@@ -586,10 +584,10 @@ describe("runWebHeartbeatOnce", () => {
|
||||
const resolver = vi.fn();
|
||||
await runWebHeartbeatOnce({
|
||||
cfg: {
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1555"],
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
to: "+1555",
|
||||
verbose: false,
|
||||
@@ -610,10 +608,10 @@ describe("runWebHeartbeatOnce", () => {
|
||||
const resolver = vi.fn();
|
||||
await runWebHeartbeatOnce({
|
||||
cfg: {
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1555"],
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
to: "+1555",
|
||||
verbose: false,
|
||||
@@ -762,10 +760,10 @@ describe("web auto-reply", () => {
|
||||
const runtime = { log: vi.fn(), error: vi.fn(), exit: vi.fn() } as never;
|
||||
|
||||
setLoadConfigMock(() => ({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1555"],
|
||||
session: { store: storePath },
|
||||
},
|
||||
session: { store: storePath },
|
||||
}));
|
||||
|
||||
const controller = new AbortController();
|
||||
@@ -820,11 +818,11 @@ describe("web auto-reply", () => {
|
||||
const runtime = { log: vi.fn(), error: vi.fn(), exit: vi.fn() } as never;
|
||||
|
||||
setLoadConfigMock(() => ({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1555"],
|
||||
groupChat: { requireMention: true, mentionPatterns: ["@clawd"] },
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
session: { store: store.storePath },
|
||||
}));
|
||||
|
||||
const controller = new AbortController();
|
||||
@@ -921,10 +919,10 @@ describe("web auto-reply", () => {
|
||||
};
|
||||
|
||||
setLoadConfigMock(() => ({
|
||||
inbound: {
|
||||
messages: {
|
||||
timestampPrefix: "UTC",
|
||||
session: { store: store.storePath },
|
||||
},
|
||||
session: { store: store.storePath },
|
||||
}));
|
||||
|
||||
await monitorWebProvider(false, listenerFactory, false, resolver);
|
||||
@@ -1473,10 +1471,10 @@ describe("web auto-reply", () => {
|
||||
});
|
||||
|
||||
setLoadConfigMock(() => ({
|
||||
inbound: {
|
||||
routing: {
|
||||
groupChat: { mentionPatterns: ["@clawd"] },
|
||||
session: { store: storePath },
|
||||
},
|
||||
session: { store: storePath },
|
||||
}));
|
||||
|
||||
let capturedOnMessage:
|
||||
@@ -1547,7 +1545,7 @@ describe("web auto-reply", () => {
|
||||
const resolver = vi.fn().mockResolvedValue({ text: "ok" });
|
||||
|
||||
setLoadConfigMock(() => ({
|
||||
inbound: {
|
||||
routing: {
|
||||
// Self-chat heuristic: allowFrom includes selfE164.
|
||||
allowFrom: ["+999"],
|
||||
groupChat: {
|
||||
@@ -1697,8 +1695,10 @@ describe("web auto-reply", () => {
|
||||
it("prefixes body with same-phone marker when from === to", async () => {
|
||||
// Enable messagePrefix for same-phone mode testing
|
||||
setLoadConfigMock(() => ({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: "[same-phone]",
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
@@ -1820,8 +1820,10 @@ describe("web auto-reply", () => {
|
||||
|
||||
it("applies responsePrefix to regular replies", async () => {
|
||||
setLoadConfigMock(() => ({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: "🦞",
|
||||
timestampPrefix: false,
|
||||
@@ -1863,8 +1865,10 @@ describe("web auto-reply", () => {
|
||||
|
||||
it("skips responsePrefix for HEARTBEAT_OK responses", async () => {
|
||||
setLoadConfigMock(() => ({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: "🦞",
|
||||
timestampPrefix: false,
|
||||
@@ -1907,8 +1911,10 @@ describe("web auto-reply", () => {
|
||||
|
||||
it("does not double-prefix if responsePrefix already present", async () => {
|
||||
setLoadConfigMock(() => ({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: "🦞",
|
||||
timestampPrefix: false,
|
||||
@@ -1951,8 +1957,10 @@ describe("web auto-reply", () => {
|
||||
|
||||
it("sends tool summaries immediately with responsePrefix", async () => {
|
||||
setLoadConfigMock(() => ({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: "🦞",
|
||||
timestampPrefix: false,
|
||||
|
||||
@@ -113,7 +113,7 @@ type MentionConfig = {
|
||||
};
|
||||
|
||||
function buildMentionConfig(cfg: ReturnType<typeof loadConfig>): MentionConfig {
|
||||
const gc = cfg.inbound?.groupChat;
|
||||
const gc = cfg.routing?.groupChat;
|
||||
const mentionRegexes =
|
||||
gc?.mentionPatterns
|
||||
?.map((p) => {
|
||||
@@ -124,7 +124,7 @@ function buildMentionConfig(cfg: ReturnType<typeof loadConfig>): MentionConfig {
|
||||
}
|
||||
})
|
||||
.filter((r): r is RegExp => Boolean(r)) ?? [];
|
||||
return { mentionRegexes, allowFrom: cfg.inbound?.allowFrom };
|
||||
return { mentionRegexes, allowFrom: cfg.routing?.allowFrom };
|
||||
}
|
||||
|
||||
function isBotMentioned(
|
||||
@@ -252,12 +252,12 @@ export async function runWebHeartbeatOnce(opts: {
|
||||
});
|
||||
|
||||
const cfg = cfgOverride ?? loadConfig();
|
||||
const sessionCfg = cfg.inbound?.session;
|
||||
const sessionCfg = cfg.session;
|
||||
const sessionScope = sessionCfg?.scope ?? "per-sender";
|
||||
const mainKey = sessionCfg?.mainKey;
|
||||
const sessionKey = resolveSessionKey(sessionScope, { From: to }, mainKey);
|
||||
if (sessionId) {
|
||||
const storePath = resolveStorePath(cfg.inbound?.session?.store);
|
||||
const storePath = resolveStorePath(cfg.session?.store);
|
||||
const store = loadSessionStore(storePath);
|
||||
const current = store[sessionKey] ?? {};
|
||||
store[sessionKey] = {
|
||||
@@ -356,7 +356,7 @@ export async function runWebHeartbeatOnce(opts: {
|
||||
const stripped = stripHeartbeatToken(replyPayload.text);
|
||||
if (stripped.shouldSkip && !hasMedia) {
|
||||
// Don't let heartbeats keep sessions alive: restore previous updatedAt so idle expiry still works.
|
||||
const storePath = resolveStorePath(cfg.inbound?.session?.store);
|
||||
const storePath = resolveStorePath(cfg.session?.store);
|
||||
const store = loadSessionStore(storePath);
|
||||
if (sessionSnapshot.entry && store[sessionSnapshot.key]) {
|
||||
store[sessionSnapshot.key].updatedAt = sessionSnapshot.entry.updatedAt;
|
||||
@@ -420,7 +420,7 @@ export async function runWebHeartbeatOnce(opts: {
|
||||
}
|
||||
|
||||
function getFallbackRecipient(cfg: ReturnType<typeof loadConfig>) {
|
||||
const sessionCfg = cfg.inbound?.session;
|
||||
const sessionCfg = cfg.session;
|
||||
const storePath = resolveStorePath(sessionCfg?.store);
|
||||
const store = loadSessionStore(storePath);
|
||||
const mainKey = (sessionCfg?.mainKey ?? "main").trim() || "main";
|
||||
@@ -433,18 +433,18 @@ function getFallbackRecipient(cfg: ReturnType<typeof loadConfig>) {
|
||||
}
|
||||
|
||||
const allowFrom =
|
||||
Array.isArray(cfg.inbound?.allowFrom) && cfg.inbound.allowFrom.length > 0
|
||||
? cfg.inbound.allowFrom.filter((v) => v !== "*")
|
||||
Array.isArray(cfg.routing?.allowFrom) && cfg.routing.allowFrom.length > 0
|
||||
? cfg.routing.allowFrom.filter((v) => v !== "*")
|
||||
: [];
|
||||
if (allowFrom.length === 0) return null;
|
||||
return allowFrom[0] ? normalizeE164(allowFrom[0]) : null;
|
||||
}
|
||||
|
||||
function getSessionRecipients(cfg: ReturnType<typeof loadConfig>) {
|
||||
const sessionCfg = cfg.inbound?.session;
|
||||
const sessionCfg = cfg.session;
|
||||
const scope = sessionCfg?.scope ?? "per-sender";
|
||||
if (scope === "global") return [];
|
||||
const storePath = resolveStorePath(cfg.inbound?.session?.store);
|
||||
const storePath = resolveStorePath(cfg.session?.store);
|
||||
const store = loadSessionStore(storePath);
|
||||
const isGroupKey = (key: string) =>
|
||||
key.startsWith("group:") || key.includes("@g.us");
|
||||
@@ -480,8 +480,8 @@ export function resolveHeartbeatRecipients(
|
||||
|
||||
const sessionRecipients = getSessionRecipients(cfg);
|
||||
const allowFrom =
|
||||
Array.isArray(cfg.inbound?.allowFrom) && cfg.inbound.allowFrom.length > 0
|
||||
? cfg.inbound.allowFrom.filter((v) => v !== "*").map(normalizeE164)
|
||||
Array.isArray(cfg.routing?.allowFrom) && cfg.routing.allowFrom.length > 0
|
||||
? cfg.routing.allowFrom.filter((v) => v !== "*").map(normalizeE164)
|
||||
: [];
|
||||
|
||||
const unique = (list: string[]) => [...new Set(list.filter(Boolean))];
|
||||
@@ -509,7 +509,7 @@ function getSessionSnapshot(
|
||||
from: string,
|
||||
isHeartbeat = false,
|
||||
) {
|
||||
const sessionCfg = cfg.inbound?.session;
|
||||
const sessionCfg = cfg.session;
|
||||
const scope = sessionCfg?.scope ?? "per-sender";
|
||||
const key = resolveSessionKey(
|
||||
scope,
|
||||
@@ -773,9 +773,9 @@ export async function monitorWebProvider(
|
||||
);
|
||||
const reconnectPolicy = resolveReconnectPolicy(cfg, tuning.reconnect);
|
||||
const mentionConfig = buildMentionConfig(cfg);
|
||||
const sessionStorePath = resolveStorePath(cfg.inbound?.session?.store);
|
||||
const sessionStorePath = resolveStorePath(cfg.session?.store);
|
||||
const groupHistoryLimit =
|
||||
cfg.inbound?.groupChat?.historyLimit ?? DEFAULT_GROUP_HISTORY_LIMIT;
|
||||
cfg.routing?.groupChat?.historyLimit ?? DEFAULT_GROUP_HISTORY_LIMIT;
|
||||
const groupHistories = new Map<
|
||||
string,
|
||||
Array<{ sender: string; body: string; timestamp?: number }>
|
||||
@@ -854,7 +854,7 @@ export async function monitorWebProvider(
|
||||
: `group:${conversationId}`;
|
||||
const store = loadSessionStore(sessionStorePath);
|
||||
const entry = store[key];
|
||||
const requireMention = cfg.inbound?.groupChat?.requireMention;
|
||||
const requireMention = cfg.routing?.groupChat?.requireMention;
|
||||
const defaultActivation = requireMention === false ? "always" : "mention";
|
||||
return (
|
||||
normalizeGroupActivation(entry?.groupActivation) ?? defaultActivation
|
||||
@@ -953,9 +953,9 @@ export async function monitorWebProvider(
|
||||
|
||||
const buildLine = (msg: WebInboundMsg) => {
|
||||
// Build message prefix: explicit config > default based on allowFrom
|
||||
let messagePrefix = cfg.inbound?.messagePrefix;
|
||||
let messagePrefix = cfg.messages?.messagePrefix;
|
||||
if (messagePrefix === undefined) {
|
||||
const hasAllowFrom = (cfg.inbound?.allowFrom?.length ?? 0) > 0;
|
||||
const hasAllowFrom = (cfg.routing?.allowFrom?.length ?? 0) > 0;
|
||||
messagePrefix = hasAllowFrom ? "" : "[clawdis]";
|
||||
}
|
||||
const prefixStr = messagePrefix ? `${messagePrefix} ` : "";
|
||||
@@ -1045,7 +1045,7 @@ export async function monitorWebProvider(
|
||||
}
|
||||
|
||||
if (msg.chatType !== "group") {
|
||||
const sessionCfg = cfg.inbound?.session;
|
||||
const sessionCfg = cfg.session;
|
||||
const mainKey = (sessionCfg?.mainKey ?? "main").trim() || "main";
|
||||
const storePath = resolveStorePath(sessionCfg?.store);
|
||||
const to = (() => {
|
||||
@@ -1075,7 +1075,7 @@ export async function monitorWebProvider(
|
||||
}
|
||||
}
|
||||
|
||||
const responsePrefix = cfg.inbound?.responsePrefix;
|
||||
const responsePrefix = cfg.messages?.responsePrefix;
|
||||
let didSendReply = false;
|
||||
let toolSendChain: Promise<void> = Promise.resolve();
|
||||
const sendToolResult = (payload: ReplyPayload) => {
|
||||
@@ -1580,7 +1580,7 @@ export async function monitorWebProvider(
|
||||
|
||||
// Apply response prefix if configured (same as regular messages)
|
||||
let finalText = stripped.text;
|
||||
const responsePrefix = cfg.inbound?.responsePrefix;
|
||||
const responsePrefix = cfg.messages?.responsePrefix;
|
||||
if (
|
||||
responsePrefix &&
|
||||
finalText &&
|
||||
|
||||
@@ -7,8 +7,10 @@ import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
loadConfig: vi.fn().mockReturnValue({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"], // Allow all in tests
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
|
||||
@@ -145,7 +145,7 @@ export async function monitorWebInbox(options: {
|
||||
// Filter unauthorized senders early to prevent wasted processing
|
||||
// and potential session corruption from Bad MAC errors
|
||||
const cfg = loadConfig();
|
||||
const configuredAllowFrom = cfg.inbound?.allowFrom;
|
||||
const configuredAllowFrom = cfg.routing?.allowFrom;
|
||||
// Without user config, default to self-only DM access so the owner can talk to themselves
|
||||
const defaultAllowFrom =
|
||||
(!configuredAllowFrom || configuredAllowFrom.length === 0) && selfE164
|
||||
|
||||
@@ -10,8 +10,10 @@ vi.mock("../media/store.js", () => ({
|
||||
}));
|
||||
|
||||
const mockLoadConfig = vi.fn().mockReturnValue({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"], // Allow all in tests by default
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
@@ -411,8 +413,10 @@ describe("web monitor inbox", () => {
|
||||
|
||||
it("still forwards group messages (with sender info) even when allowFrom is restrictive", async () => {
|
||||
mockLoadConfig.mockReturnValue({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+111"], // does not include +777
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
@@ -465,8 +469,10 @@ describe("web monitor inbox", () => {
|
||||
// Test for auto-recovery fix: early allowFrom filtering prevents Bad MAC errors
|
||||
// from unauthorized senders corrupting sessions
|
||||
mockLoadConfig.mockReturnValue({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+111"], // Only allow +111
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
@@ -503,8 +509,10 @@ describe("web monitor inbox", () => {
|
||||
|
||||
// Reset mock for other tests
|
||||
mockLoadConfig.mockReturnValue({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
@@ -516,9 +524,11 @@ describe("web monitor inbox", () => {
|
||||
|
||||
it("skips read receipts in self-chat mode", async () => {
|
||||
mockLoadConfig.mockReturnValue({
|
||||
inbound: {
|
||||
routing: {
|
||||
// Self-chat heuristic: allowFrom includes selfE164 (+123).
|
||||
allowFrom: ["+123"],
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
@@ -551,8 +561,10 @@ describe("web monitor inbox", () => {
|
||||
|
||||
// Reset mock for other tests
|
||||
mockLoadConfig.mockReturnValue({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
@@ -564,8 +576,10 @@ describe("web monitor inbox", () => {
|
||||
|
||||
it("lets group messages through even when sender not in allowFrom", async () => {
|
||||
mockLoadConfig.mockReturnValue({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+1234"],
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
@@ -604,8 +618,10 @@ describe("web monitor inbox", () => {
|
||||
|
||||
it("allows messages from senders in allowFrom list", async () => {
|
||||
mockLoadConfig.mockReturnValue({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+111", "+999"], // Allow +999
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
@@ -637,8 +653,10 @@ describe("web monitor inbox", () => {
|
||||
|
||||
// Reset mock for other tests
|
||||
mockLoadConfig.mockReturnValue({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
@@ -652,8 +670,10 @@ describe("web monitor inbox", () => {
|
||||
// Same-phone mode: when from === selfJid, should always be allowed
|
||||
// This allows users to message themselves even with restrictive allowFrom
|
||||
mockLoadConfig.mockReturnValue({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["+111"], // Only allow +111, but self is +123
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
@@ -686,8 +706,10 @@ describe("web monitor inbox", () => {
|
||||
|
||||
// Reset mock for other tests
|
||||
mockLoadConfig.mockReturnValue({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
@@ -751,8 +773,10 @@ it("defaults to self-only when no config is present", async () => {
|
||||
|
||||
// Reset mock for other tests
|
||||
mockLoadConfig.mockReturnValue({
|
||||
inbound: {
|
||||
routing: {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
|
||||
@@ -6,9 +6,11 @@ import { createMockBaileys } from "../../test/mocks/baileys.js";
|
||||
// Use globalThis to store the mock config so it survives vi.mock hoisting
|
||||
const CONFIG_KEY = Symbol.for("clawdis:testConfigMock");
|
||||
const DEFAULT_CONFIG = {
|
||||
inbound: {
|
||||
routing: {
|
||||
// Tests can override; default remains open to avoid surprising fixtures
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
messages: {
|
||||
messagePrefix: undefined,
|
||||
responsePrefix: undefined,
|
||||
timestampPrefix: false,
|
||||
|
||||
Reference in New Issue
Block a user