@openclaw/crabline 0.1.11 → 0.1.13
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/README.md +137 -23
- package/dist/src/bin/crabline.js +3 -1
- package/dist/src/bin/crabline.js.map +1 -1
- package/dist/src/cli/program.d.ts +5 -1
- package/dist/src/cli/program.js +281 -52
- package/dist/src/cli/program.js.map +1 -1
- package/dist/src/config/load.js +39 -3
- package/dist/src/config/load.js.map +1 -1
- package/dist/src/config/schema.d.ts +20 -0
- package/dist/src/config/schema.js +163 -35
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/core/errors.d.ts +1 -0
- package/dist/src/core/errors.js +6 -3
- package/dist/src/core/errors.js.map +1 -1
- package/dist/src/core/http-path.d.ts +1 -0
- package/dist/src/core/http-path.js +14 -0
- package/dist/src/core/http-path.js.map +1 -0
- package/dist/src/core/matcher.d.ts +3 -1
- package/dist/src/core/matcher.js +58 -2
- package/dist/src/core/matcher.js.map +1 -1
- package/dist/src/core/nonces.d.ts +2 -0
- package/dist/src/core/nonces.js +11 -1
- package/dist/src/core/nonces.js.map +1 -1
- package/dist/src/core/reporters.d.ts +5 -0
- package/dist/src/core/reporters.js +26 -2
- package/dist/src/core/reporters.js.map +1 -1
- package/dist/src/core/run.d.ts +3 -1
- package/dist/src/core/run.js +178 -66
- package/dist/src/core/run.js.map +1 -1
- package/dist/src/index.d.ts +12 -10
- package/dist/src/index.js +6 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/matrix-ids.d.ts +5 -0
- package/dist/src/matrix-ids.js +83 -0
- package/dist/src/matrix-ids.js.map +1 -0
- package/dist/src/openclaw/artifact-generation.d.ts +7 -6
- package/dist/src/openclaw/artifact-generation.js +385 -41
- package/dist/src/openclaw/artifact-generation.js.map +1 -1
- package/dist/src/openclaw/bridges/discord.d.ts +1 -0
- package/dist/src/openclaw/bridges/discord.js +149 -0
- package/dist/src/openclaw/bridges/discord.js.map +1 -0
- package/dist/src/openclaw/bridges/matrix.js +22 -5
- package/dist/src/openclaw/bridges/matrix.js.map +1 -1
- package/dist/src/openclaw/bridges/mattermost.js +14 -9
- package/dist/src/openclaw/bridges/mattermost.js.map +1 -1
- package/dist/src/openclaw/bridges/probe-response.d.ts +1 -0
- package/dist/src/openclaw/bridges/probe-response.js +5 -0
- package/dist/src/openclaw/bridges/probe-response.js.map +1 -0
- package/dist/src/openclaw/bridges/signal.js +16 -7
- package/dist/src/openclaw/bridges/signal.js.map +1 -1
- package/dist/src/openclaw/bridges/slack.js +117 -24
- package/dist/src/openclaw/bridges/slack.js.map +1 -1
- package/dist/src/openclaw/bridges/telegram.js +46 -20
- package/dist/src/openclaw/bridges/telegram.js.map +1 -1
- package/dist/src/openclaw/bridges/whatsapp.js +33 -17
- package/dist/src/openclaw/bridges/whatsapp.js.map +1 -1
- package/dist/src/openclaw/bridges/zalo.js +9 -4
- package/dist/src/openclaw/bridges/zalo.js.map +1 -1
- package/dist/src/openclaw/outbound-contract.js +3 -0
- package/dist/src/openclaw/outbound-contract.js.map +1 -1
- package/dist/src/openclaw/private-file.d.ts +38 -3
- package/dist/src/openclaw/private-file.js +2008 -87
- package/dist/src/openclaw/private-file.js.map +1 -1
- package/dist/src/openclaw/{smoke-lock.d.ts → provider-readiness-lock.d.ts} +14 -5
- package/dist/src/openclaw/provider-readiness-lock.js +1320 -0
- package/dist/src/openclaw/provider-readiness-lock.js.map +1 -0
- package/dist/src/openclaw/shared.d.ts +10 -17
- package/dist/src/openclaw/shared.js +53 -19
- package/dist/src/openclaw/shared.js.map +1 -1
- package/dist/src/openclaw.d.ts +3 -5
- package/dist/src/openclaw.js +245 -60
- package/dist/src/openclaw.js.map +1 -1
- package/dist/src/platform/process-owned-lock.d.ts +11 -0
- package/dist/src/platform/process-owned-lock.js +1698 -0
- package/dist/src/platform/process-owned-lock.js.map +1 -0
- package/dist/src/platform/recorder-directory.d.ts +1 -0
- package/dist/src/platform/recorder-directory.js +14 -0
- package/dist/src/platform/recorder-directory.js.map +1 -0
- package/dist/src/platform/windows-acl.d.ts +18 -0
- package/dist/src/platform/windows-acl.js +1367 -0
- package/dist/src/platform/windows-acl.js.map +1 -0
- package/dist/src/platform/windows-lock-root.d.ts +13 -0
- package/dist/src/platform/windows-lock-root.js +98 -0
- package/dist/src/platform/windows-lock-root.js.map +1 -0
- package/dist/src/providers/builtin/discord.d.ts +4 -0
- package/dist/src/providers/builtin/discord.js +52 -9
- package/dist/src/providers/builtin/discord.js.map +1 -1
- package/dist/src/providers/builtin/external-webhook-auth.d.ts +1 -0
- package/dist/src/providers/builtin/external-webhook-auth.js +38 -1
- package/dist/src/providers/builtin/external-webhook-auth.js.map +1 -1
- package/dist/src/providers/builtin/feishu.d.ts +1 -0
- package/dist/src/providers/builtin/feishu.js +96 -26
- package/dist/src/providers/builtin/feishu.js.map +1 -1
- package/dist/src/providers/builtin/googlechat.d.ts +1 -0
- package/dist/src/providers/builtin/googlechat.js +95 -26
- package/dist/src/providers/builtin/googlechat.js.map +1 -1
- package/dist/src/providers/builtin/imessage.js +60 -17
- package/dist/src/providers/builtin/imessage.js.map +1 -1
- package/dist/src/providers/builtin/loopback.js +88 -35
- package/dist/src/providers/builtin/loopback.js.map +1 -1
- package/dist/src/providers/builtin/matrix.d.ts +2 -2
- package/dist/src/providers/builtin/matrix.js +78 -21
- package/dist/src/providers/builtin/matrix.js.map +1 -1
- package/dist/src/providers/builtin/mattermost.d.ts +11 -7
- package/dist/src/providers/builtin/mattermost.js +138 -24
- package/dist/src/providers/builtin/mattermost.js.map +1 -1
- package/dist/src/providers/builtin/msteams.d.ts +1 -0
- package/dist/src/providers/builtin/msteams.js +118 -38
- package/dist/src/providers/builtin/msteams.js.map +1 -1
- package/dist/src/providers/builtin/native-local-mock.js +4 -4
- package/dist/src/providers/builtin/native-local-mock.js.map +1 -1
- package/dist/src/providers/builtin/script.js +1057 -146
- package/dist/src/providers/builtin/script.js.map +1 -1
- package/dist/src/providers/builtin/slack.d.ts +8 -1
- package/dist/src/providers/builtin/slack.js +327 -24
- package/dist/src/providers/builtin/slack.js.map +1 -1
- package/dist/src/providers/builtin/telegram.d.ts +1 -1
- package/dist/src/providers/builtin/telegram.js +55 -14
- package/dist/src/providers/builtin/telegram.js.map +1 -1
- package/dist/src/providers/builtin/whatsapp.d.ts +4 -3
- package/dist/src/providers/builtin/whatsapp.js +157 -29
- package/dist/src/providers/builtin/whatsapp.js.map +1 -1
- package/dist/src/providers/builtin/zalo.d.ts +5 -2
- package/dist/src/providers/builtin/zalo.js +31 -7
- package/dist/src/providers/builtin/zalo.js.map +1 -1
- package/dist/src/providers/catalog.d.ts +1 -1
- package/dist/src/providers/catalog.js +1 -1
- package/dist/src/providers/catalog.js.map +1 -1
- package/dist/src/providers/local-mock.d.ts +4 -0
- package/dist/src/providers/local-mock.js +162 -35
- package/dist/src/providers/local-mock.js.map +1 -1
- package/dist/src/providers/native-ids.d.ts +2 -0
- package/dist/src/providers/native-ids.js +3 -0
- package/dist/src/providers/native-ids.js.map +1 -1
- package/dist/src/providers/recorder.d.ts +14 -3
- package/dist/src/providers/recorder.js +521 -41
- package/dist/src/providers/recorder.js.map +1 -1
- package/dist/src/providers/registry.d.ts +1 -0
- package/dist/src/providers/registry.js +65 -20
- package/dist/src/providers/registry.js.map +1 -1
- package/dist/src/providers/signed-jwt.d.ts +6 -1
- package/dist/src/providers/signed-jwt.js +241 -50
- package/dist/src/providers/signed-jwt.js.map +1 -1
- package/dist/src/providers/slack-ids.d.ts +1 -0
- package/dist/src/providers/slack-ids.js +5 -0
- package/dist/src/providers/slack-ids.js.map +1 -1
- package/dist/src/providers/target-normalizers.d.ts +9 -1
- package/dist/src/providers/target-normalizers.js +177 -58
- package/dist/src/providers/target-normalizers.js.map +1 -1
- package/dist/src/providers/webhook-server.d.ts +3 -0
- package/dist/src/providers/webhook-server.js +268 -47
- package/dist/src/providers/webhook-server.js.map +1 -1
- package/dist/src/servers/discord.d.ts +40 -0
- package/dist/src/servers/discord.js +842 -0
- package/dist/src/servers/discord.js.map +1 -0
- package/dist/src/servers/http.d.ts +14 -2
- package/dist/src/servers/http.js +229 -58
- package/dist/src/servers/http.js.map +1 -1
- package/dist/src/servers/index.d.ts +10 -4
- package/dist/src/servers/index.js +4 -0
- package/dist/src/servers/index.js.map +1 -1
- package/dist/src/servers/matrix.d.ts +3 -0
- package/dist/src/servers/matrix.js +268 -110
- package/dist/src/servers/matrix.js.map +1 -1
- package/dist/src/servers/mattermost.d.ts +5 -0
- package/dist/src/servers/mattermost.js +389 -91
- package/dist/src/servers/mattermost.js.map +1 -1
- package/dist/src/servers/recorder.d.ts +11 -0
- package/dist/src/servers/recorder.js +1072 -69
- package/dist/src/servers/recorder.js.map +1 -1
- package/dist/src/servers/signal.d.ts +1 -0
- package/dist/src/servers/signal.js +279 -44
- package/dist/src/servers/signal.js.map +1 -1
- package/dist/src/servers/slack.d.ts +15 -0
- package/dist/src/servers/slack.js +270 -54
- package/dist/src/servers/slack.js.map +1 -1
- package/dist/src/servers/telegram-identity.d.ts +6 -0
- package/dist/src/servers/telegram-identity.js +27 -0
- package/dist/src/servers/telegram-identity.js.map +1 -0
- package/dist/src/servers/telegram.d.ts +17 -6
- package/dist/src/servers/telegram.js +1218 -107
- package/dist/src/servers/telegram.js.map +1 -1
- package/dist/src/servers/webhook-target.d.ts +12 -4
- package/dist/src/servers/webhook-target.js +226 -28
- package/dist/src/servers/webhook-target.js.map +1 -1
- package/dist/src/servers/whatsapp-baileys-websocket.d.ts +60 -1
- package/dist/src/servers/whatsapp-baileys-websocket.js +782 -112
- package/dist/src/servers/whatsapp-baileys-websocket.js.map +1 -1
- package/dist/src/servers/whatsapp-jid.d.ts +1 -0
- package/dist/src/servers/whatsapp-jid.js +9 -5
- package/dist/src/servers/whatsapp-jid.js.map +1 -1
- package/dist/src/servers/whatsapp-wire/binary-node.d.ts +1 -0
- package/dist/src/servers/whatsapp-wire/binary-node.js +37 -13
- package/dist/src/servers/whatsapp-wire/binary-node.js.map +1 -1
- package/dist/src/servers/whatsapp-wire/crypto.d.ts +3 -0
- package/dist/src/servers/whatsapp-wire/crypto.js +23 -8
- package/dist/src/servers/whatsapp-wire/crypto.js.map +1 -1
- package/dist/src/servers/whatsapp-wire/handshake.d.ts +9 -3
- package/dist/src/servers/whatsapp-wire/handshake.js +173 -12
- package/dist/src/servers/whatsapp-wire/handshake.js.map +1 -1
- package/dist/src/servers/whatsapp-wire/signal.js +3 -3
- package/dist/src/servers/whatsapp-wire/signal.js.map +1 -1
- package/dist/src/servers/whatsapp.d.ts +7 -1
- package/dist/src/servers/whatsapp.js +149 -25
- package/dist/src/servers/whatsapp.js.map +1 -1
- package/dist/src/servers/zalo.d.ts +1 -0
- package/dist/src/servers/zalo.js +193 -82
- package/dist/src/servers/zalo.js.map +1 -1
- package/docs/channel-setup.md +251 -64
- package/fixtures/examples/crabline.example.yaml +3 -2
- package/package.json +18 -10
- package/dist/src/openclaw/smoke-lock.js +0 -1004
- package/dist/src/openclaw/smoke-lock.js.map +0 -1
- package/fixtures/examples/openclaw-bridge.yaml +0 -125
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { adminAuthError, drainRequestBody, hasAdminToken, InvalidJsonBodyError, isJsonObject, isLoopbackHost, jsonResponse, parseUnknownRequestBody, queryRecord, readTrimmedString, RequestBodyTooLargeError, startHttpJsonServer, } from "./http.js";
|
|
4
|
-
import { recordServerEvent } from "./recorder.js";
|
|
3
|
+
import { adminAuthError, constantTimeTokenEqual, drainRequestBody, hasAdminToken, InvalidJsonBodyError, isJsonObject, isLoopbackHost, jsonResponse, parseUnknownRequestBody, queryRecord, readTrimmedString, RequestBodyTooLargeError, startHttpJsonServer, } from "./http.js";
|
|
4
|
+
import { recordServerEvent, ServerRecorderCommittedError, } from "./recorder.js";
|
|
5
5
|
import { attachWhatsAppBaileysWebSocketServer, resolveMaxPendingWhatsAppInboundMessages, } from "./whatsapp-baileys-websocket.js";
|
|
6
6
|
import { canonicalizeWhatsAppChatJid, canonicalizeWhatsAppUserCorrelationJid, canonicalizeWhatsAppUserJid, isWhatsAppGroupJid, } from "./whatsapp-jid.js";
|
|
7
7
|
const WHATSAPP_CLOUD_RECIPIENT_RE = /^\d{7,15}$/u;
|
|
8
8
|
const WHATSAPP_GRAPH_VERSION_RE = /^v\d+\.\d+$/u;
|
|
9
|
+
const WHATSAPP_GENERATED_MESSAGE_ID_RE = /^wamid\.FAKE(\d{8,})$/u;
|
|
9
10
|
const DEFAULT_GRAPH_VERSION = "v25.0";
|
|
11
|
+
const MAX_WHATSAPP_READABLE_MESSAGE_IDS = 10_000;
|
|
12
|
+
const MAX_WHATSAPP_RECENT_MESSAGE_IDS = 10_000;
|
|
13
|
+
const MAX_WHATSAPP_MESSAGE_ID_BYTES = 128;
|
|
14
|
+
const MAX_WHATSAPP_TEXT_MESSAGE_CHARACTERS = 4_096;
|
|
15
|
+
function createDefaultAccessToken() {
|
|
16
|
+
return `EAA${randomBytes(24).toString("base64url")}`;
|
|
17
|
+
}
|
|
10
18
|
function whatsappOk(value = {}) {
|
|
11
19
|
return jsonResponse({ ok: true, ...value });
|
|
12
20
|
}
|
|
@@ -70,13 +78,67 @@ function requireAuth(request, state) {
|
|
|
70
78
|
return false;
|
|
71
79
|
}
|
|
72
80
|
const match = /^Bearer +(.+)$/iu.exec(authorization.trimStart());
|
|
73
|
-
|
|
81
|
+
const providedToken = match?.[1];
|
|
82
|
+
return providedToken ? constantTimeTokenEqual(providedToken, state.accessToken) : false;
|
|
83
|
+
}
|
|
84
|
+
/** @internal */
|
|
85
|
+
export function isWhatsAppMessageIdInUse(state, id) {
|
|
86
|
+
return (state.inboundMessageIds.has(id) ||
|
|
87
|
+
state.pendingMessageIds.has(id) ||
|
|
88
|
+
state.recentMessageIds.has(id));
|
|
74
89
|
}
|
|
75
|
-
function
|
|
76
|
-
|
|
90
|
+
function reserveMessageId(state, requestedId) {
|
|
91
|
+
let id = requestedId;
|
|
92
|
+
if (id) {
|
|
93
|
+
if (Buffer.byteLength(id, "utf8") > MAX_WHATSAPP_MESSAGE_ID_BYTES) {
|
|
94
|
+
return graphParameterError("(#100) Invalid parameter: messageId", `messageId must not exceed ${MAX_WHATSAPP_MESSAGE_ID_BYTES} UTF-8 bytes.`);
|
|
95
|
+
}
|
|
96
|
+
if (isWhatsAppMessageIdInUse(state, id)) {
|
|
97
|
+
return graphParameterError("(#100) Invalid parameter: messageId", "messageId must be unique within this WhatsApp server.");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
do {
|
|
102
|
+
id = `wamid.FAKE${String(state.nextMessageId++).padStart(8, "0")}`;
|
|
103
|
+
} while (isWhatsAppMessageIdInUse(state, id));
|
|
104
|
+
}
|
|
105
|
+
state.pendingMessageIds.add(id);
|
|
106
|
+
let settled = false;
|
|
107
|
+
return {
|
|
108
|
+
cancel() {
|
|
109
|
+
if (!settled) {
|
|
110
|
+
settled = true;
|
|
111
|
+
state.pendingMessageIds.delete(id);
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
commit() {
|
|
115
|
+
if (settled) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
settled = true;
|
|
119
|
+
state.pendingMessageIds.delete(id);
|
|
120
|
+
state.recentMessageIds.delete(id);
|
|
121
|
+
state.recentMessageIds.set(id, true);
|
|
122
|
+
if (state.recentMessageIds.size > MAX_WHATSAPP_RECENT_MESSAGE_IDS) {
|
|
123
|
+
const oldestId = state.recentMessageIds.keys().next().value;
|
|
124
|
+
if (oldestId !== undefined) {
|
|
125
|
+
state.recentMessageIds.delete(oldestId);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const generatedSequence = WHATSAPP_GENERATED_MESSAGE_ID_RE.exec(id)?.[1];
|
|
129
|
+
if (generatedSequence) {
|
|
130
|
+
const sequence = BigInt(generatedSequence);
|
|
131
|
+
if (sequence >= state.nextMessageId) {
|
|
132
|
+
state.nextMessageId = sequence + 1n;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
id,
|
|
137
|
+
};
|
|
77
138
|
}
|
|
78
139
|
function waIdFromJid(jid) {
|
|
79
|
-
|
|
140
|
+
const correlationJid = canonicalizeWhatsAppUserCorrelationJid(jid);
|
|
141
|
+
return correlationJid?.split("@", 1)[0] ?? jid;
|
|
80
142
|
}
|
|
81
143
|
function directPeerIdentity(jid) {
|
|
82
144
|
return canonicalizeWhatsAppUserCorrelationJid(jid) ?? jid;
|
|
@@ -103,6 +165,9 @@ function readTextMessageBody(body) {
|
|
|
103
165
|
if (text === undefined) {
|
|
104
166
|
return graphParameterError("(#100) Missing required parameter: text.body", "A WhatsApp text send requires text.body.");
|
|
105
167
|
}
|
|
168
|
+
if ([...text].length > MAX_WHATSAPP_TEXT_MESSAGE_CHARACTERS) {
|
|
169
|
+
return graphParameterError("(#100) Invalid parameter: text.body", `text.body must not exceed ${MAX_WHATSAPP_TEXT_MESSAGE_CHARACTERS} characters.`);
|
|
170
|
+
}
|
|
106
171
|
return text;
|
|
107
172
|
}
|
|
108
173
|
function createWhatsAppMessage(params) {
|
|
@@ -139,9 +204,14 @@ function prepareSendMessage(params) {
|
|
|
139
204
|
}
|
|
140
205
|
return {
|
|
141
206
|
commit() {
|
|
207
|
+
const reservation = reserveMessageId(params.state);
|
|
208
|
+
if (reservation instanceof Response) {
|
|
209
|
+
return reservation;
|
|
210
|
+
}
|
|
211
|
+
reservation.commit();
|
|
142
212
|
const message = createWhatsAppMessage({
|
|
143
213
|
fromMe: true,
|
|
144
|
-
id:
|
|
214
|
+
id: reservation.id,
|
|
145
215
|
remoteJid: `${to}@s.whatsapp.net`,
|
|
146
216
|
text,
|
|
147
217
|
});
|
|
@@ -158,7 +228,7 @@ function prepareSendMessage(params) {
|
|
|
158
228
|
},
|
|
159
229
|
};
|
|
160
230
|
}
|
|
161
|
-
function handleMessageStatus(body) {
|
|
231
|
+
function handleMessageStatus(state, body) {
|
|
162
232
|
const productError = requireMessagingProduct(body);
|
|
163
233
|
if (productError) {
|
|
164
234
|
return productError;
|
|
@@ -166,11 +236,25 @@ function handleMessageStatus(body) {
|
|
|
166
236
|
if (readTrimmedString(body.status) !== "read") {
|
|
167
237
|
return graphParameterError("(#100) Invalid parameter: status", 'status must be "read" for message status updates.');
|
|
168
238
|
}
|
|
169
|
-
|
|
239
|
+
const messageId = readTrimmedString(body.message_id);
|
|
240
|
+
if (!messageId) {
|
|
170
241
|
return graphParameterError("(#100) Missing required parameter: message_id", "A message status update requires message_id.");
|
|
171
242
|
}
|
|
243
|
+
if (!state.inboundMessageIds.has(messageId)) {
|
|
244
|
+
return graphParameterError("(#100) Invalid parameter: message_id", "message_id must reference an accepted inbound message.");
|
|
245
|
+
}
|
|
172
246
|
return jsonResponse({ success: true });
|
|
173
247
|
}
|
|
248
|
+
function rememberInboundMessageId(state, messageId) {
|
|
249
|
+
state.inboundMessageIds.delete(messageId);
|
|
250
|
+
state.inboundMessageIds.add(messageId);
|
|
251
|
+
if (state.inboundMessageIds.size > MAX_WHATSAPP_READABLE_MESSAGE_IDS) {
|
|
252
|
+
const oldest = state.inboundMessageIds.values().next().value;
|
|
253
|
+
if (oldest !== undefined) {
|
|
254
|
+
state.inboundMessageIds.delete(oldest);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
174
258
|
async function handleAdminInbound(params) {
|
|
175
259
|
const chatJid = requireWhatsAppChatJid(params.body.chatJid ?? params.body.chatId);
|
|
176
260
|
if (chatJid instanceof Response) {
|
|
@@ -180,6 +264,11 @@ async function handleAdminInbound(params) {
|
|
|
180
264
|
if (senderJid instanceof Response) {
|
|
181
265
|
return { response: senderJid };
|
|
182
266
|
}
|
|
267
|
+
if (directPeerIdentity(senderJid) === directPeerIdentity(params.state.selfJid)) {
|
|
268
|
+
return {
|
|
269
|
+
response: graphParameterError("(#100) Invalid parameter: senderJid", "senderJid must not identify the configured WhatsApp self identity."),
|
|
270
|
+
};
|
|
271
|
+
}
|
|
183
272
|
const isGroupChat = isWhatsAppGroupJid(chatJid);
|
|
184
273
|
if (!isGroupChat && directPeerIdentity(chatJid) !== directPeerIdentity(senderJid)) {
|
|
185
274
|
return {
|
|
@@ -192,11 +281,15 @@ async function handleAdminInbound(params) {
|
|
|
192
281
|
response: graphParameterError("(#100) Missing required parameter: text", "An inbound WhatsApp event requires text."),
|
|
193
282
|
};
|
|
194
283
|
}
|
|
284
|
+
const messageIdReservation = reserveMessageId(params.state, readTrimmedString(params.body.messageId));
|
|
285
|
+
if (messageIdReservation instanceof Response) {
|
|
286
|
+
return { response: messageIdReservation };
|
|
287
|
+
}
|
|
195
288
|
const message = createWhatsAppMessage({
|
|
196
289
|
fromMe: false,
|
|
197
|
-
id:
|
|
290
|
+
id: messageIdReservation.id,
|
|
198
291
|
pushName: readTrimmedString(params.body.pushName) ?? "Test User",
|
|
199
|
-
remoteJid: chatJid,
|
|
292
|
+
remoteJid: isGroupChat ? chatJid : directPeerIdentity(chatJid),
|
|
200
293
|
senderJid: isGroupChat ? senderJid : undefined,
|
|
201
294
|
text,
|
|
202
295
|
});
|
|
@@ -236,7 +329,7 @@ async function handleAdminInbound(params) {
|
|
|
236
329
|
],
|
|
237
330
|
object: "whatsapp_business_account",
|
|
238
331
|
};
|
|
239
|
-
return { message, webhook };
|
|
332
|
+
return { message, messageIdReservation, webhook };
|
|
240
333
|
}
|
|
241
334
|
async function handleRequest(params) {
|
|
242
335
|
const url = new URL(params.request.url ?? "/", "http://127.0.0.1");
|
|
@@ -246,7 +339,7 @@ async function handleRequest(params) {
|
|
|
246
339
|
return new Response("not found", { status: 404 });
|
|
247
340
|
}
|
|
248
341
|
if (!hasAdminToken(params.request, params.state.adminToken)) {
|
|
249
|
-
params.request
|
|
342
|
+
drainRequestBody(params.request);
|
|
250
343
|
return adminAuthError();
|
|
251
344
|
}
|
|
252
345
|
const body = await parseUnknownRequestBody(params.request);
|
|
@@ -269,6 +362,7 @@ async function handleRequest(params) {
|
|
|
269
362
|
? params.state.prepareInboundMessage(result.message)
|
|
270
363
|
: undefined;
|
|
271
364
|
if (result.message && !preparedDelivery) {
|
|
365
|
+
result.messageIdReservation?.cancel();
|
|
272
366
|
return graphError({
|
|
273
367
|
code: 4,
|
|
274
368
|
details: "The pending WhatsApp inbound queue is full.",
|
|
@@ -284,24 +378,50 @@ async function handleRequest(params) {
|
|
|
284
378
|
await appendEvent(params.state, event);
|
|
285
379
|
}
|
|
286
380
|
catch (error) {
|
|
287
|
-
|
|
381
|
+
if (!(error instanceof ServerRecorderCommittedError)) {
|
|
382
|
+
preparedDelivery?.cancel();
|
|
383
|
+
result.messageIdReservation?.cancel();
|
|
384
|
+
throw error;
|
|
385
|
+
}
|
|
386
|
+
result.messageIdReservation?.commit();
|
|
387
|
+
if (result.message && preparedDelivery) {
|
|
388
|
+
try {
|
|
389
|
+
await preparedDelivery.commit();
|
|
390
|
+
rememberInboundMessageId(params.state, result.message.key.id);
|
|
391
|
+
}
|
|
392
|
+
catch (deliveryError) {
|
|
393
|
+
const reconciliationError = new AggregateError([error, deliveryError], "WhatsApp recorder append committed, but inbound delivery reconciliation failed.");
|
|
394
|
+
reconciliationError.cause = deliveryError;
|
|
395
|
+
throw reconciliationError;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
288
398
|
throw error;
|
|
289
399
|
}
|
|
290
400
|
if (result.message && preparedDelivery) {
|
|
291
|
-
|
|
292
|
-
|
|
401
|
+
try {
|
|
402
|
+
const delivery = await preparedDelivery.commit();
|
|
403
|
+
result.messageIdReservation?.commit();
|
|
404
|
+
rememberInboundMessageId(params.state, result.message.key.id);
|
|
405
|
+
return whatsappOk({ delivery, message: result.message, webhook: result.webhook });
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
result.messageIdReservation?.cancel();
|
|
409
|
+
throw error;
|
|
410
|
+
}
|
|
293
411
|
}
|
|
412
|
+
result.messageIdReservation?.cancel();
|
|
294
413
|
return graphParameterError("(#100) Invalid inbound WhatsApp event");
|
|
295
414
|
}
|
|
296
415
|
const phoneNumberPath = `/${params.state.graphVersion}/${params.state.phoneNumberId}`;
|
|
297
416
|
const messagesPath = `${phoneNumberPath}/messages`;
|
|
298
417
|
if (!requireAuth(params.request, params.state)) {
|
|
299
|
-
params.request
|
|
418
|
+
drainRequestBody(params.request);
|
|
300
419
|
return graphAuthError();
|
|
301
420
|
}
|
|
302
421
|
if (url.pathname === phoneNumberPath && params.request.method === "GET") {
|
|
303
422
|
const body = queryRecord(url);
|
|
304
423
|
await appendEvent(params.state, {
|
|
424
|
+
accepted: true,
|
|
305
425
|
at: new Date().toISOString(),
|
|
306
426
|
body,
|
|
307
427
|
method: params.request.method,
|
|
@@ -335,7 +455,8 @@ async function handleRequest(params) {
|
|
|
335
455
|
response = graphParameterError("(#100) Invalid parameter: request body", "The request body must be a JSON object.");
|
|
336
456
|
}
|
|
337
457
|
else if ("status" in body || "message_id" in body) {
|
|
338
|
-
response = handleMessageStatus(body);
|
|
458
|
+
response = handleMessageStatus(params.state, body);
|
|
459
|
+
event.accepted = response.ok;
|
|
339
460
|
}
|
|
340
461
|
else {
|
|
341
462
|
const prepared = prepareSendMessage({ body, state: params.state });
|
|
@@ -347,7 +468,7 @@ async function handleRequest(params) {
|
|
|
347
468
|
}
|
|
348
469
|
response = prepared;
|
|
349
470
|
}
|
|
350
|
-
event.accepted
|
|
471
|
+
event.accepted ??= false;
|
|
351
472
|
await appendEvent(params.state, event);
|
|
352
473
|
return response;
|
|
353
474
|
}
|
|
@@ -356,6 +477,9 @@ async function handleRequest(params) {
|
|
|
356
477
|
}
|
|
357
478
|
export async function startWhatsAppServer(params = {}) {
|
|
358
479
|
const host = params.host ?? "127.0.0.1";
|
|
480
|
+
if (!isLoopbackHost(host)) {
|
|
481
|
+
throw new Error("WhatsApp server requires a loopback host because its HTTP and WebSocket endpoints carry credentials over cleartext.");
|
|
482
|
+
}
|
|
359
483
|
if (params.accessToken !== undefined &&
|
|
360
484
|
(!params.accessToken.trim() || params.accessToken !== params.accessToken.trim())) {
|
|
361
485
|
throw new Error("WhatsApp accessToken must not be empty or whitespace-padded.");
|
|
@@ -378,15 +502,15 @@ export async function startWhatsAppServer(params = {}) {
|
|
|
378
502
|
throw new Error("WhatsApp selfJid must be a WhatsApp user JID.");
|
|
379
503
|
}
|
|
380
504
|
const state = {
|
|
381
|
-
accessToken: params.accessToken ??
|
|
382
|
-
(isLoopbackHost(host)
|
|
383
|
-
? "crabline-whatsapp-access-token"
|
|
384
|
-
: `EAA${randomBytes(24).toString("base64url")}`),
|
|
505
|
+
accessToken: params.accessToken ?? createDefaultAccessToken(),
|
|
385
506
|
adminToken: params.adminToken ?? randomBytes(24).toString("hex"),
|
|
386
507
|
prepareInboundMessage: () => undefined,
|
|
387
508
|
displayPhoneNumber: params.displayPhoneNumber ?? "15550000000",
|
|
388
509
|
graphVersion,
|
|
389
|
-
|
|
510
|
+
inboundMessageIds: new Set(),
|
|
511
|
+
pendingMessageIds: new Set(),
|
|
512
|
+
recentMessageIds: new Map(),
|
|
513
|
+
nextMessageId: 1n,
|
|
390
514
|
onEvent: params.onEvent,
|
|
391
515
|
phoneNumberId,
|
|
392
516
|
recorderPath: params.recorderPath ?? path.resolve(".crabline", "servers", "whatsapp.jsonl"),
|
|
@@ -422,6 +546,7 @@ export async function startWhatsAppServer(params = {}) {
|
|
|
422
546
|
appendEvent: (event) => appendEvent(state, event),
|
|
423
547
|
httpServer: httpServer.server,
|
|
424
548
|
maxPendingInboundMessages,
|
|
549
|
+
messageAcceptanceTimeoutMs: params.messageAcceptanceTimeoutMs,
|
|
425
550
|
path: "/ws/chat",
|
|
426
551
|
selfJid: state.selfJid,
|
|
427
552
|
};
|
|
@@ -465,7 +590,6 @@ export async function startWhatsAppServer(params = {}) {
|
|
|
465
590
|
baileysWebSocketUrl,
|
|
466
591
|
messagesUrl,
|
|
467
592
|
phoneNumberUrl,
|
|
468
|
-
statusUrl: messagesUrl,
|
|
469
593
|
},
|
|
470
594
|
env: {
|
|
471
595
|
CLOUD_API_ACCESS_TOKEN: state.accessToken,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whatsapp.js","sourceRoot":"","sources":["../../../src/servers/whatsapp.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IncomingMessage } from \"node:http\";\nimport { randomBytes } from \"node:crypto\";\nimport path from \"node:path\";\nimport {\n adminAuthError,\n drainRequestBody,\n hasAdminToken,\n InvalidJsonBodyError,\n isJsonObject,\n isLoopbackHost,\n jsonResponse,\n parseUnknownRequestBody,\n queryRecord,\n readTrimmedString,\n RequestBodyTooLargeError,\n startHttpJsonServer,\n type ServerRequestEvent,\n} from \"./http.js\";\nimport { recordServerEvent, type ServerEventObserver } from \"./recorder.js\";\nimport {\n attachWhatsAppBaileysWebSocketServer,\n resolveMaxPendingWhatsAppInboundMessages,\n type PreparedWhatsAppBaileysInboundDelivery,\n type WhatsAppBaileysInboundMessage,\n} from \"./whatsapp-baileys-websocket.js\";\nimport {\n canonicalizeWhatsAppChatJid,\n canonicalizeWhatsAppUserCorrelationJid,\n canonicalizeWhatsAppUserJid,\n isWhatsAppGroupJid,\n} from \"./whatsapp-jid.js\";\n\nconst WHATSAPP_CLOUD_RECIPIENT_RE = /^\\d{7,15}$/u;\nconst WHATSAPP_GRAPH_VERSION_RE = /^v\\d+\\.\\d+$/u;\nconst DEFAULT_GRAPH_VERSION = \"v25.0\";\n\ntype WhatsAppServerState = {\n accessToken: string;\n adminToken: string;\n displayPhoneNumber: string;\n prepareInboundMessage(\n message: WhatsAppBaileysInboundMessage,\n ): PreparedWhatsAppBaileysInboundDelivery | undefined;\n graphVersion: string;\n nextMessageId: number;\n onEvent: ServerEventObserver | undefined;\n phoneNumberId: string;\n recorderPath: string;\n selfJid: string;\n};\n\nexport type WhatsAppBaileysMessage = WhatsAppBaileysInboundMessage;\n\nexport type WhatsAppServerManifest = {\n accessToken: string;\n adminToken: string;\n baseUrl: string;\n endpoints: {\n adminInboundUrl: string;\n apiRoot: string;\n baileysWebSocketUrl: string;\n messagesUrl: string;\n phoneNumberUrl: string;\n statusUrl: string;\n };\n env: {\n CLOUD_API_ACCESS_TOKEN: string;\n CLOUD_API_VERSION: string;\n WA_BASE_URL: string;\n WA_PHONE_NUMBER_ID: string;\n };\n graphVersion: string;\n phoneNumberId: string;\n provider: \"whatsapp\";\n recorderPath: string;\n selfJid: string;\n version: 1;\n};\n\nexport type StartedWhatsAppServer = {\n close(): Promise<void>;\n manifest: WhatsAppServerManifest;\n};\n\nexport type StartWhatsAppServerParams = {\n accessToken?: string | undefined;\n adminToken?: string | undefined;\n displayPhoneNumber?: string | undefined;\n graphVersion?: string | undefined;\n host?: string | undefined;\n maxPendingInboundMessages?: number | undefined;\n onEvent?: ServerEventObserver | undefined;\n phoneNumberId?: string | undefined;\n port?: number | undefined;\n recorderPath?: string | undefined;\n selfJid?: string | undefined;\n};\n\ntype WhatsAppAdminInboundResult = {\n message?: WhatsAppBaileysMessage | undefined;\n response?: Response | undefined;\n webhook?: Record<string, unknown> | undefined;\n};\n\ntype WhatsAppRecorderEvent = ServerRequestEvent & {\n accepted?: boolean | undefined;\n message?: WhatsAppBaileysMessage | undefined;\n};\n\nfunction whatsappOk(value: Record<string, unknown> = {}): Response {\n return jsonResponse({ ok: true, ...value });\n}\n\nfunction graphError(params: {\n code?: number | undefined;\n details?: string | undefined;\n message: string;\n status?: number | undefined;\n type?: string | undefined;\n}): Response {\n return jsonResponse(\n {\n error: {\n code: params.code ?? 100,\n ...(params.details\n ? {\n error_data: {\n details: params.details,\n messaging_product: \"whatsapp\",\n },\n }\n : {}),\n fbtrace_id: \"A1B2C3D4E5F\",\n message: params.message,\n type: params.type ?? \"OAuthException\",\n },\n },\n params.status ?? 400,\n );\n}\n\nfunction graphParameterError(message: string, details?: string): Response {\n return graphError({ code: 100, details, message, status: 400 });\n}\n\nfunction graphAuthError(): Response {\n return graphError({\n code: 190,\n message: \"Invalid OAuth access token.\",\n status: 401,\n });\n}\n\nasync function appendEvent(state: WhatsAppServerState, event: ServerRequestEvent) {\n await recordServerEvent({ event, onEvent: state.onEvent, recorderPath: state.recorderPath });\n}\n\nfunction requireWhatsAppChatJid(value: unknown): string | Response {\n const stringValue = readTrimmedString(value);\n const canonical = stringValue ? canonicalizeWhatsAppChatJid(stringValue) : undefined;\n if (!canonical) {\n return graphParameterError(\n \"(#100) Invalid parameter: chatJid\",\n \"chatJid must be a WhatsApp user or group JID.\",\n );\n }\n return canonical;\n}\n\nfunction requireWhatsAppSenderJid(value: unknown): string | Response {\n const stringValue = readTrimmedString(value);\n const canonical = stringValue ? canonicalizeWhatsAppUserJid(stringValue) : undefined;\n if (!canonical) {\n return graphParameterError(\n \"(#100) Invalid parameter: senderJid\",\n \"senderJid must be a WhatsApp user JID.\",\n );\n }\n return canonical;\n}\n\nfunction requireCloudRecipient(value: unknown): string | Response {\n const recipient = readTrimmedString(value);\n if (!recipient || !WHATSAPP_CLOUD_RECIPIENT_RE.test(recipient)) {\n return graphParameterError(\n \"(#100) Invalid parameter: to\",\n \"to must be a WhatsApp phone number in international format without punctuation.\",\n );\n }\n return recipient;\n}\n\nfunction requireAuth(request: IncomingMessage, state: WhatsAppServerState): boolean {\n const authorization = request.headers.authorization;\n if (typeof authorization !== \"string\") {\n return false;\n }\n const match = /^Bearer +(.+)$/iu.exec(authorization.trimStart());\n return match?.[1] === state.accessToken;\n}\n\nfunction nextMessageId(state: WhatsAppServerState): string {\n return `wamid.FAKE${String(state.nextMessageId++).padStart(8, \"0\")}`;\n}\n\nfunction waIdFromJid(jid: string): string {\n return jid.split(\"@\", 1)[0]?.split(\":\", 1)[0] ?? jid;\n}\n\nfunction directPeerIdentity(jid: string): string {\n return canonicalizeWhatsAppUserCorrelationJid(jid) ?? jid;\n}\n\nfunction requireMessagingProduct(body: Record<string, unknown>): Response | undefined {\n const messagingProduct = readTrimmedString(body.messaging_product);\n if (messagingProduct !== \"whatsapp\") {\n return graphParameterError(\n \"(#100) Invalid parameter: messaging_product\",\n 'messaging_product must be \"whatsapp\".',\n );\n }\n return undefined;\n}\n\nfunction readTextMessageBody(body: Record<string, unknown>): string | Response {\n const type = readTrimmedString(body.type);\n if (!type) {\n return graphParameterError(\n \"(#100) Missing required parameter: type\",\n 'A WhatsApp text send requires type to be \"text\".',\n );\n }\n if (type !== \"text\") {\n return graphParameterError(\n \"(#100) Unsupported message type\",\n \"This test API currently supports WhatsApp text message sends.\",\n );\n }\n const textPayload = body.text;\n const text =\n textPayload && typeof textPayload === \"object\"\n ? readMessageText((textPayload as Record<string, unknown>).body)\n : undefined;\n if (text === undefined) {\n return graphParameterError(\n \"(#100) Missing required parameter: text.body\",\n \"A WhatsApp text send requires text.body.\",\n );\n }\n return text;\n}\n\nfunction createWhatsAppMessage(params: {\n fromMe: boolean;\n id: string;\n pushName?: string | undefined;\n remoteJid: string;\n senderJid?: string | undefined;\n text: string;\n}) {\n return {\n key: {\n fromMe: params.fromMe,\n id: params.id,\n ...(params.senderJid ? { participant: params.senderJid } : {}),\n remoteJid: params.remoteJid,\n },\n message: {\n conversation: params.text,\n },\n messageTimestamp: Math.floor(Date.now() / 1000),\n pushName: params.pushName ?? (params.fromMe ? \"Test Bot\" : \"Test User\"),\n };\n}\n\ntype PreparedWhatsAppSend = {\n commit(): Response;\n};\n\nfunction prepareSendMessage(params: {\n body: Record<string, unknown>;\n state: WhatsAppServerState;\n}): PreparedWhatsAppSend | Response {\n const productError = requireMessagingProduct(params.body);\n if (productError) {\n return productError;\n }\n const recipientType = readTrimmedString(params.body.recipient_type);\n if (recipientType && recipientType !== \"individual\") {\n return graphParameterError(\n \"(#100) Invalid parameter: recipient_type\",\n 'recipient_type must be \"individual\".',\n );\n }\n const to = requireCloudRecipient(params.body.to);\n if (to instanceof Response) {\n return to;\n }\n const text = readTextMessageBody(params.body);\n if (text instanceof Response) {\n return text;\n }\n return {\n commit() {\n const message = createWhatsAppMessage({\n fromMe: true,\n id: nextMessageId(params.state),\n remoteJid: `${to}@s.whatsapp.net`,\n text,\n });\n return jsonResponse({\n contacts: [\n {\n input: to,\n wa_id: to,\n },\n ],\n messages: [{ id: message.key.id }],\n messaging_product: \"whatsapp\",\n });\n },\n };\n}\n\nfunction handleMessageStatus(body: Record<string, unknown>): Response {\n const productError = requireMessagingProduct(body);\n if (productError) {\n return productError;\n }\n if (readTrimmedString(body.status) !== \"read\") {\n return graphParameterError(\n \"(#100) Invalid parameter: status\",\n 'status must be \"read\" for message status updates.',\n );\n }\n if (!readTrimmedString(body.message_id)) {\n return graphParameterError(\n \"(#100) Missing required parameter: message_id\",\n \"A message status update requires message_id.\",\n );\n }\n return jsonResponse({ success: true });\n}\n\nasync function handleAdminInbound(params: {\n body: Record<string, unknown>;\n state: WhatsAppServerState;\n}): Promise<WhatsAppAdminInboundResult> {\n const chatJid = requireWhatsAppChatJid(params.body.chatJid ?? params.body.chatId);\n if (chatJid instanceof Response) {\n return { response: chatJid };\n }\n const senderJid = requireWhatsAppSenderJid(params.body.senderJid ?? params.body.from);\n if (senderJid instanceof Response) {\n return { response: senderJid };\n }\n const isGroupChat = isWhatsAppGroupJid(chatJid);\n if (!isGroupChat && directPeerIdentity(chatJid) !== directPeerIdentity(senderJid)) {\n return {\n response: graphParameterError(\n \"(#100) Invalid parameter: senderJid\",\n \"senderJid must identify the direct chat peer.\",\n ),\n };\n }\n const text = readMessageText(params.body.text);\n if (text === undefined) {\n return {\n response: graphParameterError(\n \"(#100) Missing required parameter: text\",\n \"An inbound WhatsApp event requires text.\",\n ),\n };\n }\n const message = createWhatsAppMessage({\n fromMe: false,\n id: readTrimmedString(params.body.messageId) ?? nextMessageId(params.state),\n pushName: readTrimmedString(params.body.pushName) ?? \"Test User\",\n remoteJid: chatJid,\n senderJid: isGroupChat ? senderJid : undefined,\n text,\n });\n const timestamp = String(message.messageTimestamp);\n const webhook = {\n entry: [\n {\n changes: [\n {\n field: \"messages\",\n value: {\n contacts: [\n {\n profile: { name: readTrimmedString(params.body.pushName) ?? \"Test User\" },\n wa_id: waIdFromJid(senderJid),\n },\n ],\n messages: [\n {\n from: waIdFromJid(senderJid),\n id: message.key.id,\n text: { body: text },\n timestamp,\n type: \"text\",\n },\n ],\n messaging_product: \"whatsapp\",\n metadata: {\n display_phone_number: params.state.displayPhoneNumber,\n phone_number_id: params.state.phoneNumberId,\n },\n },\n },\n ],\n id: \"TEST_WABA\",\n },\n ],\n object: \"whatsapp_business_account\",\n };\n return { message, webhook };\n}\n\nasync function handleRequest(params: { request: IncomingMessage; state: WhatsAppServerState }) {\n const url = new URL(params.request.url ?? \"/\", \"http://127.0.0.1\");\n\n if (url.pathname === \"/_crabline/admin/whatsapp/inbound\") {\n if (params.request.method !== \"POST\") {\n drainRequestBody(params.request);\n return new Response(\"not found\", { status: 404 });\n }\n if (!hasAdminToken(params.request, params.state.adminToken)) {\n params.request.resume();\n return adminAuthError();\n }\n const body = await parseUnknownRequestBody(params.request);\n if (!isJsonObject(body)) {\n return graphParameterError(\n \"(#100) Invalid parameter: request body\",\n \"The request body must be a JSON object.\",\n );\n }\n const result = await handleAdminInbound({ body, state: params.state });\n if (result.response) {\n return result.response;\n }\n const event: WhatsAppRecorderEvent = {\n at: new Date().toISOString(),\n body,\n method: params.request.method,\n path: url.pathname,\n query: queryRecord(url),\n type: \"admin\",\n };\n const preparedDelivery = result.message\n ? params.state.prepareInboundMessage(result.message)\n : undefined;\n if (result.message && !preparedDelivery) {\n return graphError({\n code: 4,\n details: \"The pending WhatsApp inbound queue is full.\",\n message: \"(#4) Application request limit reached.\",\n status: 503,\n type: \"OAuthException\",\n });\n }\n if (result.message) {\n event.message = result.message;\n }\n try {\n await appendEvent(params.state, event);\n } catch (error) {\n preparedDelivery?.cancel();\n throw error;\n }\n if (result.message && preparedDelivery) {\n const delivery = await preparedDelivery.commit();\n return whatsappOk({ delivery, message: result.message, webhook: result.webhook });\n }\n return graphParameterError(\"(#100) Invalid inbound WhatsApp event\");\n }\n\n const phoneNumberPath = `/${params.state.graphVersion}/${params.state.phoneNumberId}`;\n const messagesPath = `${phoneNumberPath}/messages`;\n if (!requireAuth(params.request, params.state)) {\n params.request.resume();\n return graphAuthError();\n }\n if (url.pathname === phoneNumberPath && params.request.method === \"GET\") {\n const body = queryRecord(url);\n await appendEvent(params.state, {\n at: new Date().toISOString(),\n body,\n method: params.request.method,\n path: url.pathname,\n query: body,\n type: \"api\",\n });\n return jsonResponse({\n display_phone_number: params.state.displayPhoneNumber,\n id: params.state.phoneNumberId,\n quality_rating: \"GREEN\",\n verified_name: \"Crabline Test Bot\",\n });\n }\n if (url.pathname === messagesPath) {\n if (params.request.method !== \"POST\") {\n drainRequestBody(params.request);\n return new Response(\"not found\", { status: 404 });\n }\n const body = await parseUnknownRequestBody(params.request);\n const event: WhatsAppRecorderEvent = {\n at: new Date().toISOString(),\n body,\n method: params.request.method,\n path: url.pathname,\n query: queryRecord(url),\n type: \"api\",\n };\n let response: Response;\n if (!isJsonObject(body)) {\n response = graphParameterError(\n \"(#100) Invalid parameter: request body\",\n \"The request body must be a JSON object.\",\n );\n } else if (\"status\" in body || \"message_id\" in body) {\n response = handleMessageStatus(body);\n } else {\n const prepared = prepareSendMessage({ body, state: params.state });\n if (!(prepared instanceof Response)) {\n response = prepared.commit();\n event.accepted = true;\n await appendEvent(params.state, event);\n return response;\n }\n response = prepared;\n }\n event.accepted = false;\n await appendEvent(params.state, event);\n return response;\n }\n drainRequestBody(params.request);\n return new Response(\"not found\", { status: 404 });\n}\n\nexport async function startWhatsAppServer(\n params: StartWhatsAppServerParams = {},\n): Promise<StartedWhatsAppServer> {\n const host = params.host ?? \"127.0.0.1\";\n if (\n params.accessToken !== undefined &&\n (!params.accessToken.trim() || params.accessToken !== params.accessToken.trim())\n ) {\n throw new Error(\"WhatsApp accessToken must not be empty or whitespace-padded.\");\n }\n if (\n params.adminToken !== undefined &&\n (!params.adminToken.trim() || params.adminToken !== params.adminToken.trim())\n ) {\n throw new Error(\"WhatsApp adminToken must not be empty or whitespace-padded.\");\n }\n const graphVersion = params.graphVersion ?? DEFAULT_GRAPH_VERSION;\n if (!WHATSAPP_GRAPH_VERSION_RE.test(graphVersion)) {\n throw new Error(`Invalid WhatsApp Graph API version: ${graphVersion}.`);\n }\n const phoneNumberId = params.phoneNumberId ?? \"100000000000000\";\n if (!/^\\d+$/u.test(phoneNumberId)) {\n throw new Error(\"WhatsApp phoneNumberId must contain only digits.\");\n }\n const maxPendingInboundMessages = resolveMaxPendingWhatsAppInboundMessages(\n params.maxPendingInboundMessages,\n );\n const selfJid = canonicalizeWhatsAppUserJid(params.selfJid ?? \"15550000000@s.whatsapp.net\");\n if (!selfJid) {\n throw new Error(\"WhatsApp selfJid must be a WhatsApp user JID.\");\n }\n const state: WhatsAppServerState = {\n accessToken:\n params.accessToken ??\n (isLoopbackHost(host)\n ? \"crabline-whatsapp-access-token\"\n : `EAA${randomBytes(24).toString(\"base64url\")}`),\n adminToken: params.adminToken ?? randomBytes(24).toString(\"hex\"),\n prepareInboundMessage: () => undefined,\n displayPhoneNumber: params.displayPhoneNumber ?? \"15550000000\",\n graphVersion,\n nextMessageId: 1,\n onEvent: params.onEvent,\n phoneNumberId,\n recorderPath: params.recorderPath ?? path.resolve(\".crabline\", \"servers\", \"whatsapp.jsonl\"),\n selfJid,\n };\n const httpServer = await startHttpJsonServer({\n handle: (request) => handleRequest({ request, state }),\n handleError: (error) => {\n if (error instanceof InvalidJsonBodyError) {\n return graphParameterError(\n \"(#100) Invalid parameter: request body\",\n \"The request body must be valid JSON.\",\n );\n }\n if (error instanceof RequestBodyTooLargeError) {\n return graphError({\n code: 100,\n details: \"The request body exceeds the supported size limit.\",\n message: \"(#100) Request body is too large.\",\n status: 413,\n });\n }\n return undefined;\n },\n host,\n port: params.port ?? 0,\n serverName: \"WhatsApp\",\n });\n const baseUrl = httpServer.baseUrl;\n const apiRoot = `${baseUrl}/${state.graphVersion}`;\n const phoneNumberUrl = `${apiRoot}/${state.phoneNumberId}`;\n const messagesUrl = `${phoneNumberUrl}/messages`;\n const baileysWebSocketUrl = `${baseUrl.replace(\n /^http/u,\n \"ws\",\n )}/ws/chat?access_token=${encodeURIComponent(state.accessToken)}`;\n const baileysWebSocketOptions = {\n accessToken: state.accessToken,\n appendEvent: (event: ServerRequestEvent) => appendEvent(state, event),\n httpServer: httpServer.server,\n maxPendingInboundMessages,\n path: \"/ws/chat\",\n selfJid: state.selfJid,\n };\n let baileysWebSocketServer;\n try {\n baileysWebSocketServer = attachWhatsAppBaileysWebSocketServer(baileysWebSocketOptions);\n } catch (error) {\n try {\n await httpServer.close();\n } catch (closeError) {\n const aggregateError = new AggregateError(\n [error, closeError],\n \"WhatsApp WebSocket startup failed and HTTP rollback also failed.\",\n );\n aggregateError.cause = error;\n throw aggregateError;\n }\n throw error;\n }\n state.prepareInboundMessage = (message) => baileysWebSocketServer.prepareInboundMessage(message);\n return {\n async close() {\n const results = await Promise.allSettled([\n baileysWebSocketServer.close(),\n httpServer.close(),\n ]);\n const errors = results.flatMap((result) =>\n result.status === \"rejected\" ? [result.reason] : [],\n );\n if (errors.length === 1) {\n throw errors[0];\n }\n if (errors.length > 1) {\n throw new AggregateError(errors, \"WhatsApp server shutdown failed.\");\n }\n },\n manifest: {\n accessToken: state.accessToken,\n adminToken: state.adminToken,\n baseUrl,\n endpoints: {\n adminInboundUrl: `${baseUrl}/_crabline/admin/whatsapp/inbound`,\n apiRoot,\n baileysWebSocketUrl,\n messagesUrl,\n phoneNumberUrl,\n statusUrl: messagesUrl,\n },\n env: {\n CLOUD_API_ACCESS_TOKEN: state.accessToken,\n CLOUD_API_VERSION: state.graphVersion,\n WA_BASE_URL: baseUrl,\n WA_PHONE_NUMBER_ID: state.phoneNumberId,\n },\n graphVersion: state.graphVersion,\n phoneNumberId: state.phoneNumberId,\n provider: \"whatsapp\",\n recorderPath: state.recorderPath,\n selfJid: state.selfJid,\n version: 1,\n },\n };\n}\n\nfunction readMessageText(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value : undefined;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"whatsapp.js","sourceRoot":"","sources":["../../../src/servers/whatsapp.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IncomingMessage } from \"node:http\";\nimport { randomBytes } from \"node:crypto\";\nimport path from \"node:path\";\nimport {\n adminAuthError,\n constantTimeTokenEqual,\n drainRequestBody,\n hasAdminToken,\n InvalidJsonBodyError,\n isJsonObject,\n isLoopbackHost,\n jsonResponse,\n parseUnknownRequestBody,\n queryRecord,\n readTrimmedString,\n RequestBodyTooLargeError,\n startHttpJsonServer,\n type ServerRequestEvent,\n} from \"./http.js\";\nimport {\n recordServerEvent,\n ServerRecorderCommittedError,\n type ServerEventObserver,\n} from \"./recorder.js\";\nimport {\n attachWhatsAppBaileysWebSocketServer,\n resolveMaxPendingWhatsAppInboundMessages,\n type PreparedWhatsAppBaileysInboundDelivery,\n type WhatsAppBaileysInboundMessage,\n} from \"./whatsapp-baileys-websocket.js\";\nimport {\n canonicalizeWhatsAppChatJid,\n canonicalizeWhatsAppUserCorrelationJid,\n canonicalizeWhatsAppUserJid,\n isWhatsAppGroupJid,\n} from \"./whatsapp-jid.js\";\n\nconst WHATSAPP_CLOUD_RECIPIENT_RE = /^\\d{7,15}$/u;\nconst WHATSAPP_GRAPH_VERSION_RE = /^v\\d+\\.\\d+$/u;\nconst WHATSAPP_GENERATED_MESSAGE_ID_RE = /^wamid\\.FAKE(\\d{8,})$/u;\nconst DEFAULT_GRAPH_VERSION = \"v25.0\";\nconst MAX_WHATSAPP_READABLE_MESSAGE_IDS = 10_000;\nconst MAX_WHATSAPP_RECENT_MESSAGE_IDS = 10_000;\nconst MAX_WHATSAPP_MESSAGE_ID_BYTES = 128;\nconst MAX_WHATSAPP_TEXT_MESSAGE_CHARACTERS = 4_096;\n\nfunction createDefaultAccessToken(): string {\n return `EAA${randomBytes(24).toString(\"base64url\")}`;\n}\n\ntype WhatsAppServerState = {\n accessToken: string;\n adminToken: string;\n displayPhoneNumber: string;\n prepareInboundMessage(\n message: WhatsAppBaileysInboundMessage,\n ): PreparedWhatsAppBaileysInboundDelivery | undefined;\n graphVersion: string;\n inboundMessageIds: Set<string>;\n pendingMessageIds: Set<string>;\n recentMessageIds: Map<string, true>;\n nextMessageId: bigint;\n onEvent: ServerEventObserver | undefined;\n phoneNumberId: string;\n recorderPath: string;\n selfJid: string;\n};\n\nexport type WhatsAppBaileysMessage = WhatsAppBaileysInboundMessage;\n\nexport type WhatsAppServerManifest = {\n accessToken: string;\n adminToken: string;\n baseUrl: string;\n endpoints: {\n adminInboundUrl: string;\n apiRoot: string;\n baileysWebSocketUrl: string;\n messagesUrl: string;\n phoneNumberUrl: string;\n };\n env: {\n CLOUD_API_ACCESS_TOKEN: string;\n CLOUD_API_VERSION: string;\n WA_BASE_URL: string;\n WA_PHONE_NUMBER_ID: string;\n };\n graphVersion: string;\n phoneNumberId: string;\n provider: \"whatsapp\";\n recorderPath: string;\n selfJid: string;\n version: 1;\n};\n\nexport type StartedWhatsAppServer = {\n close(): Promise<void>;\n manifest: WhatsAppServerManifest;\n};\n\nexport type StartWhatsAppServerParams = {\n accessToken?: string | undefined;\n adminToken?: string | undefined;\n displayPhoneNumber?: string | undefined;\n graphVersion?: string | undefined;\n host?: string | undefined;\n maxPendingInboundMessages?: number | undefined;\n messageAcceptanceTimeoutMs?: number | undefined;\n onEvent?: ServerEventObserver | undefined;\n phoneNumberId?: string | undefined;\n port?: number | undefined;\n recorderPath?: string | undefined;\n selfJid?: string | undefined;\n};\n\ntype WhatsAppAdminInboundResult = {\n message?: WhatsAppBaileysMessage | undefined;\n messageIdReservation?: WhatsAppMessageIdReservation | undefined;\n response?: Response | undefined;\n webhook?: Record<string, unknown> | undefined;\n};\n\ntype WhatsAppRecorderEvent = ServerRequestEvent & {\n accepted?: boolean | undefined;\n message?: WhatsAppBaileysMessage | undefined;\n};\n\nfunction whatsappOk(value: Record<string, unknown> = {}): Response {\n return jsonResponse({ ok: true, ...value });\n}\n\nfunction graphError(params: {\n code?: number | undefined;\n details?: string | undefined;\n message: string;\n status?: number | undefined;\n type?: string | undefined;\n}): Response {\n return jsonResponse(\n {\n error: {\n code: params.code ?? 100,\n ...(params.details\n ? {\n error_data: {\n details: params.details,\n messaging_product: \"whatsapp\",\n },\n }\n : {}),\n fbtrace_id: \"A1B2C3D4E5F\",\n message: params.message,\n type: params.type ?? \"OAuthException\",\n },\n },\n params.status ?? 400,\n );\n}\n\nfunction graphParameterError(message: string, details?: string): Response {\n return graphError({ code: 100, details, message, status: 400 });\n}\n\nfunction graphAuthError(): Response {\n return graphError({\n code: 190,\n message: \"Invalid OAuth access token.\",\n status: 401,\n });\n}\n\nasync function appendEvent(state: WhatsAppServerState, event: WhatsAppRecorderEvent) {\n await recordServerEvent({ event, onEvent: state.onEvent, recorderPath: state.recorderPath });\n}\n\nfunction requireWhatsAppChatJid(value: unknown): string | Response {\n const stringValue = readTrimmedString(value);\n const canonical = stringValue ? canonicalizeWhatsAppChatJid(stringValue) : undefined;\n if (!canonical) {\n return graphParameterError(\n \"(#100) Invalid parameter: chatJid\",\n \"chatJid must be a WhatsApp user or group JID.\",\n );\n }\n return canonical;\n}\n\nfunction requireWhatsAppSenderJid(value: unknown): string | Response {\n const stringValue = readTrimmedString(value);\n const canonical = stringValue ? canonicalizeWhatsAppUserJid(stringValue) : undefined;\n if (!canonical) {\n return graphParameterError(\n \"(#100) Invalid parameter: senderJid\",\n \"senderJid must be a WhatsApp user JID.\",\n );\n }\n return canonical;\n}\n\nfunction requireCloudRecipient(value: unknown): string | Response {\n const recipient = readTrimmedString(value);\n if (!recipient || !WHATSAPP_CLOUD_RECIPIENT_RE.test(recipient)) {\n return graphParameterError(\n \"(#100) Invalid parameter: to\",\n \"to must be a WhatsApp phone number in international format without punctuation.\",\n );\n }\n return recipient;\n}\n\nfunction requireAuth(request: IncomingMessage, state: WhatsAppServerState): boolean {\n const authorization = request.headers.authorization;\n if (typeof authorization !== \"string\") {\n return false;\n }\n const match = /^Bearer +(.+)$/iu.exec(authorization.trimStart());\n const providedToken = match?.[1];\n return providedToken ? constantTimeTokenEqual(providedToken, state.accessToken) : false;\n}\n\ntype WhatsAppMessageIdReservation = {\n cancel(): void;\n commit(): void;\n id: string;\n};\n\n/** @internal */\nexport function isWhatsAppMessageIdInUse(\n state: {\n inboundMessageIds: ReadonlySet<string>;\n pendingMessageIds: ReadonlySet<string>;\n recentMessageIds: ReadonlyMap<string, true>;\n },\n id: string,\n): boolean {\n return (\n state.inboundMessageIds.has(id) ||\n state.pendingMessageIds.has(id) ||\n state.recentMessageIds.has(id)\n );\n}\n\nfunction reserveMessageId(\n state: WhatsAppServerState,\n requestedId?: string,\n): WhatsAppMessageIdReservation | Response {\n let id = requestedId;\n if (id) {\n if (Buffer.byteLength(id, \"utf8\") > MAX_WHATSAPP_MESSAGE_ID_BYTES) {\n return graphParameterError(\n \"(#100) Invalid parameter: messageId\",\n `messageId must not exceed ${MAX_WHATSAPP_MESSAGE_ID_BYTES} UTF-8 bytes.`,\n );\n }\n if (isWhatsAppMessageIdInUse(state, id)) {\n return graphParameterError(\n \"(#100) Invalid parameter: messageId\",\n \"messageId must be unique within this WhatsApp server.\",\n );\n }\n } else {\n do {\n id = `wamid.FAKE${String(state.nextMessageId++).padStart(8, \"0\")}`;\n } while (isWhatsAppMessageIdInUse(state, id));\n }\n state.pendingMessageIds.add(id);\n let settled = false;\n return {\n cancel() {\n if (!settled) {\n settled = true;\n state.pendingMessageIds.delete(id);\n }\n },\n commit() {\n if (settled) {\n return;\n }\n settled = true;\n state.pendingMessageIds.delete(id);\n state.recentMessageIds.delete(id);\n state.recentMessageIds.set(id, true);\n if (state.recentMessageIds.size > MAX_WHATSAPP_RECENT_MESSAGE_IDS) {\n const oldestId = state.recentMessageIds.keys().next().value;\n if (oldestId !== undefined) {\n state.recentMessageIds.delete(oldestId);\n }\n }\n const generatedSequence = WHATSAPP_GENERATED_MESSAGE_ID_RE.exec(id)?.[1];\n if (generatedSequence) {\n const sequence = BigInt(generatedSequence);\n if (sequence >= state.nextMessageId) {\n state.nextMessageId = sequence + 1n;\n }\n }\n },\n id,\n };\n}\n\nfunction waIdFromJid(jid: string): string {\n const correlationJid = canonicalizeWhatsAppUserCorrelationJid(jid);\n return correlationJid?.split(\"@\", 1)[0] ?? jid;\n}\n\nfunction directPeerIdentity(jid: string): string {\n return canonicalizeWhatsAppUserCorrelationJid(jid) ?? jid;\n}\n\nfunction requireMessagingProduct(body: Record<string, unknown>): Response | undefined {\n const messagingProduct = readTrimmedString(body.messaging_product);\n if (messagingProduct !== \"whatsapp\") {\n return graphParameterError(\n \"(#100) Invalid parameter: messaging_product\",\n 'messaging_product must be \"whatsapp\".',\n );\n }\n return undefined;\n}\n\nfunction readTextMessageBody(body: Record<string, unknown>): string | Response {\n const type = readTrimmedString(body.type);\n if (!type) {\n return graphParameterError(\n \"(#100) Missing required parameter: type\",\n 'A WhatsApp text send requires type to be \"text\".',\n );\n }\n if (type !== \"text\") {\n return graphParameterError(\n \"(#100) Unsupported message type\",\n \"This test API currently supports WhatsApp text message sends.\",\n );\n }\n const textPayload = body.text;\n const text =\n textPayload && typeof textPayload === \"object\"\n ? readMessageText((textPayload as Record<string, unknown>).body)\n : undefined;\n if (text === undefined) {\n return graphParameterError(\n \"(#100) Missing required parameter: text.body\",\n \"A WhatsApp text send requires text.body.\",\n );\n }\n if ([...text].length > MAX_WHATSAPP_TEXT_MESSAGE_CHARACTERS) {\n return graphParameterError(\n \"(#100) Invalid parameter: text.body\",\n `text.body must not exceed ${MAX_WHATSAPP_TEXT_MESSAGE_CHARACTERS} characters.`,\n );\n }\n return text;\n}\n\nfunction createWhatsAppMessage(params: {\n fromMe: boolean;\n id: string;\n pushName?: string | undefined;\n remoteJid: string;\n senderJid?: string | undefined;\n text: string;\n}) {\n return {\n key: {\n fromMe: params.fromMe,\n id: params.id,\n ...(params.senderJid ? { participant: params.senderJid } : {}),\n remoteJid: params.remoteJid,\n },\n message: {\n conversation: params.text,\n },\n messageTimestamp: Math.floor(Date.now() / 1000),\n pushName: params.pushName ?? (params.fromMe ? \"Test Bot\" : \"Test User\"),\n };\n}\n\ntype PreparedWhatsAppSend = {\n commit(): Response;\n};\n\nfunction prepareSendMessage(params: {\n body: Record<string, unknown>;\n state: WhatsAppServerState;\n}): PreparedWhatsAppSend | Response {\n const productError = requireMessagingProduct(params.body);\n if (productError) {\n return productError;\n }\n const recipientType = readTrimmedString(params.body.recipient_type);\n if (recipientType && recipientType !== \"individual\") {\n return graphParameterError(\n \"(#100) Invalid parameter: recipient_type\",\n 'recipient_type must be \"individual\".',\n );\n }\n const to = requireCloudRecipient(params.body.to);\n if (to instanceof Response) {\n return to;\n }\n const text = readTextMessageBody(params.body);\n if (text instanceof Response) {\n return text;\n }\n return {\n commit() {\n const reservation = reserveMessageId(params.state);\n if (reservation instanceof Response) {\n return reservation;\n }\n reservation.commit();\n const message = createWhatsAppMessage({\n fromMe: true,\n id: reservation.id,\n remoteJid: `${to}@s.whatsapp.net`,\n text,\n });\n return jsonResponse({\n contacts: [\n {\n input: to,\n wa_id: to,\n },\n ],\n messages: [{ id: message.key.id }],\n messaging_product: \"whatsapp\",\n });\n },\n };\n}\n\nfunction handleMessageStatus(state: WhatsAppServerState, body: Record<string, unknown>): Response {\n const productError = requireMessagingProduct(body);\n if (productError) {\n return productError;\n }\n if (readTrimmedString(body.status) !== \"read\") {\n return graphParameterError(\n \"(#100) Invalid parameter: status\",\n 'status must be \"read\" for message status updates.',\n );\n }\n const messageId = readTrimmedString(body.message_id);\n if (!messageId) {\n return graphParameterError(\n \"(#100) Missing required parameter: message_id\",\n \"A message status update requires message_id.\",\n );\n }\n if (!state.inboundMessageIds.has(messageId)) {\n return graphParameterError(\n \"(#100) Invalid parameter: message_id\",\n \"message_id must reference an accepted inbound message.\",\n );\n }\n return jsonResponse({ success: true });\n}\n\nfunction rememberInboundMessageId(state: WhatsAppServerState, messageId: string): void {\n state.inboundMessageIds.delete(messageId);\n state.inboundMessageIds.add(messageId);\n if (state.inboundMessageIds.size > MAX_WHATSAPP_READABLE_MESSAGE_IDS) {\n const oldest = state.inboundMessageIds.values().next().value;\n if (oldest !== undefined) {\n state.inboundMessageIds.delete(oldest);\n }\n }\n}\n\nasync function handleAdminInbound(params: {\n body: Record<string, unknown>;\n state: WhatsAppServerState;\n}): Promise<WhatsAppAdminInboundResult> {\n const chatJid = requireWhatsAppChatJid(params.body.chatJid ?? params.body.chatId);\n if (chatJid instanceof Response) {\n return { response: chatJid };\n }\n const senderJid = requireWhatsAppSenderJid(params.body.senderJid ?? params.body.from);\n if (senderJid instanceof Response) {\n return { response: senderJid };\n }\n if (directPeerIdentity(senderJid) === directPeerIdentity(params.state.selfJid)) {\n return {\n response: graphParameterError(\n \"(#100) Invalid parameter: senderJid\",\n \"senderJid must not identify the configured WhatsApp self identity.\",\n ),\n };\n }\n const isGroupChat = isWhatsAppGroupJid(chatJid);\n if (!isGroupChat && directPeerIdentity(chatJid) !== directPeerIdentity(senderJid)) {\n return {\n response: graphParameterError(\n \"(#100) Invalid parameter: senderJid\",\n \"senderJid must identify the direct chat peer.\",\n ),\n };\n }\n const text = readMessageText(params.body.text);\n if (text === undefined) {\n return {\n response: graphParameterError(\n \"(#100) Missing required parameter: text\",\n \"An inbound WhatsApp event requires text.\",\n ),\n };\n }\n const messageIdReservation = reserveMessageId(\n params.state,\n readTrimmedString(params.body.messageId),\n );\n if (messageIdReservation instanceof Response) {\n return { response: messageIdReservation };\n }\n const message = createWhatsAppMessage({\n fromMe: false,\n id: messageIdReservation.id,\n pushName: readTrimmedString(params.body.pushName) ?? \"Test User\",\n remoteJid: isGroupChat ? chatJid : directPeerIdentity(chatJid),\n senderJid: isGroupChat ? senderJid : undefined,\n text,\n });\n const timestamp = String(message.messageTimestamp);\n const webhook = {\n entry: [\n {\n changes: [\n {\n field: \"messages\",\n value: {\n contacts: [\n {\n profile: { name: readTrimmedString(params.body.pushName) ?? \"Test User\" },\n wa_id: waIdFromJid(senderJid),\n },\n ],\n messages: [\n {\n from: waIdFromJid(senderJid),\n id: message.key.id,\n text: { body: text },\n timestamp,\n type: \"text\",\n },\n ],\n messaging_product: \"whatsapp\",\n metadata: {\n display_phone_number: params.state.displayPhoneNumber,\n phone_number_id: params.state.phoneNumberId,\n },\n },\n },\n ],\n id: \"TEST_WABA\",\n },\n ],\n object: \"whatsapp_business_account\",\n };\n return { message, messageIdReservation, webhook };\n}\n\nasync function handleRequest(params: { request: IncomingMessage; state: WhatsAppServerState }) {\n const url = new URL(params.request.url ?? \"/\", \"http://127.0.0.1\");\n\n if (url.pathname === \"/_crabline/admin/whatsapp/inbound\") {\n if (params.request.method !== \"POST\") {\n drainRequestBody(params.request);\n return new Response(\"not found\", { status: 404 });\n }\n if (!hasAdminToken(params.request, params.state.adminToken)) {\n drainRequestBody(params.request);\n return adminAuthError();\n }\n const body = await parseUnknownRequestBody(params.request);\n if (!isJsonObject(body)) {\n return graphParameterError(\n \"(#100) Invalid parameter: request body\",\n \"The request body must be a JSON object.\",\n );\n }\n const result = await handleAdminInbound({ body, state: params.state });\n if (result.response) {\n return result.response;\n }\n const event: WhatsAppRecorderEvent = {\n at: new Date().toISOString(),\n body,\n method: params.request.method,\n path: url.pathname,\n query: queryRecord(url),\n type: \"admin\",\n };\n const preparedDelivery = result.message\n ? params.state.prepareInboundMessage(result.message)\n : undefined;\n if (result.message && !preparedDelivery) {\n result.messageIdReservation?.cancel();\n return graphError({\n code: 4,\n details: \"The pending WhatsApp inbound queue is full.\",\n message: \"(#4) Application request limit reached.\",\n status: 503,\n type: \"OAuthException\",\n });\n }\n if (result.message) {\n event.message = result.message;\n }\n try {\n await appendEvent(params.state, event);\n } catch (error) {\n if (!(error instanceof ServerRecorderCommittedError)) {\n preparedDelivery?.cancel();\n result.messageIdReservation?.cancel();\n throw error;\n }\n result.messageIdReservation?.commit();\n if (result.message && preparedDelivery) {\n try {\n await preparedDelivery.commit();\n rememberInboundMessageId(params.state, result.message.key.id);\n } catch (deliveryError) {\n const reconciliationError = new AggregateError(\n [error, deliveryError],\n \"WhatsApp recorder append committed, but inbound delivery reconciliation failed.\",\n );\n reconciliationError.cause = deliveryError;\n throw reconciliationError;\n }\n }\n throw error;\n }\n if (result.message && preparedDelivery) {\n try {\n const delivery = await preparedDelivery.commit();\n result.messageIdReservation?.commit();\n rememberInboundMessageId(params.state, result.message.key.id);\n return whatsappOk({ delivery, message: result.message, webhook: result.webhook });\n } catch (error) {\n result.messageIdReservation?.cancel();\n throw error;\n }\n }\n result.messageIdReservation?.cancel();\n return graphParameterError(\"(#100) Invalid inbound WhatsApp event\");\n }\n\n const phoneNumberPath = `/${params.state.graphVersion}/${params.state.phoneNumberId}`;\n const messagesPath = `${phoneNumberPath}/messages`;\n if (!requireAuth(params.request, params.state)) {\n drainRequestBody(params.request);\n return graphAuthError();\n }\n if (url.pathname === phoneNumberPath && params.request.method === \"GET\") {\n const body = queryRecord(url);\n await appendEvent(params.state, {\n accepted: true,\n at: new Date().toISOString(),\n body,\n method: params.request.method,\n path: url.pathname,\n query: body,\n type: \"api\",\n });\n return jsonResponse({\n display_phone_number: params.state.displayPhoneNumber,\n id: params.state.phoneNumberId,\n quality_rating: \"GREEN\",\n verified_name: \"Crabline Test Bot\",\n });\n }\n if (url.pathname === messagesPath) {\n if (params.request.method !== \"POST\") {\n drainRequestBody(params.request);\n return new Response(\"not found\", { status: 404 });\n }\n const body = await parseUnknownRequestBody(params.request);\n const event: WhatsAppRecorderEvent = {\n at: new Date().toISOString(),\n body,\n method: params.request.method,\n path: url.pathname,\n query: queryRecord(url),\n type: \"api\",\n };\n let response: Response;\n if (!isJsonObject(body)) {\n response = graphParameterError(\n \"(#100) Invalid parameter: request body\",\n \"The request body must be a JSON object.\",\n );\n } else if (\"status\" in body || \"message_id\" in body) {\n response = handleMessageStatus(params.state, body);\n event.accepted = response.ok;\n } else {\n const prepared = prepareSendMessage({ body, state: params.state });\n if (!(prepared instanceof Response)) {\n response = prepared.commit();\n event.accepted = true;\n await appendEvent(params.state, event);\n return response;\n }\n response = prepared;\n }\n event.accepted ??= false;\n await appendEvent(params.state, event);\n return response;\n }\n drainRequestBody(params.request);\n return new Response(\"not found\", { status: 404 });\n}\n\nexport async function startWhatsAppServer(\n params: StartWhatsAppServerParams = {},\n): Promise<StartedWhatsAppServer> {\n const host = params.host ?? \"127.0.0.1\";\n if (!isLoopbackHost(host)) {\n throw new Error(\n \"WhatsApp server requires a loopback host because its HTTP and WebSocket endpoints carry credentials over cleartext.\",\n );\n }\n if (\n params.accessToken !== undefined &&\n (!params.accessToken.trim() || params.accessToken !== params.accessToken.trim())\n ) {\n throw new Error(\"WhatsApp accessToken must not be empty or whitespace-padded.\");\n }\n if (\n params.adminToken !== undefined &&\n (!params.adminToken.trim() || params.adminToken !== params.adminToken.trim())\n ) {\n throw new Error(\"WhatsApp adminToken must not be empty or whitespace-padded.\");\n }\n const graphVersion = params.graphVersion ?? DEFAULT_GRAPH_VERSION;\n if (!WHATSAPP_GRAPH_VERSION_RE.test(graphVersion)) {\n throw new Error(`Invalid WhatsApp Graph API version: ${graphVersion}.`);\n }\n const phoneNumberId = params.phoneNumberId ?? \"100000000000000\";\n if (!/^\\d+$/u.test(phoneNumberId)) {\n throw new Error(\"WhatsApp phoneNumberId must contain only digits.\");\n }\n const maxPendingInboundMessages = resolveMaxPendingWhatsAppInboundMessages(\n params.maxPendingInboundMessages,\n );\n const selfJid = canonicalizeWhatsAppUserJid(params.selfJid ?? \"15550000000@s.whatsapp.net\");\n if (!selfJid) {\n throw new Error(\"WhatsApp selfJid must be a WhatsApp user JID.\");\n }\n const state: WhatsAppServerState = {\n accessToken: params.accessToken ?? createDefaultAccessToken(),\n adminToken: params.adminToken ?? randomBytes(24).toString(\"hex\"),\n prepareInboundMessage: () => undefined,\n displayPhoneNumber: params.displayPhoneNumber ?? \"15550000000\",\n graphVersion,\n inboundMessageIds: new Set(),\n pendingMessageIds: new Set(),\n recentMessageIds: new Map(),\n nextMessageId: 1n,\n onEvent: params.onEvent,\n phoneNumberId,\n recorderPath: params.recorderPath ?? path.resolve(\".crabline\", \"servers\", \"whatsapp.jsonl\"),\n selfJid,\n };\n const httpServer = await startHttpJsonServer({\n handle: (request) => handleRequest({ request, state }),\n handleError: (error) => {\n if (error instanceof InvalidJsonBodyError) {\n return graphParameterError(\n \"(#100) Invalid parameter: request body\",\n \"The request body must be valid JSON.\",\n );\n }\n if (error instanceof RequestBodyTooLargeError) {\n return graphError({\n code: 100,\n details: \"The request body exceeds the supported size limit.\",\n message: \"(#100) Request body is too large.\",\n status: 413,\n });\n }\n return undefined;\n },\n host,\n port: params.port ?? 0,\n serverName: \"WhatsApp\",\n });\n const baseUrl = httpServer.baseUrl;\n const apiRoot = `${baseUrl}/${state.graphVersion}`;\n const phoneNumberUrl = `${apiRoot}/${state.phoneNumberId}`;\n const messagesUrl = `${phoneNumberUrl}/messages`;\n const baileysWebSocketUrl = `${baseUrl.replace(\n /^http/u,\n \"ws\",\n )}/ws/chat?access_token=${encodeURIComponent(state.accessToken)}`;\n const baileysWebSocketOptions = {\n accessToken: state.accessToken,\n appendEvent: (event: ServerRequestEvent) => appendEvent(state, event),\n httpServer: httpServer.server,\n maxPendingInboundMessages,\n messageAcceptanceTimeoutMs: params.messageAcceptanceTimeoutMs,\n path: \"/ws/chat\",\n selfJid: state.selfJid,\n };\n let baileysWebSocketServer;\n try {\n baileysWebSocketServer = attachWhatsAppBaileysWebSocketServer(baileysWebSocketOptions);\n } catch (error) {\n try {\n await httpServer.close();\n } catch (closeError) {\n const aggregateError = new AggregateError(\n [error, closeError],\n \"WhatsApp WebSocket startup failed and HTTP rollback also failed.\",\n );\n aggregateError.cause = error;\n throw aggregateError;\n }\n throw error;\n }\n state.prepareInboundMessage = (message) => baileysWebSocketServer.prepareInboundMessage(message);\n return {\n async close() {\n const results = await Promise.allSettled([\n baileysWebSocketServer.close(),\n httpServer.close(),\n ]);\n const errors = results.flatMap((result) =>\n result.status === \"rejected\" ? [result.reason] : [],\n );\n if (errors.length === 1) {\n throw errors[0];\n }\n if (errors.length > 1) {\n throw new AggregateError(errors, \"WhatsApp server shutdown failed.\");\n }\n },\n manifest: {\n accessToken: state.accessToken,\n adminToken: state.adminToken,\n baseUrl,\n endpoints: {\n adminInboundUrl: `${baseUrl}/_crabline/admin/whatsapp/inbound`,\n apiRoot,\n baileysWebSocketUrl,\n messagesUrl,\n phoneNumberUrl,\n },\n env: {\n CLOUD_API_ACCESS_TOKEN: state.accessToken,\n CLOUD_API_VERSION: state.graphVersion,\n WA_BASE_URL: baseUrl,\n WA_PHONE_NUMBER_ID: state.phoneNumberId,\n },\n graphVersion: state.graphVersion,\n phoneNumberId: state.phoneNumberId,\n provider: \"whatsapp\",\n recorderPath: state.recorderPath,\n selfJid: state.selfJid,\n version: 1,\n },\n };\n}\n\nfunction readMessageText(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value : undefined;\n}\n"]}
|
|
@@ -31,6 +31,7 @@ export type StartZaloServerParams = {
|
|
|
31
31
|
onEvent?: ServerEventObserver | undefined;
|
|
32
32
|
port?: number | undefined;
|
|
33
33
|
recorderPath?: string | undefined;
|
|
34
|
+
maxPendingInboundBytes?: number | undefined;
|
|
34
35
|
maxPendingInboundEvents?: number | undefined;
|
|
35
36
|
webhookDeliveryTimeoutMs?: number | undefined;
|
|
36
37
|
};
|