Skip to content

Commit e15f156

Browse files
committed
fix(test): reduce node hotspot startup cost
Scope: conversation-binding/targets startup trimming + schema help isolation guardrail
1 parent ee07780 commit e15f156

5 files changed

Lines changed: 395 additions & 704 deletions

File tree

src/infra/outbound/targets.shared-test.ts

Lines changed: 3 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,149 +1,15 @@
11
import { afterEach, beforeEach, describe, expect, it } from "vitest";
2-
import type { ChannelOutboundAdapter } from "../../channels/plugins/types.js";
3-
import type { OpenClawConfig } from "../../config/config.js";
42
import { setActivePluginRegistry } from "../../plugins/runtime.js";
5-
import { createOutboundTestPlugin, createTestRegistry } from "../../test-utils/channel-plugins.js";
6-
import { isWhatsAppGroupJid, normalizeWhatsAppTarget } from "../../whatsapp/normalize.js";
73
import { resolveOutboundTarget } from "./targets.js";
8-
9-
type TelegramTargetParts = {
10-
chatId: string;
11-
messageThreadId?: number;
12-
chatType: "direct" | "group" | "unknown";
13-
};
14-
15-
function parseTelegramTestTarget(raw: string): TelegramTargetParts {
16-
const trimmed = raw
17-
.trim()
18-
.replace(/^(telegram|tg):/i, "")
19-
.trim();
20-
const topicMatch = /^(.+?):topic:(\d+)$/u.exec(trimmed);
21-
if (topicMatch) {
22-
const chatId = topicMatch[1];
23-
return {
24-
chatId,
25-
messageThreadId: Number.parseInt(topicMatch[2], 10),
26-
chatType: chatId.startsWith("-") ? "group" : "direct",
27-
};
28-
}
29-
30-
const threadMatch = /^(.+):(\d+)$/u.exec(trimmed);
31-
if (threadMatch) {
32-
const chatId = threadMatch[1];
33-
return {
34-
chatId,
35-
messageThreadId: Number.parseInt(threadMatch[2], 10),
36-
chatType: chatId.startsWith("-") ? "group" : "direct",
37-
};
38-
}
39-
40-
return {
41-
chatId: trimmed,
42-
chatType: trimmed.startsWith("-") ? "group" : "direct",
43-
};
44-
}
45-
46-
const telegramMessaging = {
47-
parseExplicitTarget: ({ raw }: { raw: string }) => parseTelegramTestMessagingTarget(raw),
48-
};
49-
50-
export function inferTelegramTestChatType(to: string): "direct" | "group" | undefined {
51-
const chatType = parseTelegramTestTarget(to).chatType;
52-
return chatType === "unknown" ? undefined : chatType;
53-
}
54-
55-
export function parseTelegramTestMessagingTarget(raw: string): {
56-
to: string;
57-
threadId?: number;
58-
chatType?: "direct" | "group";
59-
} {
60-
const target = parseTelegramTestTarget(raw);
61-
return {
62-
to: target.chatId,
63-
threadId: target.messageThreadId,
64-
chatType: target.chatType === "unknown" ? undefined : target.chatType,
65-
};
66-
}
67-
68-
const whatsappMessaging = {
69-
inferTargetChatType: ({ to }: { to: string }) => {
70-
const normalized = normalizeWhatsAppTarget(to);
71-
if (!normalized) {
72-
return undefined;
73-
}
74-
return isWhatsAppGroupJid(normalized) ? ("group" as const) : ("direct" as const);
75-
},
76-
targetResolver: {
77-
hint: "<E.164|group JID>",
78-
},
79-
};
80-
81-
export const telegramOutboundStub: ChannelOutboundAdapter = {
82-
deliveryMode: "direct",
83-
};
84-
85-
export const whatsappOutboundStub: ChannelOutboundAdapter = {
86-
deliveryMode: "gateway",
87-
resolveTarget: ({ to }) => {
88-
const normalized = typeof to === "string" ? normalizeWhatsAppTarget(to) : undefined;
89-
if (normalized) {
90-
return { ok: true as const, to: normalized };
91-
}
92-
return {
93-
ok: false as const,
94-
error: new Error("WhatsApp target required"),
95-
};
96-
},
97-
};
4+
import { createTargetsTestRegistry } from "./targets.test-helpers.js";
985

