@openclaw/crabline 0.1.12 → 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 +38 -11
- package/dist/src/cli/program.js +17 -2
- package/dist/src/cli/program.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/openclaw/artifact-generation.d.ts +5 -9
- package/dist/src/openclaw/artifact-generation.js +41 -69
- 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 +1 -1
- package/dist/src/openclaw/bridges/matrix.js.map +1 -1
- package/dist/src/openclaw/bridges/mattermost.js +1 -1
- package/dist/src/openclaw/bridges/mattermost.js.map +1 -1
- package/dist/src/openclaw/bridges/signal.js +1 -1
- package/dist/src/openclaw/bridges/signal.js.map +1 -1
- package/dist/src/openclaw/bridges/slack.js +1 -1
- package/dist/src/openclaw/bridges/slack.js.map +1 -1
- package/dist/src/openclaw/bridges/telegram.js +1 -1
- package/dist/src/openclaw/bridges/telegram.js.map +1 -1
- package/dist/src/openclaw/bridges/whatsapp.js +1 -1
- package/dist/src/openclaw/bridges/whatsapp.js.map +1 -1
- package/dist/src/openclaw/bridges/zalo.js +1 -1
- 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/{smoke-lock.d.ts → provider-readiness-lock.d.ts} +7 -7
- package/dist/src/openclaw/{smoke-lock.js → provider-readiness-lock.js} +122 -260
- package/dist/src/openclaw/provider-readiness-lock.js.map +1 -0
- package/dist/src/openclaw/shared.d.ts +9 -17
- package/dist/src/openclaw/shared.js +5 -6
- package/dist/src/openclaw/shared.js.map +1 -1
- package/dist/src/openclaw.d.ts +3 -5
- package/dist/src/openclaw.js +22 -20
- package/dist/src/openclaw.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/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/slack.js +11 -3
- package/dist/src/servers/slack.js.map +1 -1
- package/dist/src/servers/telegram.js +51 -2
- package/dist/src/servers/telegram.js.map +1 -1
- package/dist/src/servers/whatsapp.d.ts +0 -1
- package/dist/src/servers/whatsapp.js +0 -1
- package/dist/src/servers/whatsapp.js.map +1 -1
- package/docs/channel-setup.md +66 -21
- package/package.json +1 -1
- package/dist/src/openclaw/smoke-lock.js.map +0 -1
|
@@ -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 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 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 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 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"]}
|
package/docs/channel-setup.md
CHANGED
|
@@ -4,7 +4,7 @@ Crabline is a local mock service for OpenClaw channel contracts. It has two
|
|
|
4
4
|
surfaces:
|
|
5
5
|
|
|
6
6
|
- fixture-level local mocks used directly by the Crabline CLI
|
|
7
|
-
- local provider servers that OpenClaw
|
|
7
|
+
- local provider servers that real OpenClaw channel plugins can target
|
|
8
8
|
|
|
9
9
|
Live channel testing belongs in OpenClaw's live channel adapters. Crabline
|
|
10
10
|
belongs in deterministic smoke CI and local QA where the test needs
|
|
@@ -224,9 +224,9 @@ watch commands are terminated when cancellation fires.
|
|
|
224
224
|
|
|
225
225
|
## Local Provider Servers
|
|
226
226
|
|
|
227
|
-
Server-backed channels currently include Mattermost, Matrix, Signal,
|
|
228
|
-
Telegram, WhatsApp, and Zalo. Loopback binds retain stable local
|
|
229
|
-
|
|
227
|
+
Server-backed channels currently include Discord, Mattermost, Matrix, Signal,
|
|
228
|
+
Slack, Telegram, WhatsApp, and Zalo. Loopback binds retain stable local
|
|
229
|
+
credentials for deterministic tests. Non-loopback binds generate fresh provider-shaped
|
|
230
230
|
credentials unless the corresponding credential is supplied.
|
|
231
231
|
WhatsApp is loopback-only because its HTTP and WebSocket endpoints carry bearer
|
|
232
232
|
credentials over cleartext and the built-in server does not terminate TLS.
|
|
@@ -264,6 +264,53 @@ to be private. Exclude ready files from version control and CI artifact
|
|
|
264
264
|
collection, and delete them after use. On non-POSIX or shared filesystems,
|
|
265
265
|
verify the effective ACLs before publishing one.
|
|
266
266
|
|
|
267
|
+
### Discord
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
crabline --json serve discord --ready-file .crabline/discord-server.json
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
The ready manifest exposes `applicationId`, `botUserId`, `botToken`,
|
|
274
|
+
`endpoints.apiRoot`, `endpoints.gatewayBotUrl`, `endpoints.gatewayUrl`,
|
|
275
|
+
`endpoints.adminInboundUrl`, `adminToken`, and `recorderPath`. OpenClaw-specific
|
|
276
|
+
endpoint injection and target translation belong to the Crabline OpenClaw
|
|
277
|
+
bridge and the OpenClaw Discord plugin; the provider server itself implements
|
|
278
|
+
Discord's public protocol subset and contains no OpenClaw behavior.
|
|
279
|
+
|
|
280
|
+
Post an inbound user message to `endpoints.adminInboundUrl` with the manifest's
|
|
281
|
+
admin token:
|
|
282
|
+
|
|
283
|
+
```json
|
|
284
|
+
{
|
|
285
|
+
"channelId": "135000000000000010",
|
|
286
|
+
"guildId": "135000000000000011",
|
|
287
|
+
"senderId": "135000000000000012",
|
|
288
|
+
"senderName": "Alice",
|
|
289
|
+
"content": "hello"
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
The control plane creates provider state and emits a normal Discord
|
|
294
|
+
`MESSAGE_CREATE` dispatch on an identified Gateway session. `parentChannelId`
|
|
295
|
+
turns `channelId` into a public thread channel. Supported client boundaries are
|
|
296
|
+
REST v10 bot/application identity, Gateway metadata, guild/channel/member
|
|
297
|
+
lookups, DM creation, text message create/read/reply, typing, application
|
|
298
|
+
command registration, and a v10 JSON Gateway with HELLO, IDENTIFY, READY,
|
|
299
|
+
heartbeat acknowledgement, resume, and deterministic shutdown.
|
|
300
|
+
|
|
301
|
+
Current fidelity limits are one Gateway shard, no transport compression, and no
|
|
302
|
+
missed-dispatch replay: resume succeeds only from the retained session's latest
|
|
303
|
+
sequence. The server also omits voice, interaction dispatch,
|
|
304
|
+
attachment/multipart upload, and Discord's distributed permission or
|
|
305
|
+
bucket-allocation systems.
|
|
306
|
+
The server still returns provider-native authentication, JSON error, and basic
|
|
307
|
+
rate-limit headers for its supported routes.
|
|
308
|
+
|
|
309
|
+
This is not the fixture-level Discord local mock. The fixture adapter's
|
|
310
|
+
interactions webhook remains available to Crabline fixture commands; the
|
|
311
|
+
Discord provider server exists so the real OpenClaw Discord plugin can use
|
|
312
|
+
normal REST and Gateway transports without contacting Discord.
|
|
313
|
+
|
|
267
314
|
### Mattermost
|
|
268
315
|
|
|
269
316
|
Start the server:
|
|
@@ -478,7 +525,6 @@ Manifest fields:
|
|
|
478
525
|
- `endpoints.adminInboundUrl`: authenticated admin ingress for test user
|
|
479
526
|
messages using the WhatsApp Business webhook payload shape
|
|
480
527
|
- `endpoints.messagesUrl`: provider-native Cloud API message and status endpoint
|
|
481
|
-
- `endpoints.statusUrl`: alias for the same provider-native status endpoint
|
|
482
528
|
- `recorderPath`: JSONL provider traffic recorder for HTTP traffic and Baileys
|
|
483
529
|
WebSocket stanzas. Multi-message webhook deliveries use one versioned batch
|
|
484
530
|
line that Crabline's recorder APIs flatten into individual events.
|
|
@@ -511,8 +557,8 @@ The admin ingress accepts JSON like:
|
|
|
511
557
|
}
|
|
512
558
|
```
|
|
513
559
|
|
|
514
|
-
Outbound text sends and composing presence are recorded through the
|
|
515
|
-
provider messages and presence endpoints.
|
|
560
|
+
Outbound text sends and composing presence are recorded through the local
|
|
561
|
+
provider server's messages and presence endpoints.
|
|
516
562
|
|
|
517
563
|
### Zalo Server
|
|
518
564
|
|
|
@@ -639,7 +685,7 @@ chat IDs must be negative. Zero is invalid for every Telegram target kind.
|
|
|
639
685
|
|
|
640
686
|
## Smoke CI Guidance
|
|
641
687
|
|
|
642
|
-
For deterministic CI, use Crabline
|
|
688
|
+
For deterministic CI, use the Crabline channel driver:
|
|
643
689
|
|
|
644
690
|
```yaml
|
|
645
691
|
profile: smoke-ci
|
|
@@ -663,8 +709,8 @@ roundtrip. Real OpenClaw channel proof comes from QA scenarios that launch the
|
|
|
663
709
|
gateway and run its normal channel adapter against the local provider.
|
|
664
710
|
|
|
665
711
|
Crabline stages the manifest, capability report, and provider-readiness report
|
|
666
|
-
inside one owner-only generation directory under the
|
|
667
|
-
`.crabline-
|
|
712
|
+
inside one owner-only generation directory under the
|
|
713
|
+
`.crabline-channel-driver-artifacts/` store name, atomically installs the complete
|
|
668
714
|
directory, and then atomically switches the single `current.json` pointer.
|
|
669
715
|
Readers therefore see either the prior complete generation or the next complete
|
|
670
716
|
generation, never per-file mixtures. Setup, probe, cleanup, staging, or
|
|
@@ -687,17 +733,16 @@ contain `capabilityReport` and `providerReadiness` payloads while their manifest
|
|
|
687
733
|
capability, and provider-readiness paths identify the authoritative immutable
|
|
688
734
|
generation.
|
|
689
735
|
|
|
690
|
-
Lock owners
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
and are reclaimed only after their recorded process exits.
|
|
736
|
+
Lock owners use one versioned format containing the PID, process-start identity,
|
|
737
|
+
and token-specific lease. Both the acquisition reservation and owner claim renew
|
|
738
|
+
their 10-minute leases while the readiness run remains active, so a live run
|
|
739
|
+
retains exclusive ownership beyond the initial lease. A heartbeat failure or
|
|
740
|
+
lost ownership aborts publication before the generation is committed. Recovery
|
|
741
|
+
first atomically moves a stale reservation into a uniquely named recovery claim,
|
|
742
|
+
then revalidates its token-specific lease before deletion; a renewal that wins
|
|
743
|
+
the rename race is restored rather than reclaimed. The lease also bounds stale
|
|
744
|
+
locks when an unrelated live process has inherited the abandoned PID. Malformed
|
|
745
|
+
or unversioned owner records fail closed and are not migrated or recovered.
|
|
701
746
|
|
|
702
747
|
For release or live verification, use OpenClaw's live driver:
|
|
703
748
|
|