@sjawhar/whatsapp-mcp 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/db.d.ts +28 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +153 -30
- package/dist/db.js.map +1 -1
- package/dist/http-server.d.ts +8 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +198 -0
- package/dist/http-server.js.map +1 -0
- package/dist/import-contacts.d.ts +6 -3
- package/dist/import-contacts.d.ts.map +1 -1
- package/dist/import-contacts.js +28 -14
- package/dist/import-contacts.js.map +1 -1
- package/dist/index.js +192 -26
- package/dist/index.js.map +1 -1
- package/dist/resources.d.ts +16 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +84 -0
- package/dist/resources.js.map +1 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +38 -15
- package/dist/tools.js.map +1 -1
- package/dist/whatsapp.d.ts +13 -1
- package/dist/whatsapp.d.ts.map +1 -1
- package/dist/whatsapp.js +167 -31
- package/dist/whatsapp.js.map +1 -1
- package/package.json +5 -1
- package/dist/__tests__/connection.test.d.ts +0 -2
- package/dist/__tests__/connection.test.d.ts.map +0 -1
- package/dist/__tests__/connection.test.js +0 -105
- package/dist/__tests__/connection.test.js.map +0 -1
- package/dist/__tests__/disconnect.test.d.ts +0 -2
- package/dist/__tests__/disconnect.test.d.ts.map +0 -1
- package/dist/__tests__/disconnect.test.js +0 -166
- package/dist/__tests__/disconnect.test.js.map +0 -1
- package/dist/__tests__/download-media.test.d.ts +0 -2
- package/dist/__tests__/download-media.test.d.ts.map +0 -1
- package/dist/__tests__/download-media.test.js +0 -110
- package/dist/__tests__/download-media.test.js.map +0 -1
- package/dist/__tests__/failures/connection-failures.test.d.ts +0 -2
- package/dist/__tests__/failures/connection-failures.test.d.ts.map +0 -1
- package/dist/__tests__/failures/connection-failures.test.js +0 -146
- package/dist/__tests__/failures/connection-failures.test.js.map +0 -1
- package/dist/__tests__/failures/edge-cases.test.d.ts +0 -2
- package/dist/__tests__/failures/edge-cases.test.d.ts.map +0 -1
- package/dist/__tests__/failures/edge-cases.test.js +0 -121
- package/dist/__tests__/failures/edge-cases.test.js.map +0 -1
- package/dist/__tests__/failures/resource-failures.test.d.ts +0 -2
- package/dist/__tests__/failures/resource-failures.test.d.ts.map +0 -1
- package/dist/__tests__/failures/resource-failures.test.js +0 -136
- package/dist/__tests__/failures/resource-failures.test.js.map +0 -1
- package/dist/__tests__/failures/security-failures.test.d.ts +0 -2
- package/dist/__tests__/failures/security-failures.test.d.ts.map +0 -1
- package/dist/__tests__/failures/security-failures.test.js +0 -0
- package/dist/__tests__/failures/security-failures.test.js.map +0 -1
- package/dist/__tests__/helpers/fake-baileys.d.ts +0 -52
- package/dist/__tests__/helpers/fake-baileys.d.ts.map +0 -1
- package/dist/__tests__/helpers/fake-baileys.js +0 -60
- package/dist/__tests__/helpers/fake-baileys.js.map +0 -1
- package/dist/__tests__/helpers/mcp-test-client.d.ts +0 -9
- package/dist/__tests__/helpers/mcp-test-client.d.ts.map +0 -1
- package/dist/__tests__/helpers/mcp-test-client.js +0 -40
- package/dist/__tests__/helpers/mcp-test-client.js.map +0 -1
- package/dist/__tests__/helpers/test-db.d.ts +0 -4
- package/dist/__tests__/helpers/test-db.d.ts.map +0 -1
- package/dist/__tests__/helpers/test-db.js +0 -32
- package/dist/__tests__/helpers/test-db.js.map +0 -1
- package/dist/__tests__/integration/chat-navigation.test.d.ts +0 -2
- package/dist/__tests__/integration/chat-navigation.test.d.ts.map +0 -1
- package/dist/__tests__/integration/chat-navigation.test.js +0 -171
- package/dist/__tests__/integration/chat-navigation.test.js.map +0 -1
- package/dist/__tests__/integration/contacts-flow.test.d.ts +0 -2
- package/dist/__tests__/integration/contacts-flow.test.d.ts.map +0 -1
- package/dist/__tests__/integration/contacts-flow.test.js +0 -144
- package/dist/__tests__/integration/contacts-flow.test.js.map +0 -1
- package/dist/__tests__/integration/media-flow.test.d.ts +0 -2
- package/dist/__tests__/integration/media-flow.test.d.ts.map +0 -1
- package/dist/__tests__/integration/media-flow.test.js +0 -225
- package/dist/__tests__/integration/media-flow.test.js.map +0 -1
- package/dist/__tests__/integration/search-flow.test.d.ts +0 -2
- package/dist/__tests__/integration/search-flow.test.d.ts.map +0 -1
- package/dist/__tests__/integration/search-flow.test.js +0 -44
- package/dist/__tests__/integration/search-flow.test.js.map +0 -1
- package/dist/__tests__/integration/send-message.test.d.ts +0 -2
- package/dist/__tests__/integration/send-message.test.d.ts.map +0 -1
- package/dist/__tests__/integration/send-message.test.js +0 -160
- package/dist/__tests__/integration/send-message.test.js.map +0 -1
- package/dist/__tests__/lock-file.test.d.ts +0 -2
- package/dist/__tests__/lock-file.test.d.ts.map +0 -1
- package/dist/__tests__/lock-file.test.js +0 -63
- package/dist/__tests__/lock-file.test.js.map +0 -1
- package/dist/__tests__/medium-fixes.test.d.ts +0 -2
- package/dist/__tests__/medium-fixes.test.d.ts.map +0 -1
- package/dist/__tests__/medium-fixes.test.js +0 -141
- package/dist/__tests__/medium-fixes.test.js.map +0 -1
- package/dist/__tests__/rate-limit.test.d.ts +0 -2
- package/dist/__tests__/rate-limit.test.d.ts.map +0 -1
- package/dist/__tests__/rate-limit.test.js +0 -193
- package/dist/__tests__/rate-limit.test.js.map +0 -1
- package/dist/__tests__/send-file.test.d.ts +0 -2
- package/dist/__tests__/send-file.test.d.ts.map +0 -1
- package/dist/__tests__/send-file.test.js +0 -237
- package/dist/__tests__/send-file.test.js.map +0 -1
- package/dist/__tests__/smoke.test.d.ts +0 -2
- package/dist/__tests__/smoke.test.d.ts.map +0 -1
- package/dist/__tests__/smoke.test.js +0 -28
- package/dist/__tests__/smoke.test.js.map +0 -1
- package/dist/__tests__/transcribe.test.d.ts +0 -2
- package/dist/__tests__/transcribe.test.d.ts.map +0 -1
- package/dist/__tests__/transcribe.test.js +0 -71
- package/dist/__tests__/transcribe.test.js.map +0 -1
- package/dist/__tests__/zombie.test.d.ts +0 -2
- package/dist/__tests__/zombie.test.d.ts.map +0 -1
- package/dist/__tests__/zombie.test.js +0 -145
- package/dist/__tests__/zombie.test.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"search-flow.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/search-flow.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"send-message.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/send-message.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3
|
-
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
4
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
-
import { createFakeBaileysSocket } from "../helpers/fake-baileys.js";
|
|
6
|
-
import { closeTestDb, seedTestDb, setupTestDb } from "../helpers/test-db.js";
|
|
7
|
-
const mockState = vi.hoisted(() => ({
|
|
8
|
-
sockets: [],
|
|
9
|
-
}));
|
|
10
|
-
vi.mock("@whiskeysockets/baileys", () => ({
|
|
11
|
-
default: vi.fn(() => {
|
|
12
|
-
const socket = createFakeBaileysSocket();
|
|
13
|
-
mockState.sockets.push(socket);
|
|
14
|
-
return socket;
|
|
15
|
-
}),
|
|
16
|
-
DisconnectReason: {
|
|
17
|
-
loggedOut: 401,
|
|
18
|
-
connectionReplaced: 440,
|
|
19
|
-
},
|
|
20
|
-
fetchLatestBaileysVersion: vi.fn(async () => ({ version: [2, 3000, 0] })),
|
|
21
|
-
downloadMediaMessage: vi.fn(),
|
|
22
|
-
getContentType: vi.fn(),
|
|
23
|
-
initAuthCreds: vi.fn(() => ({})),
|
|
24
|
-
BufferJSON: {
|
|
25
|
-
replacer: (_key, value) => value,
|
|
26
|
-
reviver: (_key, value) => value,
|
|
27
|
-
},
|
|
28
|
-
proto: {
|
|
29
|
-
Message: {
|
|
30
|
-
AppStateSyncKeyData: {
|
|
31
|
-
fromObject: (value) => value,
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
}));
|
|
36
|
-
function parseToolJson(result) {
|
|
37
|
-
const text = result.content?.find((entry) => entry.type === "text")?.text || "";
|
|
38
|
-
try {
|
|
39
|
-
return JSON.parse(text);
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
return text;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
describe("integration: send_message", () => {
|
|
46
|
-
const originalMinInterval = process.env.MIN_SEND_INTERVAL_MS;
|
|
47
|
-
const originalJitter = process.env.SEND_JITTER_MS;
|
|
48
|
-
let server;
|
|
49
|
-
let client;
|
|
50
|
-
let closeWhatsApp;
|
|
51
|
-
beforeAll(async () => {
|
|
52
|
-
process.env.MIN_SEND_INTERVAL_MS = "150";
|
|
53
|
-
process.env.SEND_JITTER_MS = "0";
|
|
54
|
-
await setupTestDb();
|
|
55
|
-
seedTestDb();
|
|
56
|
-
const whatsapp = await import("../../whatsapp.js");
|
|
57
|
-
closeWhatsApp = whatsapp.closeWhatsApp;
|
|
58
|
-
await whatsapp.initWhatsApp();
|
|
59
|
-
const socket = mockState.sockets.at(-1);
|
|
60
|
-
if (!socket)
|
|
61
|
-
throw new Error("Expected fake Baileys socket");
|
|
62
|
-
socket.emitConnectionOpen();
|
|
63
|
-
server = new McpServer({ name: "whatsapp-test", version: "1.0.0" });
|
|
64
|
-
const { registerTools } = await import("../../tools.js");
|
|
65
|
-
registerTools(server);
|
|
66
|
-
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
67
|
-
client = new Client({ name: "whatsapp-test-client", version: "1.0.0" });
|
|
68
|
-
await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
|
|
69
|
-
});
|
|
70
|
-
afterAll(async () => {
|
|
71
|
-
await Promise.all([client?.close(), server?.close()]);
|
|
72
|
-
await closeWhatsApp?.();
|
|
73
|
-
closeTestDb();
|
|
74
|
-
if (originalMinInterval === undefined) {
|
|
75
|
-
delete process.env.MIN_SEND_INTERVAL_MS;
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
process.env.MIN_SEND_INTERVAL_MS = originalMinInterval;
|
|
79
|
-
}
|
|
80
|
-
if (originalJitter === undefined) {
|
|
81
|
-
delete process.env.SEND_JITTER_MS;
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
process.env.SEND_JITTER_MS = originalJitter;
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
it("returns preview when confirmed=false", async () => {
|
|
88
|
-
const socket = mockState.sockets.at(-1);
|
|
89
|
-
if (!socket)
|
|
90
|
-
throw new Error("Expected fake Baileys socket");
|
|
91
|
-
const before = socket.sentMessages.length;
|
|
92
|
-
const result = (await client.callTool({
|
|
93
|
-
name: "send_message",
|
|
94
|
-
arguments: {
|
|
95
|
-
jid: "15550001111@s.whatsapp.net",
|
|
96
|
-
text: "Preview only",
|
|
97
|
-
confirmed: false,
|
|
98
|
-
},
|
|
99
|
-
}));
|
|
100
|
-
const payload = parseToolJson(result);
|
|
101
|
-
expect(result.isError).toBeFalsy();
|
|
102
|
-
expect(payload).toMatchObject({
|
|
103
|
-
status: "confirmation_required",
|
|
104
|
-
jid: "15550001111@s.whatsapp.net",
|
|
105
|
-
phone: "15550001111",
|
|
106
|
-
message: "Preview only",
|
|
107
|
-
});
|
|
108
|
-
expect(socket.sentMessages.length).toBe(before);
|
|
109
|
-
});
|
|
110
|
-
it("sends when confirmed=true", async () => {
|
|
111
|
-
const socket = mockState.sockets.at(-1);
|
|
112
|
-
if (!socket)
|
|
113
|
-
throw new Error("Expected fake Baileys socket");
|
|
114
|
-
const result = (await client.callTool({
|
|
115
|
-
name: "send_message",
|
|
116
|
-
arguments: {
|
|
117
|
-
jid: "15550001111@s.whatsapp.net",
|
|
118
|
-
text: "Actually send this",
|
|
119
|
-
confirmed: true,
|
|
120
|
-
},
|
|
121
|
-
}));
|
|
122
|
-
const payload = parseToolJson(result);
|
|
123
|
-
expect(result.isError).toBeFalsy();
|
|
124
|
-
expect(payload).toMatchObject({
|
|
125
|
-
success: true,
|
|
126
|
-
to: "15550001111@s.whatsapp.net",
|
|
127
|
-
messageId: expect.any(String),
|
|
128
|
-
});
|
|
129
|
-
expect(socket.sentMessages.at(-1)).toMatchObject({
|
|
130
|
-
jid: "15550001111@s.whatsapp.net",
|
|
131
|
-
content: { text: "Actually send this" },
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
it("applies rate limiting delay for second rapid send", async () => {
|
|
135
|
-
const firstResult = (await client.callTool({
|
|
136
|
-
name: "send_message",
|
|
137
|
-
arguments: {
|
|
138
|
-
jid: "15550001111@s.whatsapp.net",
|
|
139
|
-
text: "first rapid",
|
|
140
|
-
confirmed: true,
|
|
141
|
-
},
|
|
142
|
-
}));
|
|
143
|
-
expect(firstResult.isError).toBeFalsy();
|
|
144
|
-
const started = Date.now();
|
|
145
|
-
const secondResult = (await client.callTool({
|
|
146
|
-
name: "send_message",
|
|
147
|
-
arguments: {
|
|
148
|
-
jid: "15550001111@s.whatsapp.net",
|
|
149
|
-
text: "second rapid",
|
|
150
|
-
confirmed: true,
|
|
151
|
-
},
|
|
152
|
-
}));
|
|
153
|
-
const elapsed = Date.now() - started;
|
|
154
|
-
const payload = parseToolJson(secondResult);
|
|
155
|
-
expect(secondResult.isError).toBeFalsy();
|
|
156
|
-
expect(payload.success).toBe(true);
|
|
157
|
-
expect(elapsed).toBeGreaterThanOrEqual(120);
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
//# sourceMappingURL=send-message.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"send-message.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/send-message.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAA0B,MAAM,4BAA4B,CAAC;AAC7F,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAE7E,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAClC,OAAO,EAAE,EAAyB;CACnC,CAAC,CAAC,CAAC;AAEJ,EAAE,CAAC,IAAI,CAAC,yBAAyB,EAAE,GAAG,EAAE,CAAC,CAAC;IACxC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE;QAClB,MAAM,MAAM,GAAG,uBAAuB,EAAE,CAAC;QACzC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IACF,gBAAgB,EAAE;QAChB,SAAS,EAAE,GAAG;QACd,kBAAkB,EAAE,GAAG;KACxB;IACD,yBAAyB,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IACzE,oBAAoB,EAAE,EAAE,CAAC,EAAE,EAAE;IAC7B,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE;IACvB,aAAa,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAChC,UAAU,EAAE;QACV,QAAQ,EAAE,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE,CAAC,KAAK;QACjD,OAAO,EAAE,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE,CAAC,KAAK;KACjD;IACD,KAAK,EAAE;QACL,OAAO,EAAE;YACP,mBAAmB,EAAE;gBACnB,UAAU,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,KAAK;aACtC;SACF;KACF;CACF,CAAC,CAAC,CAAC;AAOJ,SAAS,aAAa,CAAC,MAAqB;IAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;IAChF,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,MAAM,mBAAmB,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IAC7D,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAElD,IAAI,MAAiB,CAAC;IACtB,IAAI,MAAc,CAAC;IACnB,IAAI,aAAkC,CAAC;IAEvC,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,KAAK,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,GAAG,CAAC;QAEjC,MAAM,WAAW,EAAE,CAAC;QACpB,UAAU,EAAE,CAAC;QAEb,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;QACnD,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC;QACvC,MAAM,QAAQ,CAAC,YAAY,EAAE,CAAC;QAE9B,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAC7D,MAAM,CAAC,kBAAkB,EAAE,CAAC;QAE5B,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACpE,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACzD,aAAa,CAAC,MAAM,CAAC,CAAC;QAEtB,MAAM,CAAC,eAAe,EAAE,eAAe,CAAC,GAAG,iBAAiB,CAAC,gBAAgB,EAAE,CAAC;QAChF,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACxE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,KAAK,IAAI,EAAE;QAClB,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACtD,MAAM,aAAa,EAAE,EAAE,CAAC;QACxB,WAAW,EAAE,CAAC;QAEd,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;YACtC,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,mBAAmB,CAAC;QACzD,CAAC;QAED,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,cAAc,CAAC;QAC9C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAE7D,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC;QAC1C,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC;YACpC,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE;gBACT,GAAG,EAAE,4BAA4B;gBACjC,IAAI,EAAE,cAAc;gBACpB,SAAS,EAAE,KAAK;aACjB;SACF,CAAC,CAAkB,CAAC;QAErB,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAQ,CAAC;QAE7C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC;QACnC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC;YAC5B,MAAM,EAAE,uBAAuB;YAC/B,GAAG,EAAE,4BAA4B;YACjC,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,cAAc;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAE7D,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC;YACpC,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE;gBACT,GAAG,EAAE,4BAA4B;gBACjC,IAAI,EAAE,oBAAoB;gBAC1B,SAAS,EAAE,IAAI;aAChB;SACF,CAAC,CAAkB,CAAC;QAErB,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAQ,CAAC;QAE7C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC;QACnC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC;YAC5B,OAAO,EAAE,IAAI;YACb,EAAE,EAAE,4BAA4B;YAChC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;SAC9B,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;YAC/C,GAAG,EAAE,4BAA4B;YACjC,OAAO,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE;SACxC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,WAAW,GAAG,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC;YACzC,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE;gBACT,GAAG,EAAE,4BAA4B;gBACjC,IAAI,EAAE,aAAa;gBACnB,SAAS,EAAE,IAAI;aAChB;SACF,CAAC,CAAkB,CAAC;QACrB,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC;QAExC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,YAAY,GAAG,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC;YAC1C,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE;gBACT,GAAG,EAAE,4BAA4B;gBACjC,IAAI,EAAE,cAAc;gBACpB,SAAS,EAAE,IAAI;aAChB;SACF,CAAC,CAAkB,CAAC;QACrB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;QAErC,MAAM,OAAO,GAAG,aAAa,CAAC,YAAY,CAAQ,CAAC;QACnD,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC;QACzC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,CAAC,OAAO,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lock-file.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/lock-file.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import os from "node:os";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
5
|
-
import { acquireWhatsAppLock, releaseWhatsAppLock } from "../lock.js";
|
|
6
|
-
describe("lock file", () => {
|
|
7
|
-
let tmpDir;
|
|
8
|
-
let lockFile;
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "wa-lock-test-"));
|
|
11
|
-
lockFile = path.join(tmpDir, ".whatsapp.lock");
|
|
12
|
-
});
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
// Clean up: release if owned, then remove temp dir
|
|
15
|
-
try {
|
|
16
|
-
releaseWhatsAppLock(lockFile);
|
|
17
|
-
}
|
|
18
|
-
catch { }
|
|
19
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
20
|
-
});
|
|
21
|
-
it("acquires lock on first call and writes current PID", () => {
|
|
22
|
-
expect(acquireWhatsAppLock(lockFile)).toBe(true);
|
|
23
|
-
expect(fs.existsSync(lockFile)).toBe(true);
|
|
24
|
-
const pid = parseInt(fs.readFileSync(lockFile, "utf-8").trim(), 10);
|
|
25
|
-
expect(pid).toBe(process.pid);
|
|
26
|
-
});
|
|
27
|
-
it("two rapid calls — exactly one succeeds", () => {
|
|
28
|
-
const first = acquireWhatsAppLock(lockFile);
|
|
29
|
-
const second = acquireWhatsAppLock(lockFile);
|
|
30
|
-
expect(first).toBe(true);
|
|
31
|
-
expect(second).toBe(false);
|
|
32
|
-
});
|
|
33
|
-
it("stale lock with dead PID — new process takes over", () => {
|
|
34
|
-
fs.mkdirSync(path.dirname(lockFile), { recursive: true });
|
|
35
|
-
fs.writeFileSync(lockFile, "99999999");
|
|
36
|
-
const result = acquireWhatsAppLock(lockFile);
|
|
37
|
-
expect(result).toBe(true);
|
|
38
|
-
const pid = parseInt(fs.readFileSync(lockFile, "utf-8").trim(), 10);
|
|
39
|
-
expect(pid).toBe(process.pid);
|
|
40
|
-
});
|
|
41
|
-
it("release removes the lock file when owned by current PID", () => {
|
|
42
|
-
acquireWhatsAppLock(lockFile);
|
|
43
|
-
expect(fs.existsSync(lockFile)).toBe(true);
|
|
44
|
-
releaseWhatsAppLock(lockFile);
|
|
45
|
-
expect(fs.existsSync(lockFile)).toBe(false);
|
|
46
|
-
});
|
|
47
|
-
it("release is safe when no lock file exists", () => {
|
|
48
|
-
expect(() => releaseWhatsAppLock(lockFile)).not.toThrow();
|
|
49
|
-
});
|
|
50
|
-
it("release does not remove lock owned by different PID", () => {
|
|
51
|
-
fs.mkdirSync(path.dirname(lockFile), { recursive: true });
|
|
52
|
-
fs.writeFileSync(lockFile, "99999999");
|
|
53
|
-
releaseWhatsAppLock(lockFile);
|
|
54
|
-
// File should still exist — not our PID
|
|
55
|
-
expect(fs.existsSync(lockFile)).toBe(true);
|
|
56
|
-
});
|
|
57
|
-
it("creates parent directories if they don't exist", () => {
|
|
58
|
-
const nested = path.join(tmpDir, "deep", "nested", ".whatsapp.lock");
|
|
59
|
-
expect(acquireWhatsAppLock(nested)).toBe(true);
|
|
60
|
-
expect(fs.existsSync(nested)).toBe(true);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
//# sourceMappingURL=lock-file.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lock-file.test.js","sourceRoot":"","sources":["../../src/__tests__/lock-file.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"medium-fixes.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/medium-fixes.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
2
|
-
import { closeTestDb, seedTestDb, setupTestDb } from "./helpers/test-db.js";
|
|
3
|
-
import { createMcpTestClient } from "./helpers/mcp-test-client.js";
|
|
4
|
-
// ─── Fix 1: JID device suffix stripping ─────────────────────────────
|
|
5
|
-
describe("toJid — device suffix stripping", () => {
|
|
6
|
-
let toJid;
|
|
7
|
-
beforeAll(async () => {
|
|
8
|
-
const utils = await import("../utils.js");
|
|
9
|
-
toJid = utils.toJid;
|
|
10
|
-
});
|
|
11
|
-
it("strips device suffix from phone JID", () => {
|
|
12
|
-
expect(toJid("1234567890:5@s.whatsapp.net")).toBe("1234567890@s.whatsapp.net");
|
|
13
|
-
});
|
|
14
|
-
it("strips multi-digit device suffix", () => {
|
|
15
|
-
expect(toJid("9876543210:42@s.whatsapp.net")).toBe("9876543210@s.whatsapp.net");
|
|
16
|
-
});
|
|
17
|
-
it("passes through normal phone JID unchanged", () => {
|
|
18
|
-
expect(toJid("1234567890@s.whatsapp.net")).toBe("1234567890@s.whatsapp.net");
|
|
19
|
-
});
|
|
20
|
-
it("passes through group JID unchanged", () => {
|
|
21
|
-
expect(toJid("123456789-987654321@g.us")).toBe("123456789-987654321@g.us");
|
|
22
|
-
});
|
|
23
|
-
it("passes through LID JID unchanged", () => {
|
|
24
|
-
expect(toJid("12345@lid")).toBe("12345@lid");
|
|
25
|
-
});
|
|
26
|
-
it("normalizes bare phone number to JID", () => {
|
|
27
|
-
expect(toJid("1234567890")).toBe("1234567890@s.whatsapp.net");
|
|
28
|
-
});
|
|
29
|
-
it("strips + prefix from phone number", () => {
|
|
30
|
-
expect(toJid("+1234567890")).toBe("1234567890@s.whatsapp.net");
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
// ─── Fix 2: Search LIKE wildcard escaping ────────────────────────────
|
|
34
|
-
describe("searchMessages — LIKE wildcard escaping", () => {
|
|
35
|
-
let dbModule;
|
|
36
|
-
beforeAll(async () => {
|
|
37
|
-
await setupTestDb();
|
|
38
|
-
seedTestDb();
|
|
39
|
-
dbModule = await import("../db.js");
|
|
40
|
-
// Insert messages with specific content for wildcard tests
|
|
41
|
-
const db = dbModule.getDb();
|
|
42
|
-
db.prepare("INSERT INTO messages (id, chat_jid, from_me, type, text, timestamp, has_media) VALUES (?, ?, ?, ?, ?, ?, ?)").run("msg-percent", "15550001111@s.whatsapp.net", 0, "text", "100% done", 1700000010, 0);
|
|
43
|
-
db.prepare("INSERT INTO messages (id, chat_jid, from_me, type, text, timestamp, has_media) VALUES (?, ?, ?, ?, ?, ?, ?)").run("msg-underscore", "15550001111@s.whatsapp.net", 0, "text", "use_snake_case", 1700000020, 0);
|
|
44
|
-
db.prepare("INSERT INTO messages (id, chat_jid, from_me, type, text, timestamp, has_media) VALUES (?, ?, ?, ?, ?, ?, ?)").run("msg-normal", "15550001111@s.whatsapp.net", 0, "text", "normal message", 1700000030, 0);
|
|
45
|
-
});
|
|
46
|
-
afterAll(() => {
|
|
47
|
-
closeTestDb();
|
|
48
|
-
});
|
|
49
|
-
it("searching '%' does NOT match all messages", () => {
|
|
50
|
-
const results = dbModule.searchMessages("%");
|
|
51
|
-
// Should only match messages containing a literal "%" character
|
|
52
|
-
expect(results.length).toBeLessThanOrEqual(1);
|
|
53
|
-
if (results.length > 0) {
|
|
54
|
-
expect(results.every((r) => typeof r.text === "string" && r.text.includes("%"))).toBe(true);
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
it("searching '_' does NOT match single characters", () => {
|
|
58
|
-
const results = dbModule.searchMessages("_");
|
|
59
|
-
// Should only match messages containing a literal "_" character
|
|
60
|
-
for (const r of results) {
|
|
61
|
-
expect(typeof r.text === "string" && r.text.includes("_")).toBe(true);
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
it("finds messages with literal % in text", () => {
|
|
65
|
-
const results = dbModule.searchMessages("100%");
|
|
66
|
-
expect(results.length).toBeGreaterThanOrEqual(1);
|
|
67
|
-
expect(results.some((r) => r.text === "100% done")).toBe(true);
|
|
68
|
-
});
|
|
69
|
-
it("finds messages with literal _ in text", () => {
|
|
70
|
-
const results = dbModule.searchMessages("snake_case");
|
|
71
|
-
expect(results.length).toBeGreaterThanOrEqual(1);
|
|
72
|
-
expect(results.some((r) => r.text === "use_snake_case")).toBe(true);
|
|
73
|
-
});
|
|
74
|
-
it("normal substring search still works", () => {
|
|
75
|
-
const results = dbModule.searchMessages("normal");
|
|
76
|
-
expect(results.length).toBeGreaterThanOrEqual(1);
|
|
77
|
-
expect(results.some((r) => r.text === "normal message")).toBe(true);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
// ─── Fix 3: VCF path containment ────────────────────────────────────
|
|
81
|
-
describe("importContactsFromVcf — path containment", () => {
|
|
82
|
-
let importContactsFromVcf;
|
|
83
|
-
let Database;
|
|
84
|
-
beforeAll(async () => {
|
|
85
|
-
const mod = await import("../import-contacts.js");
|
|
86
|
-
importContactsFromVcf = mod.importContactsFromVcf;
|
|
87
|
-
const dbMod = await import("better-sqlite3");
|
|
88
|
-
Database = (dbMod.default ?? dbMod);
|
|
89
|
-
});
|
|
90
|
-
it("rejects /etc/passwd as VCF path", () => {
|
|
91
|
-
// Create a minimal in-memory DB with schema
|
|
92
|
-
const db = new Database(":memory:");
|
|
93
|
-
db.exec(`
|
|
94
|
-
CREATE TABLE IF NOT EXISTS chats (jid TEXT PRIMARY KEY, name TEXT, conversation_ts INTEGER DEFAULT 0, unread_count INTEGER DEFAULT 0);
|
|
95
|
-
CREATE TABLE IF NOT EXISTS contacts (jid TEXT PRIMARY KEY, name TEXT, notify TEXT);
|
|
96
|
-
`);
|
|
97
|
-
expect(() => importContactsFromVcf(db, "/etc/passwd")).toThrow(/VCF path not allowed/);
|
|
98
|
-
db.close();
|
|
99
|
-
});
|
|
100
|
-
it("rejects path traversal attempts", () => {
|
|
101
|
-
const db = new Database(":memory:");
|
|
102
|
-
db.exec(`
|
|
103
|
-
CREATE TABLE IF NOT EXISTS chats (jid TEXT PRIMARY KEY, name TEXT, conversation_ts INTEGER DEFAULT 0, unread_count INTEGER DEFAULT 0);
|
|
104
|
-
CREATE TABLE IF NOT EXISTS contacts (jid TEXT PRIMARY KEY, name TEXT, notify TEXT);
|
|
105
|
-
`);
|
|
106
|
-
expect(() => importContactsFromVcf(db, "../../../etc/shadow")).toThrow(/VCF path not allowed/);
|
|
107
|
-
db.close();
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
// ─── Fix 4: list_chats limit passthrough ─────────────────────────────
|
|
111
|
-
describe("list_chats — limit passthrough to DB", () => {
|
|
112
|
-
let client;
|
|
113
|
-
beforeAll(async () => {
|
|
114
|
-
// Re-setup DB for MCP client tests (clean state)
|
|
115
|
-
await setupTestDb();
|
|
116
|
-
const dbModule = await import("../db.js");
|
|
117
|
-
const db = dbModule.getDb();
|
|
118
|
-
// Seed 10 chats with messages
|
|
119
|
-
for (let i = 1; i <= 10; i++) {
|
|
120
|
-
const jid = `1555000${String(i).padStart(4, "0")}@s.whatsapp.net`;
|
|
121
|
-
db.prepare("INSERT OR REPLACE INTO chats (jid, name, conversation_ts, unread_count) VALUES (?, ?, ?, ?)").run(jid, `Contact ${i}`, 1700000000 + i * 100, 0);
|
|
122
|
-
db.prepare("INSERT OR REPLACE INTO messages (id, chat_jid, from_me, type, text, timestamp, has_media) VALUES (?, ?, ?, ?, ?, ?, ?)").run(`msg-${i}`, jid, 0, "text", `Message from contact ${i}`, 1700000000 + i * 100, 0);
|
|
123
|
-
}
|
|
124
|
-
client = await createMcpTestClient();
|
|
125
|
-
});
|
|
126
|
-
afterAll(async () => {
|
|
127
|
-
await client?.close();
|
|
128
|
-
closeTestDb();
|
|
129
|
-
});
|
|
130
|
-
it("returns at most `limit` chats from DB", async () => {
|
|
131
|
-
const result = await client.callTool("list_chats", { limit: 5 });
|
|
132
|
-
expect(Array.isArray(result)).toBe(true);
|
|
133
|
-
expect(result.length).toBeLessThanOrEqual(5);
|
|
134
|
-
});
|
|
135
|
-
it("returns more chats with higher limit", async () => {
|
|
136
|
-
const result = await client.callTool("list_chats", { limit: 100 });
|
|
137
|
-
expect(Array.isArray(result)).toBe(true);
|
|
138
|
-
expect(result.length).toBeGreaterThanOrEqual(10);
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
//# sourceMappingURL=medium-fixes.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"medium-fixes.test.js","sourceRoot":"","sources":["../../src/__tests__/medium-fixes.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/rate-limit.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { createFakeBaileysSocket } from "./helpers/fake-baileys.js";
|
|
3
|
-
import { closeTestDb, seedTestDb, setupTestDb } from "./helpers/test-db.js";
|
|
4
|
-
const mockState = vi.hoisted(() => ({
|
|
5
|
-
sockets: [],
|
|
6
|
-
}));
|
|
7
|
-
vi.mock("@whiskeysockets/baileys", () => ({
|
|
8
|
-
default: vi.fn(() => {
|
|
9
|
-
const socket = createFakeBaileysSocket();
|
|
10
|
-
mockState.sockets.push(socket);
|
|
11
|
-
return socket;
|
|
12
|
-
}),
|
|
13
|
-
DisconnectReason: {
|
|
14
|
-
loggedOut: 401,
|
|
15
|
-
connectionClosed: 428,
|
|
16
|
-
connectionReplaced: 440,
|
|
17
|
-
badSession: 500,
|
|
18
|
-
unavailableService: 503,
|
|
19
|
-
restartRequired: 515,
|
|
20
|
-
connectionLost: 408,
|
|
21
|
-
forbidden: 403,
|
|
22
|
-
multideviceMismatch: 411,
|
|
23
|
-
},
|
|
24
|
-
fetchLatestBaileysVersion: vi.fn(async () => ({ version: [2, 3000, 0] })),
|
|
25
|
-
downloadMediaMessage: vi.fn(),
|
|
26
|
-
getContentType: vi.fn(),
|
|
27
|
-
initAuthCreds: vi.fn(() => ({})),
|
|
28
|
-
BufferJSON: {
|
|
29
|
-
replacer: (_key, value) => value,
|
|
30
|
-
reviver: (_key, value) => value,
|
|
31
|
-
},
|
|
32
|
-
proto: {
|
|
33
|
-
Message: {
|
|
34
|
-
AppStateSyncKeyData: {
|
|
35
|
-
fromObject: (value) => value,
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
}));
|
|
40
|
-
function latestSocket() {
|
|
41
|
-
const socket = mockState.sockets.at(-1);
|
|
42
|
-
if (!socket)
|
|
43
|
-
throw new Error("No fake socket was created");
|
|
44
|
-
return socket;
|
|
45
|
-
}
|
|
46
|
-
describe("SendRateLimiter", () => {
|
|
47
|
-
beforeEach(() => {
|
|
48
|
-
vi.useFakeTimers();
|
|
49
|
-
});
|
|
50
|
-
afterEach(() => {
|
|
51
|
-
vi.useRealTimers();
|
|
52
|
-
});
|
|
53
|
-
it("delays when called rapidly", async () => {
|
|
54
|
-
const { SendRateLimiter } = await import("../whatsapp.js");
|
|
55
|
-
const limiter = new SendRateLimiter(3000, 0); // no jitter for deterministic test
|
|
56
|
-
// First call: no delay (lastSendTimestamp is 0)
|
|
57
|
-
const start = Date.now();
|
|
58
|
-
const p1 = limiter.throttle();
|
|
59
|
-
await vi.advanceTimersByTimeAsync(0);
|
|
60
|
-
await p1;
|
|
61
|
-
const afterFirst = Date.now();
|
|
62
|
-
// Second call immediately: should delay by ~3000ms
|
|
63
|
-
const p2 = limiter.throttle();
|
|
64
|
-
// Should NOT have resolved yet
|
|
65
|
-
let resolved = false;
|
|
66
|
-
p2.then(() => { resolved = true; });
|
|
67
|
-
await vi.advanceTimersByTimeAsync(2999);
|
|
68
|
-
expect(resolved).toBe(false);
|
|
69
|
-
await vi.advanceTimersByTimeAsync(1);
|
|
70
|
-
await p2;
|
|
71
|
-
expect(Date.now() - afterFirst).toBeGreaterThanOrEqual(3000);
|
|
72
|
-
});
|
|
73
|
-
it("does not delay when enough time has elapsed", async () => {
|
|
74
|
-
const { SendRateLimiter } = await import("../whatsapp.js");
|
|
75
|
-
const limiter = new SendRateLimiter(3000, 0);
|
|
76
|
-
await limiter.throttle();
|
|
77
|
-
// Advance well past the interval
|
|
78
|
-
vi.advanceTimersByTime(5000);
|
|
79
|
-
const before = Date.now();
|
|
80
|
-
const p2 = limiter.throttle();
|
|
81
|
-
// Should resolve almost immediately (no setTimeout needed)
|
|
82
|
-
await vi.advanceTimersByTimeAsync(0);
|
|
83
|
-
await p2;
|
|
84
|
-
// Elapsed should be minimal (just jitter=0)
|
|
85
|
-
expect(Date.now() - before).toBeLessThan(100);
|
|
86
|
-
});
|
|
87
|
-
it("adds random jitter to delay", async () => {
|
|
88
|
-
const { SendRateLimiter } = await import("../whatsapp.js");
|
|
89
|
-
// First call: no jitter. Second call: jitter = 0.5 * 2000 = 1000ms
|
|
90
|
-
vi.spyOn(Math, "random").mockReturnValueOnce(0).mockReturnValueOnce(0.5);
|
|
91
|
-
const limiter = new SendRateLimiter(3000, 2000);
|
|
92
|
-
await limiter.throttle();
|
|
93
|
-
// Second call: should delay 3000ms (min interval) + 1000ms (jitter) = 4000ms
|
|
94
|
-
const p2 = limiter.throttle();
|
|
95
|
-
let resolved = false;
|
|
96
|
-
p2.then(() => { resolved = true; });
|
|
97
|
-
await vi.advanceTimersByTimeAsync(3999);
|
|
98
|
-
expect(resolved).toBe(false);
|
|
99
|
-
await vi.advanceTimersByTimeAsync(1);
|
|
100
|
-
await p2;
|
|
101
|
-
expect(resolved).toBe(true);
|
|
102
|
-
vi.spyOn(Math, "random").mockRestore();
|
|
103
|
-
});
|
|
104
|
-
it("always adds jitter even when enough time elapsed", async () => {
|
|
105
|
-
const { SendRateLimiter } = await import("../whatsapp.js");
|
|
106
|
-
vi.spyOn(Math, "random").mockReturnValueOnce(0).mockReturnValueOnce(0.5);
|
|
107
|
-
const limiter = new SendRateLimiter(3000, 2000);
|
|
108
|
-
await limiter.throttle();
|
|
109
|
-
vi.advanceTimersByTime(10000); // well past min interval
|
|
110
|
-
// Jitter = 0.5 * 2000 = 1000ms delay even though min interval passed
|
|
111
|
-
const p2 = limiter.throttle();
|
|
112
|
-
let resolved = false;
|
|
113
|
-
p2.then(() => { resolved = true; });
|
|
114
|
-
await vi.advanceTimersByTimeAsync(999);
|
|
115
|
-
expect(resolved).toBe(false);
|
|
116
|
-
await vi.advanceTimersByTimeAsync(1);
|
|
117
|
-
await p2;
|
|
118
|
-
expect(resolved).toBe(true);
|
|
119
|
-
vi.spyOn(Math, "random").mockRestore();
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
describe("rate limiting integration", () => {
|
|
123
|
-
const originalMinInterval = process.env.MIN_SEND_INTERVAL_MS;
|
|
124
|
-
const originalJitter = process.env.SEND_JITTER_MS;
|
|
125
|
-
beforeEach(async () => {
|
|
126
|
-
vi.resetModules();
|
|
127
|
-
vi.useFakeTimers();
|
|
128
|
-
mockState.sockets.length = 0;
|
|
129
|
-
process.env.MIN_SEND_INTERVAL_MS = "3000";
|
|
130
|
-
process.env.SEND_JITTER_MS = "0"; // no jitter for predictable integration tests
|
|
131
|
-
await setupTestDb();
|
|
132
|
-
seedTestDb();
|
|
133
|
-
});
|
|
134
|
-
afterEach(async () => {
|
|
135
|
-
const whatsapp = await import("../whatsapp.js");
|
|
136
|
-
await whatsapp.closeWhatsApp();
|
|
137
|
-
closeTestDb();
|
|
138
|
-
vi.useRealTimers();
|
|
139
|
-
if (originalMinInterval === undefined) {
|
|
140
|
-
delete process.env.MIN_SEND_INTERVAL_MS;
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
process.env.MIN_SEND_INTERVAL_MS = originalMinInterval;
|
|
144
|
-
}
|
|
145
|
-
if (originalJitter === undefined) {
|
|
146
|
-
delete process.env.SEND_JITTER_MS;
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
process.env.SEND_JITTER_MS = originalJitter;
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
it("delays second rapid send_message by at least MIN_SEND_INTERVAL_MS", async () => {
|
|
153
|
-
const whatsapp = await import("../whatsapp.js");
|
|
154
|
-
await whatsapp.initWhatsApp();
|
|
155
|
-
const socket = latestSocket();
|
|
156
|
-
socket.emitConnectionOpen();
|
|
157
|
-
// First send — should go immediately
|
|
158
|
-
const p1 = whatsapp.sendTextMessage("15550001111", "first");
|
|
159
|
-
await vi.advanceTimersByTimeAsync(0);
|
|
160
|
-
await p1;
|
|
161
|
-
// Second send immediately — should be delayed
|
|
162
|
-
const p2 = whatsapp.sendTextMessage("15550001111", "second");
|
|
163
|
-
let secondDone = false;
|
|
164
|
-
p2.then(() => { secondDone = true; });
|
|
165
|
-
// At 2999ms, should NOT be done
|
|
166
|
-
await vi.advanceTimersByTimeAsync(2999);
|
|
167
|
-
expect(secondDone).toBe(false);
|
|
168
|
-
// At 3000ms, should complete
|
|
169
|
-
await vi.advanceTimersByTimeAsync(1);
|
|
170
|
-
await p2;
|
|
171
|
-
expect(secondDone).toBe(true);
|
|
172
|
-
});
|
|
173
|
-
it("respects env var configuration for MIN_SEND_INTERVAL_MS", async () => {
|
|
174
|
-
// Already set MIN_SEND_INTERVAL_MS=3000 and SEND_JITTER_MS=0 in beforeEach
|
|
175
|
-
// This test validates the module reads them
|
|
176
|
-
const whatsapp = await import("../whatsapp.js");
|
|
177
|
-
await whatsapp.initWhatsApp();
|
|
178
|
-
const socket = latestSocket();
|
|
179
|
-
socket.emitConnectionOpen();
|
|
180
|
-
const p1 = whatsapp.sendTextMessage("15550001111", "a");
|
|
181
|
-
await vi.advanceTimersByTimeAsync(0);
|
|
182
|
-
await p1;
|
|
183
|
-
const p2 = whatsapp.sendTextMessage("15550001111", "b");
|
|
184
|
-
let done = false;
|
|
185
|
-
p2.then(() => { done = true; });
|
|
186
|
-
await vi.advanceTimersByTimeAsync(2500);
|
|
187
|
-
expect(done).toBe(false);
|
|
188
|
-
await vi.advanceTimersByTimeAsync(500);
|
|
189
|
-
await p2;
|
|
190
|
-
expect(done).toBe(true);
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
//# sourceMappingURL=rate-limit.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.test.js","sourceRoot":"","sources":["../../src/__tests__/rate-limit.test.ts"],"names":[],"mappings":"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"}
|