996
export function installResolveOutboundTargetPluginRegistryHooks(): void {
1007
beforeEach(() => {
101-
setActivePluginRegistry(
102-
createTestRegistry([
103-
{
104-
pluginId: "whatsapp",
105-
plugin: {
106-
...createOutboundTestPlugin({
107-
id: "whatsapp",
108-
label: "WhatsApp",
109-
outbound: whatsappOutboundStub,
110-
messaging: whatsappMessaging,
111-
}),
112-
config: {
113-
listAccountIds: () => [],
114-
resolveDefaultTo: ({ cfg }: { cfg: OpenClawConfig }) =>
115-
typeof cfg.channels?.whatsapp?.defaultTo === "string"
116-
? cfg.channels.whatsapp.defaultTo
117-
: undefined,
118-
},
119-
},
120-
source: "test",
121-
},
122-
{
123-
pluginId: "telegram",
124-
plugin: {
125-
...createOutboundTestPlugin({
126-
id: "telegram",
127-
label: "Telegram",
128-
outbound: telegramOutboundStub,
129-
messaging: telegramMessaging,
130-
}),
131-
config: {
132-
listAccountIds: () => [],
133-
resolveDefaultTo: ({ cfg }: { cfg: OpenClawConfig }) =>
134-
typeof cfg.channels?.telegram?.defaultTo === "string"
135-
? cfg.channels.telegram.defaultTo
136-
: undefined,
137-
},
138-
},
139-
source: "test",
140-
},
141-
]),
142-
);
8+
setActivePluginRegistry(createTargetsTestRegistry());
1439
});
14410

14511
afterEach(() => {
146-
setActivePluginRegistry(createTestRegistry());
12+
setActivePluginRegistry(createTargetsTestRegistry([]));
14713
});
14814
}
14915

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
import type {
2+
ChannelMessagingAdapter,
3+
ChannelOutboundAdapter,
4+
ChannelPlugin,
5+
} from "../../channels/plugins/types.js";
6+
import type { OpenClawConfig } from "../../config/config.js";
7+
import { createTestRegistry } from "../../test-utils/channel-plugins.js";
8+
9+
function parseTelegramTargetForTest(raw: string): {
10+
chatId: string;
11+
messageThreadId?: number;
12+
chatType: "direct" | "group" | "unknown";
13+
} {
14+
const trimmed = raw.trim();
15+
const withoutPrefix = trimmed.replace(/^telegram:/i, "").trim();
16+
const topicMatch = withoutPrefix.match(/^(.*):topic:(\d+)$/i);
17+
const chatId = topicMatch?.[1]?.trim() || withoutPrefix;
18+
const messageThreadId = topicMatch?.[2] ? Number.parseInt(topicMatch[2], 10) : undefined;
19+
const numericId = chatId.startsWith("-") ? chatId.slice(1) : chatId;
20+
const chatType =
21+
/^\d+$/.test(numericId) && !chatId.startsWith("-100")
22+
? "direct"
23+
: chatId.startsWith("-")
24+
? "group"
25+
: "unknown";
26+
return { chatId, messageThreadId, chatType };
27+
}
28+
29+
function normalizeWhatsAppTargetForTest(raw: string): string | null {
30+
const trimmed = raw.trim().replace(/^whatsapp:/i, "").trim();
31+
if (!trimmed) {
32+
return null;
33+
}
34+
const lowered = trimmed.toLowerCase();
35+
if (/@g\.us$/u.test(lowered)) {
36+
const normalized = lowered.replace(/\s+/gu, "");
37+
return /^\d+@g\.us$/u.test(normalized) ? normalized : null;
38+
}
39+
const digits = trimmed.replace(/\D/gu, "");
40+
const normalized = digits ? `+${digits}` : "";
41+
return /^\+\d{7,15}$/u.test(normalized) ? normalized : null;
42+
}
43+
44+
function createWhatsAppResolveTarget(
45+
label = "WhatsApp",
46+
): ChannelOutboundAdapter["resolveTarget"] {
47+
return ({ to }) => {
48+
const normalized = to ? normalizeWhatsAppTargetForTest(to) : null;
49+
if (!normalized) {
50+
return { ok: false, error: new Error(`${label} target is required`) };
51+
}
52+
return { ok: true, to: normalized };
53+
};
54+
}
55+
56+
function createTelegramResolveTarget(label = "Telegram"): ChannelOutboundAdapter["resolveTarget"] {
57+
return ({ to }) => {
58+
const trimmed = to?.trim();
59+
if (!trimmed) {
60+
return { ok: false, error: new Error(`${label} target is required`) };
61+
}
62+
return { ok: true, to: parseTelegramTargetForTest(trimmed).chatId };
63+
};
64+
}
65+
66+
export const telegramMessagingForTest: ChannelMessagingAdapter = {
67+
parseExplicitTarget: ({ raw }) => {
68+
const target = parseTelegramTargetForTest(raw);
69+
return {
70+
to: target.chatId,
71+
threadId: target.messageThreadId,
72+
chatType: target.chatType === "unknown" ? undefined : target.chatType,
73+
};
74+
},
75+
inferTargetChatType: ({ to }) => {
76+
const target = parseTelegramTargetForTest(to);
77+
return target.chatType === "unknown" ? undefined : target.chatType;
78+
},
79+
};
80+
81+
export const whatsappMessagingForTest: ChannelMessagingAdapter = {
82+
inferTargetChatType: ({ to }) => {
83+
const normalized = normalizeWhatsAppTargetForTest(to);
84+
if (!normalized) {
85+
return undefined;
86+
}
87+
return normalized.endsWith("@g.us") ? "group" : "direct";
88+
},
89+
targetResolver: {
90+
hint: "<E.164|group JID>",
91+
},
92+
};
93+
94+
export function createTestChannelPlugin(params: {
95+
id: ChannelPlugin["id"];
96+
label?: string;
97+
outbound?: ChannelOutboundAdapter;
98+
messaging?: ChannelMessagingAdapter;
99+
resolveDefaultTo?: (params: { cfg: OpenClawConfig }) => string | undefined;
100+
}): ChannelPlugin {
101+
return {
102+
id: params.id,
103+
meta: {
104+
id: params.id,
105+
label: params.label ?? String(params.id),
106+
selectionLabel: params.label ?? String(params.id),
107+
docsPath: `/channels/${params.id}`,
108+
blurb: "test stub.",
109+
},
110+
capabilities: { chatTypes: ["direct", "group"] },
111+
config: {
112+
listAccountIds: () => [],
113+
resolveAccount: () => ({}),
114+
...(params.resolveDefaultTo
115+
? {
116+
resolveDefaultTo: params.resolveDefaultTo,
117+
}
118+
: {}),
119+
},
120+
...(params.outbound ? { outbound: params.outbound } : {}),
121+
...(params.messaging ? { messaging: params.messaging } : {}),
122+
};
123+
}
124+
125+
export function createTelegramTestPlugin(): ChannelPlugin {
126+
return createTestChannelPlugin({
127+
id: "telegram",
128+
label: "Telegram",
129+
outbound: {
130+
deliveryMode: "direct",
131+
sendText: async () => ({ channel: "telegram", messageId: "telegram-msg" }),
132+
resolveTarget: createTelegramResolveTarget(),
133+
},
134+
messaging: telegramMessagingForTest,
135+
resolveDefaultTo: ({ cfg }) =>
136+
typeof cfg.channels?.telegram?.defaultTo === "string" ? cfg.channels.telegram.defaultTo : undefined,
137+
});
138+
}
139+
140+
export function createWhatsAppTestPlugin(): ChannelPlugin {
141+
return createTestChannelPlugin({
142+
id: "whatsapp",
143+
label: "WhatsApp",
144+
outbound: {
145+
deliveryMode: "direct",
146+
sendText: async () => ({ channel: "whatsapp", messageId: "whatsapp-msg" }),
147+
resolveTarget: createWhatsAppResolveTarget(),
148+
},
149+
messaging: whatsappMessagingForTest,
150+
resolveDefaultTo: ({ cfg }) =>
151+
typeof cfg.channels?.whatsapp?.defaultTo === "string" ? cfg.channels.whatsapp.defaultTo : undefined,
152+
});
153+
}
154+
155+
export function createNoopOutboundChannelPlugin(
156+
id: "discord" | "imessage" | "slack",
157+
): ChannelPlugin {
158+
return createTestChannelPlugin({
159+
id,
160+
outbound: {
161+
deliveryMode: "direct",
162+
sendText: async () => ({ channel: id, messageId: `${id}-msg` }),
163+
},
164+
});
165+
}
166+
167+
export function createTargetsTestRegistry(
168+
plugins: ChannelPlugin[] = [createWhatsAppTestPlugin(), createTelegramTestPlugin()],
169+
) {
170+
return createTestRegistry(
171+
plugins.map((plugin) => ({
172+
pluginId: plugin.id,
173+
plugin,
174+
source: "test",
175+
})),
176+
);
177+
}

0 commit comments

Comments
 (0)