@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.
Files changed (114) hide show
  1. package/dist/db.d.ts +28 -1
  2. package/dist/db.d.ts.map +1 -1
  3. package/dist/db.js +153 -30
  4. package/dist/db.js.map +1 -1
  5. package/dist/http-server.d.ts +8 -0
  6. package/dist/http-server.d.ts.map +1 -0
  7. package/dist/http-server.js +198 -0
  8. package/dist/http-server.js.map +1 -0
  9. package/dist/import-contacts.d.ts +6 -3
  10. package/dist/import-contacts.d.ts.map +1 -1
  11. package/dist/import-contacts.js +28 -14
  12. package/dist/import-contacts.js.map +1 -1
  13. package/dist/index.js +192 -26
  14. package/dist/index.js.map +1 -1
  15. package/dist/resources.d.ts +16 -0
  16. package/dist/resources.d.ts.map +1 -0
  17. package/dist/resources.js +84 -0
  18. package/dist/resources.js.map +1 -0
  19. package/dist/tools.d.ts.map +1 -1
  20. package/dist/tools.js +38 -15
  21. package/dist/tools.js.map +1 -1
  22. package/dist/whatsapp.d.ts +13 -1
  23. package/dist/whatsapp.d.ts.map +1 -1
  24. package/dist/whatsapp.js +167 -31
  25. package/dist/whatsapp.js.map +1 -1
  26. package/package.json +5 -1
  27. package/dist/__tests__/connection.test.d.ts +0 -2
  28. package/dist/__tests__/connection.test.d.ts.map +0 -1
  29. package/dist/__tests__/connection.test.js +0 -105
  30. package/dist/__tests__/connection.test.js.map +0 -1
  31. package/dist/__tests__/disconnect.test.d.ts +0 -2
  32. package/dist/__tests__/disconnect.test.d.ts.map +0 -1
  33. package/dist/__tests__/disconnect.test.js +0 -166
  34. package/dist/__tests__/disconnect.test.js.map +0 -1
  35. package/dist/__tests__/download-media.test.d.ts +0 -2
  36. package/dist/__tests__/download-media.test.d.ts.map +0 -1
  37. package/dist/__tests__/download-media.test.js +0 -110
  38. package/dist/__tests__/download-media.test.js.map +0 -1
  39. package/dist/__tests__/failures/connection-failures.test.d.ts +0 -2
  40. package/dist/__tests__/failures/connection-failures.test.d.ts.map +0 -1
  41. package/dist/__tests__/failures/connection-failures.test.js +0 -146
  42. package/dist/__tests__/failures/connection-failures.test.js.map +0 -1
  43. package/dist/__tests__/failures/edge-cases.test.d.ts +0 -2
  44. package/dist/__tests__/failures/edge-cases.test.d.ts.map +0 -1
  45. package/dist/__tests__/failures/edge-cases.test.js +0 -121
  46. package/dist/__tests__/failures/edge-cases.test.js.map +0 -1
  47. package/dist/__tests__/failures/resource-failures.test.d.ts +0 -2
  48. package/dist/__tests__/failures/resource-failures.test.d.ts.map +0 -1
  49. package/dist/__tests__/failures/resource-failures.test.js +0 -136
  50. package/dist/__tests__/failures/resource-failures.test.js.map +0 -1
  51. package/dist/__tests__/failures/security-failures.test.d.ts +0 -2
  52. package/dist/__tests__/failures/security-failures.test.d.ts.map +0 -1
  53. package/dist/__tests__/failures/security-failures.test.js +0 -0
  54. package/dist/__tests__/failures/security-failures.test.js.map +0 -1
  55. package/dist/__tests__/helpers/fake-baileys.d.ts +0 -52
  56. package/dist/__tests__/helpers/fake-baileys.d.ts.map +0 -1
  57. package/dist/__tests__/helpers/fake-baileys.js +0 -60
  58. package/dist/__tests__/helpers/fake-baileys.js.map +0 -1
  59. package/dist/__tests__/helpers/mcp-test-client.d.ts +0 -9
  60. package/dist/__tests__/helpers/mcp-test-client.d.ts.map +0 -1
  61. package/dist/__tests__/helpers/mcp-test-client.js +0 -40
  62. package/dist/__tests__/helpers/mcp-test-client.js.map +0 -1
  63. package/dist/__tests__/helpers/test-db.d.ts +0 -4
  64. package/dist/__tests__/helpers/test-db.d.ts.map +0 -1
  65. package/dist/__tests__/helpers/test-db.js +0 -32
  66. package/dist/__tests__/helpers/test-db.js.map +0 -1
  67. package/dist/__tests__/integration/chat-navigation.test.d.ts +0 -2
  68. package/dist/__tests__/integration/chat-navigation.test.d.ts.map +0 -1
  69. package/dist/__tests__/integration/chat-navigation.test.js +0 -171
  70. package/dist/__tests__/integration/chat-navigation.test.js.map +0 -1
  71. package/dist/__tests__/integration/contacts-flow.test.d.ts +0 -2
  72. package/dist/__tests__/integration/contacts-flow.test.d.ts.map +0 -1
  73. package/dist/__tests__/integration/contacts-flow.test.js +0 -144
  74. package/dist/__tests__/integration/contacts-flow.test.js.map +0 -1
  75. package/dist/__tests__/integration/media-flow.test.d.ts +0 -2
  76. package/dist/__tests__/integration/media-flow.test.d.ts.map +0 -1
  77. package/dist/__tests__/integration/media-flow.test.js +0 -225
  78. package/dist/__tests__/integration/media-flow.test.js.map +0 -1
  79. package/dist/__tests__/integration/search-flow.test.d.ts +0 -2
  80. package/dist/__tests__/integration/search-flow.test.d.ts.map +0 -1
  81. package/dist/__tests__/integration/search-flow.test.js +0 -44
  82. package/dist/__tests__/integration/search-flow.test.js.map +0 -1
  83. package/dist/__tests__/integration/send-message.test.d.ts +0 -2
  84. package/dist/__tests__/integration/send-message.test.d.ts.map +0 -1
  85. package/dist/__tests__/integration/send-message.test.js +0 -160
  86. package/dist/__tests__/integration/send-message.test.js.map +0 -1
  87. package/dist/__tests__/lock-file.test.d.ts +0 -2
  88. package/dist/__tests__/lock-file.test.d.ts.map +0 -1
  89. package/dist/__tests__/lock-file.test.js +0 -63
  90. package/dist/__tests__/lock-file.test.js.map +0 -1
  91. package/dist/__tests__/medium-fixes.test.d.ts +0 -2
  92. package/dist/__tests__/medium-fixes.test.d.ts.map +0 -1
  93. package/dist/__tests__/medium-fixes.test.js +0 -141
  94. package/dist/__tests__/medium-fixes.test.js.map +0 -1
  95. package/dist/__tests__/rate-limit.test.d.ts +0 -2
  96. package/dist/__tests__/rate-limit.test.d.ts.map +0 -1
  97. package/dist/__tests__/rate-limit.test.js +0 -193
  98. package/dist/__tests__/rate-limit.test.js.map +0 -1
  99. package/dist/__tests__/send-file.test.d.ts +0 -2
  100. package/dist/__tests__/send-file.test.d.ts.map +0 -1
  101. package/dist/__tests__/send-file.test.js +0 -237
  102. package/dist/__tests__/send-file.test.js.map +0 -1
  103. package/dist/__tests__/smoke.test.d.ts +0 -2
  104. package/dist/__tests__/smoke.test.d.ts.map +0 -1
  105. package/dist/__tests__/smoke.test.js +0 -28
  106. package/dist/__tests__/smoke.test.js.map +0 -1
  107. package/dist/__tests__/transcribe.test.d.ts +0 -2
  108. package/dist/__tests__/transcribe.test.d.ts.map +0 -1
  109. package/dist/__tests__/transcribe.test.js +0 -71
  110. package/dist/__tests__/transcribe.test.js.map +0 -1
  111. package/dist/__tests__/zombie.test.d.ts +0 -2
  112. package/dist/__tests__/zombie.test.d.ts.map +0 -1
  113. package/dist/__tests__/zombie.test.js +0 -145
  114. package/dist/__tests__/zombie.test.js.map +0 -1
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=send-file.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"send-file.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/send-file.test.ts"],"names":[],"mappings":""}
@@ -1,237 +0,0 @@
1
- import fs from "node:fs";
2
- import os from "node:os";
3
- import path from "node:path";
4
- import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
5
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
6
- import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
7
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
- import { closeTestDb, seedTestDb, setupTestDb } from "./helpers/test-db.js";
9
- vi.mock("@whiskeysockets/baileys", () => {
10
- const listeners = new Map();
11
- const ev = {
12
- on(event, handler) {
13
- const arr = listeners.get(event) || [];
14
- arr.push(handler);
15
- listeners.set(event, arr);
16
- },
17
- process(handler) {
18
- const arr = listeners.get("event") || [];
19
- arr.push(handler);
20
- listeners.set("event", arr);
21
- },
22
- emit(event, payload) {
23
- for (const handler of listeners.get(event) || []) {
24
- void handler(payload);
25
- }
26
- },
27
- emitBatch(payload) {
28
- for (const handler of listeners.get("event") || []) {
29
- void handler(payload);
30
- }
31
- },
32
- removeAllListeners() {
33
- listeners.clear();
34
- },
35
- };
36
- const fakeSocket = {
37
- ev,
38
- sentMessages: [],
39
- user: {
40
- id: "15559990000@s.whatsapp.net",
41
- name: "Test User",
42
- lid: "15559990000@lid",
43
- },
44
- async sendMessage(jid, content) {
45
- const streamLike = [content.image, content.video, content.audio, content.document].find((value) => value && typeof value.on === "function");
46
- if (streamLike) {
47
- await new Promise((resolve) => {
48
- streamLike.on("open", () => {
49
- streamLike.destroy();
50
- resolve();
51
- });
52
- streamLike.on("error", () => resolve());
53
- });
54
- }
55
- fakeSocket.sentMessages.push({ jid, content });
56
- return { key: { id: `fake-msg-${fakeSocket.sentMessages.length}` } };
57
- },
58
- async chatModify() {
59
- return undefined;
60
- },
61
- async groupMetadata(jid) {
62
- return { subject: `Group ${jid}` };
63
- },
64
- async updateMediaMessage() {
65
- return undefined;
66
- },
67
- end() {
68
- listeners.clear();
69
- },
70
- };
71
- return {
72
- default: vi.fn(() => fakeSocket),
73
- DisconnectReason: { loggedOut: 401, connectionReplaced: 440 },
74
- fetchLatestBaileysVersion: vi.fn(async () => ({ version: [2, 3000, 0] })),
75
- downloadMediaMessage: vi.fn(),
76
- getContentType: vi.fn(),
77
- initAuthCreds: vi.fn(() => ({})),
78
- BufferJSON: {
79
- replacer: (_key, value) => value,
80
- reviver: (_key, value) => value,
81
- },
82
- proto: {
83
- Message: {
84
- AppStateSyncKeyData: {
85
- fromObject: (value) => value,
86
- },
87
- },
88
- },
89
- __fakeSocket: fakeSocket,
90
- };
91
- });
92
- function parseToolJson(result) {
93
- const text = result.content?.find((entry) => entry.type === "text")?.text || "";
94
- try {
95
- return JSON.parse(text);
96
- }
97
- catch {
98
- return text;
99
- }
100
- }
101
- describe("send_file security", () => {
102
- const originalAllowedDir = process.env.ALLOWED_SEND_DIR;
103
- const originalMaxSize = process.env.MAX_SEND_FILE_SIZE;
104
- let tempDir;
105
- let server;
106
- let client;
107
- let closeWhatsApp;
108
- beforeAll(async () => {
109
- await setupTestDb();
110
- seedTestDb();
111
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "send-file-test-"));
112
- process.env.ALLOWED_SEND_DIR = tempDir;
113
- process.env.MAX_SEND_FILE_SIZE = "67108864";
114
- process.env.MIN_SEND_INTERVAL_MS = "0";
115
- process.env.SEND_JITTER_MS = "0";
116
- const whatsapp = await import("../whatsapp.js");
117
- closeWhatsApp = whatsapp.closeWhatsApp;
118
- await whatsapp.initWhatsApp();
119
- const baileys = await import("@whiskeysockets/baileys");
120
- baileys.__fakeSocket.ev.emitBatch({
121
- "connection.update": { connection: "open" },
122
- });
123
- server = new McpServer({ name: "whatsapp-test", version: "1.0.0" });
124
- const { registerTools } = await import("../tools.js");
125
- registerTools(server);
126
- const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
127
- client = new Client({ name: "whatsapp-test-client", version: "1.0.0" });
128
- await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
129
- });
130
- afterAll(async () => {
131
- await Promise.all([client?.close(), server?.close()]);
132
- await closeWhatsApp?.();
133
- closeTestDb();
134
- fs.rmSync(tempDir, { recursive: true, force: true });
135
- if (originalAllowedDir === undefined) {
136
- delete process.env.ALLOWED_SEND_DIR;
137
- }
138
- else {
139
- process.env.ALLOWED_SEND_DIR = originalAllowedDir;
140
- }
141
- if (originalMaxSize === undefined) {
142
- delete process.env.MAX_SEND_FILE_SIZE;
143
- }
144
- else {
145
- process.env.MAX_SEND_FILE_SIZE = originalMaxSize;
146
- }
147
- });
148
- it("returns preview when confirmed=false and does not send", async () => {
149
- const filePath = path.join(tempDir, "preview.txt");
150
- fs.writeFileSync(filePath, "hello");
151
- const before = (await import("@whiskeysockets/baileys")).__fakeSocket.sentMessages.length;
152
- const result = (await client.callTool({
153
- name: "send_file",
154
- arguments: {
155
- jid: "15550001111@s.whatsapp.net",
156
- filePath,
157
- caption: "preview",
158
- confirmed: false,
159
- },
160
- }));
161
- const payload = parseToolJson(result);
162
- const after = (await import("@whiskeysockets/baileys")).__fakeSocket.sentMessages.length;
163
- expect(result.isError).toBeFalsy();
164
- expect(payload).toMatchObject({
165
- preview: true,
166
- fileName: "preview.txt",
167
- fileSize: 5,
168
- recipient: expect.objectContaining({
169
- jid: "15550001111@s.whatsapp.net",
170
- }),
171
- });
172
- expect(after).toBe(before);
173
- });
174
- it("rejects traversal path with Path not allowed", async () => {
175
- const result = (await client.callTool({
176
- name: "send_file",
177
- arguments: {
178
- jid: "15550001111@s.whatsapp.net",
179
- filePath: "../../etc/passwd",
180
- confirmed: true,
181
- },
182
- }));
183
- const text = parseToolJson(result) || "";
184
- expect(result.isError).toBe(true);
185
- expect(text).toContain("Path not allowed");
186
- });
187
- it("rejects absolute path outside allowlist", async () => {
188
- const result = (await client.callTool({
189
- name: "send_file",
190
- arguments: {
191
- jid: "15550001111@s.whatsapp.net",
192
- filePath: "/home/user/.ssh/id_rsa",
193
- confirmed: true,
194
- },
195
- }));
196
- const text = parseToolJson(result) || "";
197
- expect(result.isError).toBe(true);
198
- expect(text).toContain("Path not allowed");
199
- });
200
- it("rejects file larger than MAX_SEND_FILE_SIZE", async () => {
201
- process.env.MAX_SEND_FILE_SIZE = "4";
202
- const filePath = path.join(tempDir, "too-large.txt");
203
- fs.writeFileSync(filePath, "12345");
204
- const result = (await client.callTool({
205
- name: "send_file",
206
- arguments: {
207
- jid: "15550001111@s.whatsapp.net",
208
- filePath,
209
- confirmed: true,
210
- },
211
- }));
212
- const text = parseToolJson(result) || "";
213
- expect(result.isError).toBe(true);
214
- expect(text).toContain("File too large");
215
- process.env.MAX_SEND_FILE_SIZE = "67108864";
216
- });
217
- it("sends successfully when confirmed=true with allowed path under size limit", async () => {
218
- const filePath = path.join(tempDir, "ok.txt");
219
- fs.writeFileSync(filePath, "ok");
220
- const result = (await client.callTool({
221
- name: "send_file",
222
- arguments: {
223
- jid: "15550001111@s.whatsapp.net",
224
- filePath,
225
- caption: "ok",
226
- confirmed: true,
227
- },
228
- }));
229
- const payload = parseToolJson(result);
230
- expect(result.isError).toBeFalsy();
231
- expect(payload).toMatchObject({
232
- success: true,
233
- to: "15550001111@s.whatsapp.net",
234
- });
235
- });
236
- });
237
- //# sourceMappingURL=send-file.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"send-file.test.js","sourceRoot":"","sources":["../../src/__tests__/send-file.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=smoke.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"smoke.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/smoke.test.ts"],"names":[],"mappings":""}
@@ -1,28 +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
- describe("MCP smoke test", () => {
5
- let client;
6
- beforeAll(async () => {
7
- await setupTestDb();
8
- seedTestDb();
9
- client = await createMcpTestClient();
10
- });
11
- afterAll(async () => {
12
- await client?.close();
13
- closeTestDb();
14
- });
15
- it("connects MCP client, exposes 16 tools, and returns seeded chats", async () => {
16
- const tools = await client.listTools();
17
- expect(tools).toHaveLength(16);
18
- const listChats = await client.callTool("list_chats", { limit: 20 });
19
- expect(Array.isArray(listChats)).toBe(true);
20
- expect(listChats).toEqual(expect.arrayContaining([
21
- expect.objectContaining({
22
- jid: "15550001111@s.whatsapp.net",
23
- name: "Alice Test",
24
- }),
25
- ]));
26
- });
27
- });
28
- //# sourceMappingURL=smoke.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"smoke.test.js","sourceRoot":"","sources":["../../src/__tests__/smoke.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAsB,MAAM,8BAA8B,CAAC;AAEvF,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,IAAI,MAAqB,CAAC;IAE1B,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,WAAW,EAAE,CAAC;QACpB,UAAU,EAAE,CAAC;QACb,MAAM,GAAG,MAAM,mBAAmB,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,KAAK,IAAI,EAAE;QAClB,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC;QACtB,WAAW,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QAE/B,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACrE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CACvB,MAAM,CAAC,eAAe,CAAC;YACrB,MAAM,CAAC,gBAAgB,CAAC;gBACtB,GAAG,EAAE,4BAA4B;gBACjC,IAAI,EAAE,YAAY;aACnB,CAAC;SACH,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=transcribe.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transcribe.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/transcribe.test.ts"],"names":[],"mappings":""}
@@ -1,71 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { validateApiUrl } from "../utils.js";
3
- describe("validateApiUrl", () => {
4
- // --- Valid URLs ---
5
- it("accepts https Groq API URL", () => {
6
- const result = validateApiUrl("https://api.groq.com/openai/v1/audio/transcriptions");
7
- expect(result).toBeInstanceOf(URL);
8
- expect(result.href).toBe("https://api.groq.com/openai/v1/audio/transcriptions");
9
- });
10
- it("accepts https OpenAI API URL", () => {
11
- const result = validateApiUrl("https://api.openai.com/v1/audio/transcriptions");
12
- expect(result).toBeInstanceOf(URL);
13
- });
14
- it("accepts http URL to public host", () => {
15
- const result = validateApiUrl("http://api.example.com/v1/transcribe");
16
- expect(result).toBeInstanceOf(URL);
17
- expect(result.protocol).toBe("http:");
18
- });
19
- // --- Protocol rejection ---
20
- it("rejects file:// protocol", () => {
21
- expect(() => validateApiUrl("file:///etc/passwd")).toThrow("Only http/https URLs allowed");
22
- });
23
- it("rejects ftp:// protocol", () => {
24
- expect(() => validateApiUrl("ftp://evil.com/file")).toThrow("Only http/https URLs allowed");
25
- });
26
- it("rejects javascript: protocol", () => {
27
- expect(() => validateApiUrl("javascript:alert(1)")).toThrow();
28
- });
29
- // --- Localhost rejection ---
30
- it("rejects localhost hostname", () => {
31
- expect(() => validateApiUrl("http://localhost:8080/")).toThrow("localhost not allowed");
32
- });
33
- it("rejects 127.0.0.1", () => {
34
- expect(() => validateApiUrl("http://127.0.0.1:8080/")).toThrow("localhost not allowed");
35
- });
36
- it("rejects ::1 (IPv6 loopback)", () => {
37
- expect(() => validateApiUrl("http://[::1]:8080/")).toThrow("localhost not allowed");
38
- });
39
- // --- Private IP rejection ---
40
- it("rejects 10.x.x.x (class A private)", () => {
41
- expect(() => validateApiUrl("http://10.0.0.1/")).toThrow("Private/internal IP");
42
- });
43
- it("rejects 172.16.x.x (class B private)", () => {
44
- expect(() => validateApiUrl("http://172.16.0.1/")).toThrow("Private/internal IP");
45
- });
46
- it("rejects 172.31.255.255 (class B private upper bound)", () => {
47
- expect(() => validateApiUrl("http://172.31.255.255/")).toThrow("Private/internal IP");
48
- });
49
- it("accepts 172.15.0.1 (not in private range)", () => {
50
- const result = validateApiUrl("http://172.15.0.1/");
51
- expect(result).toBeInstanceOf(URL);
52
- });
53
- it("accepts 172.32.0.1 (not in private range)", () => {
54
- const result = validateApiUrl("http://172.32.0.1/");
55
- expect(result).toBeInstanceOf(URL);
56
- });
57
- it("rejects 192.168.x.x (class C private)", () => {
58
- expect(() => validateApiUrl("http://192.168.1.1/")).toThrow("Private/internal IP");
59
- });
60
- it("rejects 169.254.169.254 (cloud metadata / link-local)", () => {
61
- expect(() => validateApiUrl("http://169.254.169.254/")).toThrow("Private/internal IP");
62
- });
63
- // --- Invalid URLs ---
64
- it("rejects completely invalid URL", () => {
65
- expect(() => validateApiUrl("not-a-url")).toThrow();
66
- });
67
- it("rejects empty string", () => {
68
- expect(() => validateApiUrl("")).toThrow();
69
- });
70
- });
71
- //# sourceMappingURL=transcribe.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transcribe.test.js","sourceRoot":"","sources":["../../src/__tests__/transcribe.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=zombie.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"zombie.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/zombie.test.ts"],"names":[],"mappings":""}
@@ -1,145 +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("zombie watchdog + send health check", () => {
47
- const originalZombieTimeout = process.env.ZOMBIE_TIMEOUT_MS;
48
- const originalMaxSendFailures = process.env.MAX_SEND_FAILURES;
49
- beforeEach(async () => {
50
- vi.resetModules();
51
- vi.useFakeTimers();
52
- mockState.sockets.length = 0;
53
- process.env.ZOMBIE_TIMEOUT_MS = "120000";
54
- process.env.MAX_SEND_FAILURES = "3";
55
- process.env.MIN_SEND_INTERVAL_MS = "0";
56
- process.env.SEND_JITTER_MS = "0";
57
- await setupTestDb();
58
- seedTestDb();
59
- });
60
- afterEach(async () => {
61
- const whatsapp = await import("../whatsapp.js");
62
- await whatsapp.closeWhatsApp();
63
- closeTestDb();
64
- vi.useRealTimers();
65
- if (originalZombieTimeout === undefined) {
66
- delete process.env.ZOMBIE_TIMEOUT_MS;
67
- }
68
- else {
69
- process.env.ZOMBIE_TIMEOUT_MS = originalZombieTimeout;
70
- }
71
- if (originalMaxSendFailures === undefined) {
72
- delete process.env.MAX_SEND_FAILURES;
73
- }
74
- else {
75
- process.env.MAX_SEND_FAILURES = originalMaxSendFailures;
76
- }
77
- });
78
- it("forces socket end after 2 minutes without connection.update activity", async () => {
79
- const whatsapp = await import("../whatsapp.js");
80
- await whatsapp.initWhatsApp();
81
- const socket = latestSocket();
82
- socket.emitConnectionOpen();
83
- const endSpy = vi.spyOn(socket, "end");
84
- vi.advanceTimersByTime(121_000);
85
- expect(endSpy).toHaveBeenCalled();
86
- const firstEndArg = endSpy.mock.calls.at(0)?.[0];
87
- expect(firstEndArg).toBeInstanceOf(Error);
88
- if (firstEndArg instanceof Error) {
89
- expect(firstEndArg.message).toContain("Zombie connection detected");
90
- }
91
- });
92
- it("clears zombie watchdog timer when socket disconnects", async () => {
93
- const whatsapp = await import("../whatsapp.js");
94
- await whatsapp.initWhatsApp();
95
- const socket = latestSocket();
96
- socket.emitConnectionOpen();
97
- const timersAfterOpen = vi.getTimerCount();
98
- expect(timersAfterOpen).toBeGreaterThanOrEqual(1); // at least zombie watchdog
99
- socket.emitConnectionClose(428);
100
- // Zombie watchdog cleared (-1), reconnect setTimeout added (+1) → net 0 change
101
- expect(vi.getTimerCount()).toBe(timersAfterOpen);
102
- });
103
- it("forces reconnect after 3 consecutive send failures", async () => {
104
- const whatsapp = await import("../whatsapp.js");
105
- await whatsapp.initWhatsApp();
106
- const socket = latestSocket();
107
- socket.emitConnectionOpen();
108
- const endSpy = vi.spyOn(socket, "end");
109
- const sendSpy = vi.spyOn(socket, "sendMessage").mockRejectedValue(new Error("send failed"));
110
- await expect(whatsapp.sendTextMessage("15550001111", "one")).rejects.toThrow("send failed");
111
- await expect(whatsapp.sendTextMessage("15550001111", "two")).rejects.toThrow("send failed");
112
- await expect(whatsapp.sendTextMessage("15550001111", "three")).rejects.toThrow("send failed");
113
- expect(sendSpy).toHaveBeenCalledTimes(3);
114
- expect(endSpy).toHaveBeenCalled();
115
- const firstEndArg = endSpy.mock.calls.at(0)?.[0];
116
- expect(firstEndArg).toBeInstanceOf(Error);
117
- if (firstEndArg instanceof Error) {
118
- expect(firstEndArg.message).toContain("Send health check failed");
119
- }
120
- });
121
- it("resets consecutive send failures to zero after a successful send", async () => {
122
- const whatsapp = await import("../whatsapp.js");
123
- await whatsapp.initWhatsApp();
124
- const socket = latestSocket();
125
- socket.emitConnectionOpen();
126
- const endSpy = vi.spyOn(socket, "end");
127
- const sendSpy = vi.spyOn(socket, "sendMessage");
128
- sendSpy
129
- .mockRejectedValueOnce(new Error("fail-1"))
130
- .mockRejectedValueOnce(new Error("fail-2"))
131
- .mockResolvedValueOnce({ key: { id: "ok" } })
132
- .mockRejectedValueOnce(new Error("fail-3"))
133
- .mockRejectedValueOnce(new Error("fail-4"))
134
- .mockRejectedValueOnce(new Error("fail-5"));
135
- await expect(whatsapp.sendTextMessage("15550001111", "a")).rejects.toThrow("fail-1");
136
- await expect(whatsapp.sendTextMessage("15550001111", "b")).rejects.toThrow("fail-2");
137
- await expect(whatsapp.sendTextMessage("15550001111", "c")).resolves.toMatchObject({ success: true });
138
- await expect(whatsapp.sendTextMessage("15550001111", "d")).rejects.toThrow("fail-3");
139
- await expect(whatsapp.sendTextMessage("15550001111", "e")).rejects.toThrow("fail-4");
140
- expect(endSpy).not.toHaveBeenCalled();
141
- await expect(whatsapp.sendTextMessage("15550001111", "f")).rejects.toThrow("fail-5");
142
- expect(endSpy).toHaveBeenCalledTimes(1);
143
- });
144
- });
145
- //# sourceMappingURL=zombie.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"zombie.test.js","sourceRoot":"","sources":["../../src/__tests__/zombie.test.ts"],"names":[],"mappings":"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"}