@sjawhar/whatsapp-mcp 1.0.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 (125) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +122 -0
  3. package/dist/__tests__/connection.test.d.ts +2 -0
  4. package/dist/__tests__/connection.test.d.ts.map +1 -0
  5. package/dist/__tests__/connection.test.js +105 -0
  6. package/dist/__tests__/connection.test.js.map +1 -0
  7. package/dist/__tests__/disconnect.test.d.ts +2 -0
  8. package/dist/__tests__/disconnect.test.d.ts.map +1 -0
  9. package/dist/__tests__/disconnect.test.js +166 -0
  10. package/dist/__tests__/disconnect.test.js.map +1 -0
  11. package/dist/__tests__/download-media.test.d.ts +2 -0
  12. package/dist/__tests__/download-media.test.d.ts.map +1 -0
  13. package/dist/__tests__/download-media.test.js +110 -0
  14. package/dist/__tests__/download-media.test.js.map +1 -0
  15. package/dist/__tests__/failures/connection-failures.test.d.ts +2 -0
  16. package/dist/__tests__/failures/connection-failures.test.d.ts.map +1 -0
  17. package/dist/__tests__/failures/connection-failures.test.js +146 -0
  18. package/dist/__tests__/failures/connection-failures.test.js.map +1 -0
  19. package/dist/__tests__/failures/edge-cases.test.d.ts +2 -0
  20. package/dist/__tests__/failures/edge-cases.test.d.ts.map +1 -0
  21. package/dist/__tests__/failures/edge-cases.test.js +121 -0
  22. package/dist/__tests__/failures/edge-cases.test.js.map +1 -0
  23. package/dist/__tests__/failures/resource-failures.test.d.ts +2 -0
  24. package/dist/__tests__/failures/resource-failures.test.d.ts.map +1 -0
  25. package/dist/__tests__/failures/resource-failures.test.js +136 -0
  26. package/dist/__tests__/failures/resource-failures.test.js.map +1 -0
  27. package/dist/__tests__/failures/security-failures.test.d.ts +2 -0
  28. package/dist/__tests__/failures/security-failures.test.d.ts.map +1 -0
  29. package/dist/__tests__/failures/security-failures.test.js +0 -0
  30. package/dist/__tests__/failures/security-failures.test.js.map +1 -0
  31. package/dist/__tests__/helpers/fake-baileys.d.ts +52 -0
  32. package/dist/__tests__/helpers/fake-baileys.d.ts.map +1 -0
  33. package/dist/__tests__/helpers/fake-baileys.js +60 -0
  34. package/dist/__tests__/helpers/fake-baileys.js.map +1 -0
  35. package/dist/__tests__/helpers/mcp-test-client.d.ts +9 -0
  36. package/dist/__tests__/helpers/mcp-test-client.d.ts.map +1 -0
  37. package/dist/__tests__/helpers/mcp-test-client.js +40 -0
  38. package/dist/__tests__/helpers/mcp-test-client.js.map +1 -0
  39. package/dist/__tests__/helpers/test-db.d.ts +4 -0
  40. package/dist/__tests__/helpers/test-db.d.ts.map +1 -0
  41. package/dist/__tests__/helpers/test-db.js +32 -0
  42. package/dist/__tests__/helpers/test-db.js.map +1 -0
  43. package/dist/__tests__/integration/chat-navigation.test.d.ts +2 -0
  44. package/dist/__tests__/integration/chat-navigation.test.d.ts.map +1 -0
  45. package/dist/__tests__/integration/chat-navigation.test.js +171 -0
  46. package/dist/__tests__/integration/chat-navigation.test.js.map +1 -0
  47. package/dist/__tests__/integration/contacts-flow.test.d.ts +2 -0
  48. package/dist/__tests__/integration/contacts-flow.test.d.ts.map +1 -0
  49. package/dist/__tests__/integration/contacts-flow.test.js +144 -0
  50. package/dist/__tests__/integration/contacts-flow.test.js.map +1 -0
  51. package/dist/__tests__/integration/media-flow.test.d.ts +2 -0
  52. package/dist/__tests__/integration/media-flow.test.d.ts.map +1 -0
  53. package/dist/__tests__/integration/media-flow.test.js +225 -0
  54. package/dist/__tests__/integration/media-flow.test.js.map +1 -0
  55. package/dist/__tests__/integration/search-flow.test.d.ts +2 -0
  56. package/dist/__tests__/integration/search-flow.test.d.ts.map +1 -0
  57. package/dist/__tests__/integration/search-flow.test.js +44 -0
  58. package/dist/__tests__/integration/search-flow.test.js.map +1 -0
  59. package/dist/__tests__/integration/send-message.test.d.ts +2 -0
  60. package/dist/__tests__/integration/send-message.test.d.ts.map +1 -0
  61. package/dist/__tests__/integration/send-message.test.js +160 -0
  62. package/dist/__tests__/integration/send-message.test.js.map +1 -0
  63. package/dist/__tests__/lock-file.test.d.ts +2 -0
  64. package/dist/__tests__/lock-file.test.d.ts.map +1 -0
  65. package/dist/__tests__/lock-file.test.js +63 -0
  66. package/dist/__tests__/lock-file.test.js.map +1 -0
  67. package/dist/__tests__/medium-fixes.test.d.ts +2 -0
  68. package/dist/__tests__/medium-fixes.test.d.ts.map +1 -0
  69. package/dist/__tests__/medium-fixes.test.js +141 -0
  70. package/dist/__tests__/medium-fixes.test.js.map +1 -0
  71. package/dist/__tests__/rate-limit.test.d.ts +2 -0
  72. package/dist/__tests__/rate-limit.test.d.ts.map +1 -0
  73. package/dist/__tests__/rate-limit.test.js +193 -0
  74. package/dist/__tests__/rate-limit.test.js.map +1 -0
  75. package/dist/__tests__/send-file.test.d.ts +2 -0
  76. package/dist/__tests__/send-file.test.d.ts.map +1 -0
  77. package/dist/__tests__/send-file.test.js +237 -0
  78. package/dist/__tests__/send-file.test.js.map +1 -0
  79. package/dist/__tests__/smoke.test.d.ts +2 -0
  80. package/dist/__tests__/smoke.test.d.ts.map +1 -0
  81. package/dist/__tests__/smoke.test.js +28 -0
  82. package/dist/__tests__/smoke.test.js.map +1 -0
  83. package/dist/__tests__/transcribe.test.d.ts +2 -0
  84. package/dist/__tests__/transcribe.test.d.ts.map +1 -0
  85. package/dist/__tests__/transcribe.test.js +71 -0
  86. package/dist/__tests__/transcribe.test.js.map +1 -0
  87. package/dist/__tests__/zombie.test.d.ts +2 -0
  88. package/dist/__tests__/zombie.test.d.ts.map +1 -0
  89. package/dist/__tests__/zombie.test.js +145 -0
  90. package/dist/__tests__/zombie.test.js.map +1 -0
  91. package/dist/db.d.ts +53 -0
  92. package/dist/db.d.ts.map +1 -0
  93. package/dist/db.js +509 -0
  94. package/dist/db.js.map +1 -0
  95. package/dist/import-contacts.d.ts +37 -0
  96. package/dist/import-contacts.d.ts.map +1 -0
  97. package/dist/import-contacts.js +242 -0
  98. package/dist/import-contacts.js.map +1 -0
  99. package/dist/index.d.ts +3 -0
  100. package/dist/index.d.ts.map +1 -0
  101. package/dist/index.js +62 -0
  102. package/dist/index.js.map +1 -0
  103. package/dist/lock.d.ts +16 -0
  104. package/dist/lock.d.ts.map +1 -0
  105. package/dist/lock.js +65 -0
  106. package/dist/lock.js.map +1 -0
  107. package/dist/tools.d.ts +6 -0
  108. package/dist/tools.d.ts.map +1 -0
  109. package/dist/tools.js +339 -0
  110. package/dist/tools.js.map +1 -0
  111. package/dist/transcribe.d.ts +8 -0
  112. package/dist/transcribe.d.ts.map +1 -0
  113. package/dist/transcribe.js +63 -0
  114. package/dist/transcribe.js.map +1 -0
  115. package/dist/utils.d.ts +51 -0
  116. package/dist/utils.d.ts.map +1 -0
  117. package/dist/utils.js +156 -0
  118. package/dist/utils.js.map +1 -0
  119. package/dist/whatsapp.d.ts +50 -0
  120. package/dist/whatsapp.d.ts.map +1 -0
  121. package/dist/whatsapp.js +896 -0
  122. package/dist/whatsapp.js.map +1 -0
  123. package/package.json +52 -0
  124. package/patches/@whiskeysockets+baileys+6.7.21.patch +46 -0
  125. package/patches/libsignal+2.0.1.patch +84 -0
@@ -0,0 +1,146 @@
1
+ import { afterEach, beforeEach, 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
+ forbidden: 403,
19
+ connectionLost: 408,
20
+ multideviceMismatch: 411,
21
+ connectionClosed: 428,
22
+ connectionReplaced: 440,
23
+ badSession: 500,
24
+ unavailableService: 503,
25
+ restartRequired: 515,
26
+ },
27
+ fetchLatestBaileysVersion: vi.fn(async () => ({ version: [2, 3000, 0] })),
28
+ downloadMediaMessage: vi.fn(),
29
+ getContentType: vi.fn(),
30
+ initAuthCreds: vi.fn(() => ({})),
31
+ BufferJSON: {
32
+ replacer: (_key, value) => value,
33
+ reviver: (_key, value) => value,
34
+ },
35
+ proto: {
36
+ Message: {
37
+ AppStateSyncKeyData: {
38
+ fromObject: (value) => value,
39
+ },
40
+ },
41
+ },
42
+ }));
43
+ function latestSocket() {
44
+ const socket = mockState.sockets.at(-1);
45
+ if (!socket)
46
+ throw new Error("No fake socket was created");
47
+ return socket;
48
+ }
49
+ function extractText(result) {
50
+ return result.content?.find((entry) => entry.type === "text")?.text || "";
51
+ }
52
+ describe("integration failures: connection handling", () => {
53
+ const originalMaxReconnectAttempts = process.env.MAX_RECONNECT_ATTEMPTS;
54
+ const originalZombieTimeout = process.env.ZOMBIE_TIMEOUT_MS;
55
+ let server;
56
+ let client;
57
+ let whatsapp;
58
+ beforeEach(async () => {
59
+ vi.resetModules();
60
+ vi.useFakeTimers();
61
+ mockState.sockets.length = 0;
62
+ process.env.MIN_SEND_INTERVAL_MS = "0";
63
+ process.env.SEND_JITTER_MS = "0";
64
+ process.env.MAX_RECONNECT_ATTEMPTS = "2";
65
+ process.env.ZOMBIE_TIMEOUT_MS = "2000";
66
+ await setupTestDb();
67
+ seedTestDb();
68
+ whatsapp = await import("../../whatsapp.js");
69
+ await whatsapp.initWhatsApp();
70
+ latestSocket().emitConnectionOpen();
71
+ server = new McpServer({ name: "whatsapp-test", version: "1.0.0" });
72
+ const { registerTools } = await import("../../tools.js");
73
+ registerTools(server);
74
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
75
+ client = new Client({ name: "whatsapp-test-client", version: "1.0.0" });
76
+ await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
77
+ });
78
+ afterEach(async () => {
79
+ await Promise.all([client?.close(), server?.close()]);
80
+ await whatsapp?.closeWhatsApp();
81
+ closeTestDb();
82
+ vi.useRealTimers();
83
+ if (originalMaxReconnectAttempts === undefined)
84
+ delete process.env.MAX_RECONNECT_ATTEMPTS;
85
+ else
86
+ process.env.MAX_RECONNECT_ATTEMPTS = originalMaxReconnectAttempts;
87
+ if (originalZombieTimeout === undefined)
88
+ delete process.env.ZOMBIE_TIMEOUT_MS;
89
+ else
90
+ process.env.ZOMBIE_TIMEOUT_MS = originalZombieTimeout;
91
+ });
92
+ it("returns a tool error (not hang) when disconnect occurs mid send_message call", async () => {
93
+ vi.useRealTimers();
94
+ const socket = latestSocket();
95
+ vi.spyOn(socket, "sendMessage").mockImplementation(async () => {
96
+ socket.emitConnectionClose(440);
97
+ throw new Error("socket disconnected during send");
98
+ });
99
+ const toolCall = client.callTool({
100
+ name: "send_message",
101
+ arguments: {
102
+ jid: "15550001111@s.whatsapp.net",
103
+ text: "should-fail",
104
+ confirmed: true,
105
+ },
106
+ });
107
+ const settleState = await Promise.race([
108
+ toolCall.then(() => "settled"),
109
+ new Promise((resolve) => setTimeout(() => resolve("timeout"), 100)),
110
+ ]);
111
+ expect(settleState).toBe("settled");
112
+ const result = await toolCall;
113
+ expect(result.isError).toBe(true);
114
+ expect(extractText(result)).toContain("socket disconnected during send");
115
+ vi.useFakeTimers();
116
+ });
117
+ it("increases reconnect backoff across repeated disconnect events", async () => {
118
+ const errorSpy = vi.spyOn(console, "error").mockImplementation(() => undefined);
119
+ latestSocket().emitConnectionClose(428);
120
+ expect(errorSpy.mock.calls.flat().join(" ")).toContain("Reconnecting in 2s");
121
+ latestSocket().emitConnectionClose(428);
122
+ expect(errorSpy.mock.calls.flat().join(" ")).toContain("Reconnecting in 4s");
123
+ });
124
+ it("stops reconnect scheduling after MAX_RECONNECT_ATTEMPTS cap", async () => {
125
+ const errorSpy = vi.spyOn(console, "error").mockImplementation(() => undefined);
126
+ latestSocket().emitConnectionClose(428);
127
+ latestSocket().emitConnectionClose(428);
128
+ latestSocket().emitConnectionClose(428);
129
+ const logText = errorSpy.mock.calls.flat().join(" ");
130
+ expect(logText).toContain("MAX_RECONNECT_ATTEMPTS (2)");
131
+ expect(logText).toContain("Stopping reconnect attempts");
132
+ });
133
+ it("detects zombie socket after silence timeout", async () => {
134
+ const socket = latestSocket();
135
+ socket.emitConnectionOpen();
136
+ const endSpy = vi.spyOn(socket, "end");
137
+ await vi.advanceTimersByTimeAsync(2_500);
138
+ expect(endSpy).toHaveBeenCalled();
139
+ const firstErrorArg = endSpy.mock.calls.at(0)?.[0];
140
+ expect(firstErrorArg).toBeInstanceOf(Error);
141
+ if (firstErrorArg instanceof Error) {
142
+ expect(firstErrorArg.message).toContain("Zombie connection detected");
143
+ }
144
+ });
145
+ });
146
+ //# sourceMappingURL=connection-failures.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-failures.test.js","sourceRoot":"","sources":["../../../src/__tests__/failures/connection-failures.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=edge-cases.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge-cases.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/failures/edge-cases.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,121 @@
1
+ import { afterEach, beforeEach, 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
+ forbidden: 403,
19
+ connectionLost: 408,
20
+ multideviceMismatch: 411,
21
+ connectionClosed: 428,
22
+ connectionReplaced: 440,
23
+ badSession: 500,
24
+ unavailableService: 503,
25
+ restartRequired: 515,
26
+ },
27
+ fetchLatestBaileysVersion: vi.fn(async () => ({ version: [2, 3000, 0] })),
28
+ downloadMediaMessage: vi.fn(),
29
+ getContentType: vi.fn(),
30
+ initAuthCreds: vi.fn(() => ({})),
31
+ BufferJSON: {
32
+ replacer: (_key, value) => value,
33
+ reviver: (_key, value) => value,
34
+ },
35
+ proto: {
36
+ Message: {
37
+ AppStateSyncKeyData: {
38
+ fromObject: (value) => value,
39
+ },
40
+ },
41
+ },
42
+ }));
43
+ function parseToolJson(result) {
44
+ const text = result.content?.find((entry) => entry.type === "text")?.text || "";
45
+ try {
46
+ return JSON.parse(text);
47
+ }
48
+ catch {
49
+ return text;
50
+ }
51
+ }
52
+ describe("integration failures: edge cases", () => {
53
+ let server;
54
+ let client;
55
+ let closeWhatsApp;
56
+ beforeEach(async () => {
57
+ vi.resetModules();
58
+ mockState.sockets.length = 0;
59
+ process.env.MIN_SEND_INTERVAL_MS = "0";
60
+ process.env.SEND_JITTER_MS = "0";
61
+ await setupTestDb();
62
+ seedTestDb();
63
+ const whatsapp = await import("../../whatsapp.js");
64
+ closeWhatsApp = whatsapp.closeWhatsApp;
65
+ await whatsapp.initWhatsApp();
66
+ const socket = mockState.sockets.at(-1);
67
+ if (!socket)
68
+ throw new Error("Expected fake socket");
69
+ socket.emitConnectionOpen();
70
+ server = new McpServer({ name: "whatsapp-test", version: "1.0.0" });
71
+ const { registerTools } = await import("../../tools.js");
72
+ registerTools(server);
73
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
74
+ client = new Client({ name: "whatsapp-test-client", version: "1.0.0" });
75
+ await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
76
+ });
77
+ afterEach(async () => {
78
+ await Promise.all([client?.close(), server?.close()]);
79
+ await closeWhatsApp?.();
80
+ closeTestDb();
81
+ });
82
+ it("empty search query is rejected or returns no broad match results", async () => {
83
+ const result = (await client.callTool({
84
+ name: "search_messages",
85
+ arguments: {
86
+ query: "",
87
+ },
88
+ }));
89
+ const payload = parseToolJson(result);
90
+ const isSafeError = result.isError === true;
91
+ const isSafeNoResult = (typeof payload === "string" && payload.includes("No messages found")) ||
92
+ (Array.isArray(payload) && payload.length === 0);
93
+ expect(isSafeError || isSafeNoResult).toBe(true);
94
+ });
95
+ it("invalid JID format returns a clear validation error", async () => {
96
+ const result = (await client.callTool({
97
+ name: "send_message",
98
+ arguments: {
99
+ jid: "not-a-jid",
100
+ text: "hello",
101
+ confirmed: true,
102
+ },
103
+ }));
104
+ const payload = parseToolJson(result);
105
+ expect(result.isError).toBe(true);
106
+ expect(payload).toContain("Invalid phone number or JID");
107
+ });
108
+ it("download_media returns clear error when message has no media", async () => {
109
+ const result = (await client.callTool({
110
+ name: "download_media",
111
+ arguments: {
112
+ jid: "15550001111@s.whatsapp.net",
113
+ messageId: "seed-msg-1",
114
+ },
115
+ }));
116
+ const payload = parseToolJson(result);
117
+ expect(result.isError).toBe(true);
118
+ expect(payload).toContain("has no downloadable media");
119
+ });
120
+ });
121
+ //# sourceMappingURL=edge-cases.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge-cases.test.js","sourceRoot":"","sources":["../../../src/__tests__/failures/edge-cases.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=resource-failures.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-failures.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/failures/resource-failures.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,136 @@
1
+ import { afterEach, beforeEach, 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
+ forbidden: 403,
19
+ connectionLost: 408,
20
+ multideviceMismatch: 411,
21
+ connectionClosed: 428,
22
+ connectionReplaced: 440,
23
+ badSession: 500,
24
+ unavailableService: 503,
25
+ restartRequired: 515,
26
+ },
27
+ fetchLatestBaileysVersion: vi.fn(async () => ({ version: [2, 3000, 0] })),
28
+ downloadMediaMessage: vi.fn(),
29
+ getContentType: vi.fn(),
30
+ initAuthCreds: vi.fn(() => ({})),
31
+ BufferJSON: {
32
+ replacer: (_key, value) => value,
33
+ reviver: (_key, value) => value,
34
+ },
35
+ proto: {
36
+ Message: {
37
+ AppStateSyncKeyData: {
38
+ fromObject: (value) => value,
39
+ },
40
+ },
41
+ },
42
+ }));
43
+ function latestSocket() {
44
+ const socket = mockState.sockets.at(-1);
45
+ if (!socket)
46
+ throw new Error("No fake socket was created");
47
+ return socket;
48
+ }
49
+ function totalListeners(socket) {
50
+ return socket.ev.eventNames().reduce((count, event) => count + socket.ev.listenerCount(event), 0);
51
+ }
52
+ describe("integration failures: resource management", () => {
53
+ const originalMinInterval = process.env.MIN_SEND_INTERVAL_MS;
54
+ const originalJitter = process.env.SEND_JITTER_MS;
55
+ let server;
56
+ let client;
57
+ let whatsapp;
58
+ beforeEach(async () => {
59
+ vi.resetModules();
60
+ vi.useFakeTimers();
61
+ mockState.sockets.length = 0;
62
+ process.env.MIN_SEND_INTERVAL_MS = "3000";
63
+ process.env.SEND_JITTER_MS = "0";
64
+ await setupTestDb();
65
+ seedTestDb();
66
+ whatsapp = await import("../../whatsapp.js");
67
+ await whatsapp.initWhatsApp();
68
+ latestSocket().emitConnectionOpen();
69
+ server = new McpServer({ name: "whatsapp-test", version: "1.0.0" });
70
+ const { registerTools } = await import("../../tools.js");
71
+ registerTools(server);
72
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
73
+ client = new Client({ name: "whatsapp-test-client", version: "1.0.0" });
74
+ await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
75
+ });
76
+ afterEach(async () => {
77
+ await Promise.all([client?.close(), server?.close()]);
78
+ await whatsapp?.closeWhatsApp();
79
+ closeTestDb();
80
+ vi.useRealTimers();
81
+ if (originalMinInterval === undefined)
82
+ delete process.env.MIN_SEND_INTERVAL_MS;
83
+ else
84
+ process.env.MIN_SEND_INTERVAL_MS = originalMinInterval;
85
+ if (originalJitter === undefined)
86
+ delete process.env.SEND_JITTER_MS;
87
+ else
88
+ process.env.SEND_JITTER_MS = originalJitter;
89
+ });
90
+ it("enforces minimum interval between rapid send_message calls", async () => {
91
+ const first = client.callTool({
92
+ name: "send_message",
93
+ arguments: {
94
+ jid: "15550001111@s.whatsapp.net",
95
+ text: "first",
96
+ confirmed: true,
97
+ },
98
+ });
99
+ await vi.advanceTimersByTimeAsync(0);
100
+ await first;
101
+ const second = client.callTool({
102
+ name: "send_message",
103
+ arguments: {
104
+ jid: "15550001111@s.whatsapp.net",
105
+ text: "second",
106
+ confirmed: true,
107
+ },
108
+ });
109
+ let settled = false;
110
+ second.then(() => {
111
+ settled = true;
112
+ });
113
+ await vi.advanceTimersByTimeAsync(2_999);
114
+ expect(settled).toBe(false);
115
+ await vi.advanceTimersByTimeAsync(1);
116
+ const result = await second;
117
+ expect(settled).toBe(true);
118
+ expect(result.isError).toBeFalsy();
119
+ });
120
+ it("keeps listener count stable across reconnect cycles", async () => {
121
+ const firstSocket = latestSocket();
122
+ const baselineCount = totalListeners(firstSocket);
123
+ expect(baselineCount).toBeGreaterThan(0);
124
+ const historicalSockets = [firstSocket];
125
+ for (let i = 0; i < 3; i++) {
126
+ await whatsapp.initWhatsApp();
127
+ const newest = latestSocket();
128
+ historicalSockets.push(newest);
129
+ expect(totalListeners(newest)).toBe(baselineCount);
130
+ }
131
+ for (const staleSocket of historicalSockets.slice(0, -1)) {
132
+ expect(totalListeners(staleSocket)).toBe(0);
133
+ }
134
+ });
135
+ });
136
+ //# sourceMappingURL=resource-failures.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-failures.test.js","sourceRoot":"","sources":["../../../src/__tests__/failures/resource-failures.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=security-failures.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-failures.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/failures/security-failures.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-failures.test.js","sourceRoot":"","sources":["../../../src/__tests__/failures/security-failures.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,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,SAAS,EAAE,GAAG;QACd,cAAc,EAAE,GAAG;QACnB,mBAAmB,EAAE,GAAG;QACxB,gBAAgB,EAAE,GAAG;QACrB,kBAAkB,EAAE,GAAG;QACvB,UAAU,EAAE,GAAG;QACf,kBAAkB,EAAE,GAAG;QACvB,eAAe,EAAE,GAAG;KACrB;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,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7D,cAAc,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,OAAY,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,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,WAAW,CAAC,MAAqB;IACxC,OAAO,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;AAC5E,CAAC;AAED,QAAQ,CAAC,2CAA2C,EAAE,GAAG,EAAE;IACzD,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACxD,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IACvD,MAAM,qBAAqB,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC1D,MAAM,qBAAqB,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAE1D,IAAI,SAAiB,CAAC;IACtB,IAAI,MAAc,CAAC;IACnB,IAAI,MAAiB,CAAC;IACtB,IAAI,aAAkC,CAAC;IAEvC,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,EAAE,CAAC,YAAY,EAAE,CAAC;QAClB,SAAS,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAE7B,SAAS,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,0BAA0B,CAAC,CAAC,CAAC;QAC/E,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,SAAS,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,UAAU,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,GAAG,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,GAAG,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,eAAe,GAAG,UAAU,CAAC;QAEzC,MAAM,WAAW,EAAE,CAAC;QACpB,UAAU,EAAE,CAAC;QAEb,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QAC9C,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QACnB,EAAE,CAAC,OAAO,CACR,+KAA+K,CAChL,CAAC,GAAG,CACH,kBAAkB,EAClB,4BAA4B,EAC5B,CAAC,EACD,4BAA4B,EAC5B,YAAY,EACZ,YAAY,EACZ,IAAI,EACJ,UAAU,EACV,CAAC,EACD,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,EAAE,QAAQ,EAAE,wBAAwB,EAAE,EAAE,EAAE,CAAC,EACrF,IAAI,CACL,CAAC;QAEF,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,sBAAsB,CAAC,CAAC;QACrD,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,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,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,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvD,IAAI,kBAAkB,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;;YACrE,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,kBAAkB,CAAC;QACvD,IAAI,eAAe,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;;YACpE,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,eAAe,CAAC;QACtD,IAAI,qBAAqB,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;;YACvE,OAAO,CAAC,GAAG,CAAC,eAAe,GAAG,qBAAqB,CAAC;QACzD,IAAI,qBAAqB,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;;YACvE,OAAO,CAAC,GAAG,CAAC,eAAe,GAAG,qBAAqB,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN,kBAAkB;QAClB,qBAAqB;QACrB,wBAAwB;QACxB,aAAa;QACb,0BAA0B;KAC3B,CAAC,CAAC,oCAAoC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACzD,MAAM,QAAQ,GACZ,OAAO,KAAK,0BAA0B,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAE9F,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC;YACpC,IAAI,EAAE,WAAW;YACjB,SAAS,EAAE;gBACT,GAAG,EAAE,4BAA4B;gBACjC,QAAQ;gBACR,SAAS,EAAE,IAAI;aAChB;SACF,CAAC,CAAkB,CAAC;QAErB,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAChD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAEjC,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC;YACpC,IAAI,EAAE,WAAW;YACjB,SAAS,EAAE;gBACT,GAAG,EAAE,4BAA4B;gBACjC,QAAQ,EAAE,GAAG,QAAQ,OAAO;gBAC5B,SAAS,EAAE,IAAI;aAChB;SACF,CAAC,CAAkB,CAAC;QAErB,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;QACvC,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,GAAG,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;QACvD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAEpC,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC;YACpC,IAAI,EAAE,WAAW;YACjB,SAAS,EAAE;gBACT,GAAG,EAAE,4BAA4B;gBACjC,QAAQ;gBACR,SAAS,EAAE,IAAI;aAChB;SACF,CAAC,CAAkB,CAAC;QAErB,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,OAAO,CAAC,GAAG,CAAC,eAAe,GAAG,+CAA+C,CAAC;QAE9E,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC;YACpC,IAAI,EAAE,uBAAuB;YAC7B,SAAS,EAAE;gBACT,GAAG,EAAE,4BAA4B;gBACjC,SAAS,EAAE,kBAAkB;aAC9B;SACF,CAAC,CAAkB,CAAC;QAErB,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { EventEmitter } from "node:events";
2
+ type ConnectionUpdate = {
3
+ connection: "open" | "close";
4
+ lastDisconnect?: {
5
+ error?: {
6
+ output?: {
7
+ statusCode?: number;
8
+ };
9
+ };
10
+ };
11
+ qr?: string;
12
+ };
13
+ declare class FakeSocketEvents extends EventEmitter {
14
+ process(handler: (events: Record<string, unknown>) => void | Promise<void>): void;
15
+ emitBatch(events: Record<string, unknown>): void;
16
+ }
17
+ export declare class FakeBaileysSocket {
18
+ readonly ev: FakeSocketEvents;
19
+ readonly sentMessages: Array<{
20
+ jid: string;
21
+ content: Record<string, unknown>;
22
+ }>;
23
+ readonly presenceUpdates: Array<{
24
+ presence: string;
25
+ jid?: string;
26
+ }>;
27
+ user: {
28
+ id: string;
29
+ name: string;
30
+ lid: string;
31
+ };
32
+ sendMessage(jid: string, content: Record<string, unknown>): Promise<{
33
+ key: {
34
+ id: string;
35
+ };
36
+ }>;
37
+ sendPresenceUpdate(presence: string, jid?: string): Promise<void>;
38
+ chatModify(): Promise<void>;
39
+ groupMetadata(jid: string): Promise<{
40
+ subject: string;
41
+ }>;
42
+ updateMediaMessage(): Promise<void>;
43
+ end(): void;
44
+ emitConnection(update: ConnectionUpdate): void;
45
+ emitConnectionOpen(): void;
46
+ emitConnectionClose(statusCode?: number): void;
47
+ emitMessagesUpsert(messages: unknown[]): void;
48
+ emitCredsUpdate(payload?: Record<string, unknown>): void;
49
+ }
50
+ export declare function createFakeBaileysSocket(): FakeBaileysSocket;
51
+ export {};
52
+ //# sourceMappingURL=fake-baileys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-baileys.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/fake-baileys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,KAAK,gBAAgB,GAAG;IACtB,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,cAAc,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE;gBAAE,UAAU,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,CAAA;KAAE,CAAC;IAClE,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,cAAM,gBAAiB,SAAQ,YAAY;IACzC,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAIjF,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAGjD;AAED,qBAAa,iBAAiB;IAC5B,QAAQ,CAAC,EAAE,mBAA0B;IACrC,QAAQ,CAAC,YAAY,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAM;IACrF,QAAQ,CAAC,eAAe,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAM;IAEzE,IAAI;;;;MAIF;IAEI,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IAK5F,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAIxD,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzC,GAAG,IAAI,IAAI;IAIX,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAI9C,kBAAkB,IAAI,IAAI;IAI1B,mBAAmB,CAAC,UAAU,SAAM,GAAG,IAAI;IAO3C,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI;IAI7C,eAAe,CAAC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;CAG7D;AAED,wBAAgB,uBAAuB,IAAI,iBAAiB,CAE3D"}
@@ -0,0 +1,60 @@
1
+ import { EventEmitter } from "node:events";
2
+ class FakeSocketEvents extends EventEmitter {
3
+ process(handler) {
4
+ this.on("event", handler);
5
+ }
6
+ emitBatch(events) {
7
+ this.emit("event", events);
8
+ }
9
+ }
10
+ export class FakeBaileysSocket {
11
+ ev = new FakeSocketEvents();
12
+ sentMessages = [];
13
+ presenceUpdates = [];
14
+ user = {
15
+ id: "15559990000@s.whatsapp.net",
16
+ name: "Test User",
17
+ lid: "15559990000@lid",
18
+ };
19
+ async sendMessage(jid, content) {
20
+ this.sentMessages.push({ jid, content });
21
+ return { key: { id: `fake-msg-${this.sentMessages.length}` } };
22
+ }
23
+ async sendPresenceUpdate(presence, jid) {
24
+ this.presenceUpdates.push({ presence, jid });
25
+ }
26
+ async chatModify() {
27
+ return undefined;
28
+ }
29
+ async groupMetadata(jid) {
30
+ return { subject: `Group ${jid}` };
31
+ }
32
+ async updateMediaMessage() {
33
+ return undefined;
34
+ }
35
+ end() {
36
+ this.ev.removeAllListeners();
37
+ }
38
+ emitConnection(update) {
39
+ this.ev.emitBatch({ "connection.update": update });
40
+ }
41
+ emitConnectionOpen() {
42
+ this.emitConnection({ connection: "open" });
43
+ }
44
+ emitConnectionClose(statusCode = 500) {
45
+ this.emitConnection({
46
+ connection: "close",
47
+ lastDisconnect: { error: { output: { statusCode } } },
48
+ });
49
+ }
50
+ emitMessagesUpsert(messages) {
51
+ this.ev.emitBatch({ "messages.upsert": { messages, type: "notify" } });
52
+ }
53
+ emitCredsUpdate(payload = {}) {
54
+ this.ev.emit("creds.update", payload);
55
+ }
56
+ }
57
+ export function createFakeBaileysSocket() {
58
+ return new FakeBaileysSocket();
59
+ }
60
+ //# sourceMappingURL=fake-baileys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-baileys.js","sourceRoot":"","sources":["../../../src/__tests__/helpers/fake-baileys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQ3C,MAAM,gBAAiB,SAAQ,YAAY;IACzC,OAAO,CAAC,OAAkE;QACxE,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5B,CAAC;IAED,SAAS,CAAC,MAA+B;QACvC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,OAAO,iBAAiB;IACnB,EAAE,GAAG,IAAI,gBAAgB,EAAE,CAAC;IAC5B,YAAY,GAA6D,EAAE,CAAC;IAC5E,eAAe,GAA8C,EAAE,CAAC;IAEzE,IAAI,GAAG;QACL,EAAE,EAAE,4BAA4B;QAChC,IAAI,EAAE,WAAW;QACjB,GAAG,EAAE,iBAAiB;KACvB,CAAC;IAEF,KAAK,CAAC,WAAW,CAAC,GAAW,EAAE,OAAgC;QAC7D,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;QACzC,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,YAAY,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,QAAgB,EAAE,GAAY;QACrD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,GAAW;QAC7B,OAAO,EAAE,OAAO,EAAE,SAAS,GAAG,EAAE,EAAE,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,GAAG;QACD,IAAI,CAAC,EAAE,CAAC,kBAAkB,EAAE,CAAC;IAC/B,CAAC;IAED,cAAc,CAAC,MAAwB;QACrC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,mBAAmB,EAAE,MAAM,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,kBAAkB;QAChB,IAAI,CAAC,cAAc,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,mBAAmB,CAAC,UAAU,GAAG,GAAG;QAClC,IAAI,CAAC,cAAc,CAAC;YAClB,UAAU,EAAE,OAAO;YACnB,cAAc,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;SACtD,CAAC,CAAC;IACL,CAAC;IAED,kBAAkB,CAAC,QAAmB;QACpC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,iBAAiB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,eAAe,CAAC,UAAmC,EAAE;QACnD,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;CACF;AAED,MAAM,UAAU,uBAAuB;IACrC,OAAO,IAAI,iBAAiB,EAAE,CAAC;AACjC,CAAC"}
@@ -0,0 +1,9 @@
1
+ type JsonLike = Record<string, unknown> | unknown[] | string | number | boolean | null;
2
+ export type McpTestClient = {
3
+ listTools: () => Promise<string[]>;
4
+ callTool: (name: string, args?: Record<string, unknown>) => Promise<JsonLike>;
5
+ close: () => Promise<void>;
6
+ };
7
+ export declare function createMcpTestClient(): Promise<McpTestClient>;
8
+ export {};
9
+ //# sourceMappingURL=mcp-test-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-test-client.d.ts","sourceRoot":"","sources":["../../../src/__tests__/helpers/mcp-test-client.ts"],"names":[],"mappings":"AAIA,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAEvF,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACnC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9E,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAmBF,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC,CA2BlE"}