@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.
Files changed (214) hide show
  1. package/README.md +137 -23
  2. package/dist/src/bin/crabline.js +3 -1
  3. package/dist/src/bin/crabline.js.map +1 -1
  4. package/dist/src/cli/program.d.ts +5 -1
  5. package/dist/src/cli/program.js +281 -52
  6. package/dist/src/cli/program.js.map +1 -1
  7. package/dist/src/config/load.js +39 -3
  8. package/dist/src/config/load.js.map +1 -1
  9. package/dist/src/config/schema.d.ts +20 -0
  10. package/dist/src/config/schema.js +163 -35
  11. package/dist/src/config/schema.js.map +1 -1
  12. package/dist/src/core/errors.d.ts +1 -0
  13. package/dist/src/core/errors.js +6 -3
  14. package/dist/src/core/errors.js.map +1 -1
  15. package/dist/src/core/http-path.d.ts +1 -0
  16. package/dist/src/core/http-path.js +14 -0
  17. package/dist/src/core/http-path.js.map +1 -0
  18. package/dist/src/core/matcher.d.ts +3 -1
  19. package/dist/src/core/matcher.js +58 -2
  20. package/dist/src/core/matcher.js.map +1 -1
  21. package/dist/src/core/nonces.d.ts +2 -0
  22. package/dist/src/core/nonces.js +11 -1
  23. package/dist/src/core/nonces.js.map +1 -1
  24. package/dist/src/core/reporters.d.ts +5 -0
  25. package/dist/src/core/reporters.js +26 -2
  26. package/dist/src/core/reporters.js.map +1 -1
  27. package/dist/src/core/run.d.ts +3 -1
  28. package/dist/src/core/run.js +178 -66
  29. package/dist/src/core/run.js.map +1 -1
  30. package/dist/src/index.d.ts +12 -10
  31. package/dist/src/index.js +6 -5
  32. package/dist/src/index.js.map +1 -1
  33. package/dist/src/matrix-ids.d.ts +5 -0
  34. package/dist/src/matrix-ids.js +83 -0
  35. package/dist/src/matrix-ids.js.map +1 -0
  36. package/dist/src/openclaw/artifact-generation.d.ts +7 -6
  37. package/dist/src/openclaw/artifact-generation.js +385 -41
  38. package/dist/src/openclaw/artifact-generation.js.map +1 -1
  39. package/dist/src/openclaw/bridges/discord.d.ts +1 -0
  40. package/dist/src/openclaw/bridges/discord.js +149 -0
  41. package/dist/src/openclaw/bridges/discord.js.map +1 -0
  42. package/dist/src/openclaw/bridges/matrix.js +22 -5
  43. package/dist/src/openclaw/bridges/matrix.js.map +1 -1
  44. package/dist/src/openclaw/bridges/mattermost.js +14 -9
  45. package/dist/src/openclaw/bridges/mattermost.js.map +1 -1
  46. package/dist/src/openclaw/bridges/probe-response.d.ts +1 -0
  47. package/dist/src/openclaw/bridges/probe-response.js +5 -0
  48. package/dist/src/openclaw/bridges/probe-response.js.map +1 -0
  49. package/dist/src/openclaw/bridges/signal.js +16 -7
  50. package/dist/src/openclaw/bridges/signal.js.map +1 -1
  51. package/dist/src/openclaw/bridges/slack.js +117 -24
  52. package/dist/src/openclaw/bridges/slack.js.map +1 -1
  53. package/dist/src/openclaw/bridges/telegram.js +46 -20
  54. package/dist/src/openclaw/bridges/telegram.js.map +1 -1
  55. package/dist/src/openclaw/bridges/whatsapp.js +33 -17
  56. package/dist/src/openclaw/bridges/whatsapp.js.map +1 -1
  57. package/dist/src/openclaw/bridges/zalo.js +9 -4
  58. package/dist/src/openclaw/bridges/zalo.js.map +1 -1
  59. package/dist/src/openclaw/outbound-contract.js +3 -0
  60. package/dist/src/openclaw/outbound-contract.js.map +1 -1
  61. package/dist/src/openclaw/private-file.d.ts +38 -3
  62. package/dist/src/openclaw/private-file.js +2008 -87
  63. package/dist/src/openclaw/private-file.js.map +1 -1
  64. package/dist/src/openclaw/{smoke-lock.d.ts → provider-readiness-lock.d.ts} +14 -5
  65. package/dist/src/openclaw/provider-readiness-lock.js +1320 -0
  66. package/dist/src/openclaw/provider-readiness-lock.js.map +1 -0
  67. package/dist/src/openclaw/shared.d.ts +10 -17
  68. package/dist/src/openclaw/shared.js +53 -19
  69. package/dist/src/openclaw/shared.js.map +1 -1
  70. package/dist/src/openclaw.d.ts +3 -5
  71. package/dist/src/openclaw.js +245 -60
  72. package/dist/src/openclaw.js.map +1 -1
  73. package/dist/src/platform/process-owned-lock.d.ts +11 -0
  74. package/dist/src/platform/process-owned-lock.js +1698 -0
  75. package/dist/src/platform/process-owned-lock.js.map +1 -0
  76. package/dist/src/platform/recorder-directory.d.ts +1 -0
  77. package/dist/src/platform/recorder-directory.js +14 -0
  78. package/dist/src/platform/recorder-directory.js.map +1 -0
  79. package/dist/src/platform/windows-acl.d.ts +18 -0
  80. package/dist/src/platform/windows-acl.js +1367 -0
  81. package/dist/src/platform/windows-acl.js.map +1 -0
  82. package/dist/src/platform/windows-lock-root.d.ts +13 -0
  83. package/dist/src/platform/windows-lock-root.js +98 -0
  84. package/dist/src/platform/windows-lock-root.js.map +1 -0
  85. package/dist/src/providers/builtin/discord.d.ts +4 -0
  86. package/dist/src/providers/builtin/discord.js +52 -9
  87. package/dist/src/providers/builtin/discord.js.map +1 -1
  88. package/dist/src/providers/builtin/external-webhook-auth.d.ts +1 -0
  89. package/dist/src/providers/builtin/external-webhook-auth.js +38 -1
  90. package/dist/src/providers/builtin/external-webhook-auth.js.map +1 -1
  91. package/dist/src/providers/builtin/feishu.d.ts +1 -0
  92. package/dist/src/providers/builtin/feishu.js +96 -26
  93. package/dist/src/providers/builtin/feishu.js.map +1 -1
  94. package/dist/src/providers/builtin/googlechat.d.ts +1 -0
  95. package/dist/src/providers/builtin/googlechat.js +95 -26
  96. package/dist/src/providers/builtin/googlechat.js.map +1 -1
  97. package/dist/src/providers/builtin/imessage.js +60 -17
  98. package/dist/src/providers/builtin/imessage.js.map +1 -1
  99. package/dist/src/providers/builtin/loopback.js +88 -35
  100. package/dist/src/providers/builtin/loopback.js.map +1 -1
  101. package/dist/src/providers/builtin/matrix.d.ts +2 -2
  102. package/dist/src/providers/builtin/matrix.js +78 -21
  103. package/dist/src/providers/builtin/matrix.js.map +1 -1
  104. package/dist/src/providers/builtin/mattermost.d.ts +11 -7
  105. package/dist/src/providers/builtin/mattermost.js +138 -24
  106. package/dist/src/providers/builtin/mattermost.js.map +1 -1
  107. package/dist/src/providers/builtin/msteams.d.ts +1 -0
  108. package/dist/src/providers/builtin/msteams.js +118 -38
  109. package/dist/src/providers/builtin/msteams.js.map +1 -1
  110. package/dist/src/providers/builtin/native-local-mock.js +4 -4
  111. package/dist/src/providers/builtin/native-local-mock.js.map +1 -1
  112. package/dist/src/providers/builtin/script.js +1057 -146
  113. package/dist/src/providers/builtin/script.js.map +1 -1
  114. package/dist/src/providers/builtin/slack.d.ts +8 -1
  115. package/dist/src/providers/builtin/slack.js +327 -24
  116. package/dist/src/providers/builtin/slack.js.map +1 -1
  117. package/dist/src/providers/builtin/telegram.d.ts +1 -1
  118. package/dist/src/providers/builtin/telegram.js +55 -14
  119. package/dist/src/providers/builtin/telegram.js.map +1 -1
  120. package/dist/src/providers/builtin/whatsapp.d.ts +4 -3
  121. package/dist/src/providers/builtin/whatsapp.js +157 -29
  122. package/dist/src/providers/builtin/whatsapp.js.map +1 -1
  123. package/dist/src/providers/builtin/zalo.d.ts +5 -2
  124. package/dist/src/providers/builtin/zalo.js +31 -7
  125. package/dist/src/providers/builtin/zalo.js.map +1 -1
  126. package/dist/src/providers/catalog.d.ts +1 -1
  127. package/dist/src/providers/catalog.js +1 -1
  128. package/dist/src/providers/catalog.js.map +1 -1
  129. package/dist/src/providers/local-mock.d.ts +4 -0
  130. package/dist/src/providers/local-mock.js +162 -35
  131. package/dist/src/providers/local-mock.js.map +1 -1
  132. package/dist/src/providers/native-ids.d.ts +2 -0
  133. package/dist/src/providers/native-ids.js +3 -0
  134. package/dist/src/providers/native-ids.js.map +1 -1
  135. package/dist/src/providers/recorder.d.ts +14 -3
  136. package/dist/src/providers/recorder.js +521 -41
  137. package/dist/src/providers/recorder.js.map +1 -1
  138. package/dist/src/providers/registry.d.ts +1 -0
  139. package/dist/src/providers/registry.js +65 -20
  140. package/dist/src/providers/registry.js.map +1 -1
  141. package/dist/src/providers/signed-jwt.d.ts +6 -1
  142. package/dist/src/providers/signed-jwt.js +241 -50
  143. package/dist/src/providers/signed-jwt.js.map +1 -1
  144. package/dist/src/providers/slack-ids.d.ts +1 -0
  145. package/dist/src/providers/slack-ids.js +5 -0
  146. package/dist/src/providers/slack-ids.js.map +1 -1
  147. package/dist/src/providers/target-normalizers.d.ts +9 -1
  148. package/dist/src/providers/target-normalizers.js +177 -58
  149. package/dist/src/providers/target-normalizers.js.map +1 -1
  150. package/dist/src/providers/webhook-server.d.ts +3 -0
  151. package/dist/src/providers/webhook-server.js +268 -47
  152. package/dist/src/providers/webhook-server.js.map +1 -1
  153. package/dist/src/servers/discord.d.ts +40 -0
  154. package/dist/src/servers/discord.js +842 -0
  155. package/dist/src/servers/discord.js.map +1 -0
  156. package/dist/src/servers/http.d.ts +14 -2
  157. package/dist/src/servers/http.js +229 -58
  158. package/dist/src/servers/http.js.map +1 -1
  159. package/dist/src/servers/index.d.ts +10 -4
  160. package/dist/src/servers/index.js +4 -0
  161. package/dist/src/servers/index.js.map +1 -1
  162. package/dist/src/servers/matrix.d.ts +3 -0
  163. package/dist/src/servers/matrix.js +268 -110
  164. package/dist/src/servers/matrix.js.map +1 -1
  165. package/dist/src/servers/mattermost.d.ts +5 -0
  166. package/dist/src/servers/mattermost.js +389 -91
  167. package/dist/src/servers/mattermost.js.map +1 -1
  168. package/dist/src/servers/recorder.d.ts +11 -0
  169. package/dist/src/servers/recorder.js +1072 -69
  170. package/dist/src/servers/recorder.js.map +1 -1
  171. package/dist/src/servers/signal.d.ts +1 -0
  172. package/dist/src/servers/signal.js +279 -44
  173. package/dist/src/servers/signal.js.map +1 -1
  174. package/dist/src/servers/slack.d.ts +15 -0
  175. package/dist/src/servers/slack.js +270 -54
  176. package/dist/src/servers/slack.js.map +1 -1
  177. package/dist/src/servers/telegram-identity.d.ts +6 -0
  178. package/dist/src/servers/telegram-identity.js +27 -0
  179. package/dist/src/servers/telegram-identity.js.map +1 -0
  180. package/dist/src/servers/telegram.d.ts +17 -6
  181. package/dist/src/servers/telegram.js +1218 -107
  182. package/dist/src/servers/telegram.js.map +1 -1
  183. package/dist/src/servers/webhook-target.d.ts +12 -4
  184. package/dist/src/servers/webhook-target.js +226 -28
  185. package/dist/src/servers/webhook-target.js.map +1 -1
  186. package/dist/src/servers/whatsapp-baileys-websocket.d.ts +60 -1
  187. package/dist/src/servers/whatsapp-baileys-websocket.js +782 -112
  188. package/dist/src/servers/whatsapp-baileys-websocket.js.map +1 -1
  189. package/dist/src/servers/whatsapp-jid.d.ts +1 -0
  190. package/dist/src/servers/whatsapp-jid.js +9 -5
  191. package/dist/src/servers/whatsapp-jid.js.map +1 -1
  192. package/dist/src/servers/whatsapp-wire/binary-node.d.ts +1 -0
  193. package/dist/src/servers/whatsapp-wire/binary-node.js +37 -13
  194. package/dist/src/servers/whatsapp-wire/binary-node.js.map +1 -1
  195. package/dist/src/servers/whatsapp-wire/crypto.d.ts +3 -0
  196. package/dist/src/servers/whatsapp-wire/crypto.js +23 -8
  197. package/dist/src/servers/whatsapp-wire/crypto.js.map +1 -1
  198. package/dist/src/servers/whatsapp-wire/handshake.d.ts +9 -3
  199. package/dist/src/servers/whatsapp-wire/handshake.js +173 -12
  200. package/dist/src/servers/whatsapp-wire/handshake.js.map +1 -1
  201. package/dist/src/servers/whatsapp-wire/signal.js +3 -3
  202. package/dist/src/servers/whatsapp-wire/signal.js.map +1 -1
  203. package/dist/src/servers/whatsapp.d.ts +7 -1
  204. package/dist/src/servers/whatsapp.js +149 -25
  205. package/dist/src/servers/whatsapp.js.map +1 -1
  206. package/dist/src/servers/zalo.d.ts +1 -0
  207. package/dist/src/servers/zalo.js +193 -82
  208. package/dist/src/servers/zalo.js.map +1 -1
  209. package/docs/channel-setup.md +251 -64
  210. package/fixtures/examples/crabline.example.yaml +3 -2
  211. package/package.json +18 -10
  212. package/dist/src/openclaw/smoke-lock.js +0 -1004
  213. package/dist/src/openclaw/smoke-lock.js.map +0 -1
  214. package/fixtures/examples/openclaw-bridge.yaml +0 -125
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discord.js","sourceRoot":"","sources":["../../../src/servers/discord.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomBytes, randomUUID } from \"node:crypto\";\nimport type { IncomingMessage } from \"node:http\";\nimport path from \"node:path\";\nimport type { Duplex } from \"node:stream\";\nimport { WebSocket, WebSocketServer, type RawData } from \"ws\";\nimport {\n adminAuthError,\n constantTimeTokenEqual,\n hasAdminToken,\n InvalidJsonBodyError,\n isJsonObject,\n isLoopbackHost,\n parseUnknownRequestBody,\n queryRecord,\n readTrimmedString,\n RequestBodyTooLargeError,\n startHttpJsonServer,\n type ServerRequestEvent,\n} from \"./http.js\";\nimport {\n recordCommittedServerEvent,\n recordServerEvent,\n type ServerEventObserver,\n} from \"./recorder.js\";\nimport { closeWebSocketServer } from \"./websocket.js\";\n\nconst DEFAULT_HEARTBEAT_INTERVAL_MS = 45_000;\nconst DEFAULT_IDENTIFY_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_GATEWAY_PAYLOAD_BYTES = 4_096;\nconst DISCORD_EPOCH_MS = 1_420_070_400_000n;\nconst DISCORD_ID_PATTERN = /^\\d{17,20}$/u;\n\ntype DiscordUser = {\n avatar: null;\n bot?: boolean;\n discriminator: \"0\";\n global_name: string | null;\n id: string;\n username: string;\n};\n\ntype DiscordChannel = {\n guild_id?: string;\n id: string;\n last_message_id: string | null;\n name?: string;\n parent_id?: string | null;\n recipients?: DiscordUser[];\n type: number;\n};\n\ntype DiscordMessage = {\n allowed_mentions?: unknown;\n attachments: unknown[];\n author: DiscordUser;\n channel_id: string;\n components: unknown[];\n content: string;\n edited_timestamp: null;\n embeds: unknown[];\n flags: number;\n guild_id?: string;\n id: string;\n mention_everyone: boolean;\n mention_roles: string[];\n mentions: DiscordUser[];\n message_reference?: {\n channel_id: string;\n guild_id?: string;\n message_id: string;\n };\n nonce?: string | number;\n pinned: boolean;\n referenced_message?: DiscordMessage | null;\n timestamp: string;\n tts: boolean;\n type: number;\n};\n\ntype DiscordCommand = Record<string, unknown> & {\n application_id: string;\n id: string;\n version: string;\n};\n\ntype GatewayClient = {\n identified: boolean;\n sessionId?: string;\n socket: WebSocket;\n};\n\ntype GatewaySession = {\n lastSequence: number;\n};\n\ntype DiscordServerState = {\n adminToken: string;\n applicationId: string;\n botToken: string;\n botUser: DiscordUser;\n channels: Map<string, DiscordChannel>;\n commands: Map<string, DiscordCommand>;\n gatewayClients: Set<GatewayClient>;\n gatewayUrl?: string;\n guildCommands: Map<string, Map<string, DiscordCommand>>;\n guilds: Map<string, Record<string, unknown>>;\n heartbeatIntervalMs: number;\n identifyTimeoutMs: number;\n maxGatewayPayloadBytes: number;\n messages: Map<string, DiscordMessage[]>;\n nextSequence: number;\n onEvent: ServerEventObserver | undefined;\n pendingRecorderEvents: Set<Promise<void>>;\n recorderPath: string;\n sessions: Map<string, GatewaySession>;\n};\n\ntype DiscordRecorderEvent = ServerRequestEvent & { accepted?: boolean };\n\nexport type DiscordServerManifest = {\n adminToken: string;\n applicationId: string;\n baseUrl: string;\n botToken: string;\n botUserId: string;\n endpoints: {\n adminInboundUrl: string;\n apiRoot: string;\n gatewayBotUrl: string;\n gatewayUrl: string;\n };\n env: {\n DISCORD_BOT_TOKEN: string;\n };\n provider: \"discord\";\n recorderPath: string;\n version: 1;\n};\n\nexport type StartedDiscordServer = {\n close(): Promise<void>;\n manifest: DiscordServerManifest;\n};\n\nexport type StartDiscordServerParams = {\n adminToken?: string | undefined;\n applicationId?: string | undefined;\n botToken?: string | undefined;\n botUserId?: string | undefined;\n botUsername?: string | undefined;\n heartbeatIntervalMs?: number | undefined;\n host?: string | undefined;\n identifyTimeoutMs?: number | undefined;\n maxGatewayPayloadBytes?: number | undefined;\n onEvent?: ServerEventObserver | undefined;\n port?: number | undefined;\n recorderPath?: string | undefined;\n};\n\nfunction discordSnowflake(seed = 0): string {\n const timestamp = BigInt(Math.max(Date.now(), Number(DISCORD_EPOCH_MS))) - DISCORD_EPOCH_MS;\n return ((timestamp << 22n) | BigInt(seed & 0x3f_ffff)).toString();\n}\n\nexport function discordDirectChannelId(botUserId: string, recipientId: string): string {\n if (!DISCORD_ID_PATTERN.test(botUserId) || !DISCORD_ID_PATTERN.test(recipientId)) {\n throw new Error(\"Discord direct channel participants must be Discord snowflakes.\");\n }\n const digest = createHash(\"sha256\")\n .update([botUserId, recipientId].sort().join(\":\"))\n .digest(\"hex\");\n return (\n 100_000_000_000_000_000n +\n (BigInt(`0x${digest.slice(0, 16)}`) % 900_000_000_000_000_000n)\n ).toString();\n}\n\nfunction requireSnowflake(value: unknown, label: string): string {\n const id = readTrimmedString(value);\n if (!id || !DISCORD_ID_PATTERN.test(id)) {\n throw new DiscordRequestError(400, 50_035, `${label} must be a Discord snowflake.`);\n }\n return id;\n}\n\nfunction positiveInteger(value: number | undefined, fallback: number, label: string): number {\n const resolved = value ?? fallback;\n if (!Number.isSafeInteger(resolved) || resolved <= 0) {\n throw new RangeError(`${label} must be a positive safe integer.`);\n }\n return resolved;\n}\n\nclass DiscordRequestError extends Error {\n constructor(\n readonly status: number,\n readonly code: number,\n message: string,\n ) {\n super(message);\n this.name = \"DiscordRequestError\";\n }\n}\n\nfunction discordError(status: number, code: number, message: string): Response {\n return discordJson({ code, message }, status);\n}\n\nfunction rateLimitHeaders(headers?: ConstructorParameters<typeof Headers>[0]): Headers {\n return new Headers({\n \"x-ratelimit-bucket\": \"crabline-discord\",\n \"x-ratelimit-limit\": \"1000\",\n \"x-ratelimit-remaining\": \"999\",\n \"x-ratelimit-reset-after\": \"0\",\n ...Object.fromEntries(new Headers(headers)),\n });\n}\n\nfunction discordJson(value: unknown, status = 200): Response {\n return new Response(JSON.stringify(value), {\n headers: rateLimitHeaders({ \"content-type\": \"application/json\" }),\n status,\n });\n}\n\nfunction discordEmpty(status = 204): Response {\n return new Response(null, { headers: rateLimitHeaders(), status });\n}\n\nfunction authorizationError(request: IncomingMessage, state: DiscordServerState): Response | null {\n const authorization = request.headers.authorization?.trim();\n if (!authorization?.startsWith(\"Bot \")) {\n return new Response(JSON.stringify({ code: 0, message: \"401: Unauthorized\" }), {\n headers: rateLimitHeaders({\n \"content-type\": \"application/json\",\n \"www-authenticate\": 'Bot realm=\"Discord\"',\n }),\n status: 401,\n });\n }\n const token = authorization.slice(4);\n return constantTimeTokenEqual(token, state.botToken)\n ? null\n : new Response(JSON.stringify({ code: 0, message: \"401: Unauthorized\" }), {\n headers: rateLimitHeaders({ \"content-type\": \"application/json\" }),\n status: 401,\n });\n}\n\nfunction discordUser(id: string, username: string, bot = false): DiscordUser {\n return {\n avatar: null,\n ...(bot ? { bot: true } : {}),\n discriminator: \"0\",\n global_name: username,\n id,\n username,\n };\n}\n\nfunction ensureGuild(state: DiscordServerState, guildId: string): Record<string, unknown> {\n const current = state.guilds.get(guildId);\n if (current) {\n return current;\n }\n const guild = {\n afk_timeout: 300,\n channels: [],\n emojis: [],\n features: [],\n id: guildId,\n joined_at: new Date().toISOString(),\n large: false,\n member_count: 1,\n members: [\n {\n deaf: false,\n joined_at: new Date().toISOString(),\n mute: false,\n pending: false,\n roles: [],\n user: state.botUser,\n },\n ],\n name: \"Crabline Discord Guild\",\n owner_id: state.botUser.id,\n presences: [],\n roles: [\n {\n color: 0,\n hoist: false,\n id: guildId,\n managed: false,\n mentionable: false,\n name: \"@everyone\",\n permissions: \"0\",\n position: 0,\n },\n ],\n unavailable: false,\n voice_states: [],\n };\n state.guilds.set(guildId, guild);\n return guild;\n}\n\nfunction ensureChannel(params: {\n channelId: string;\n guildId?: string;\n parentId?: string;\n sender?: DiscordUser;\n state: DiscordServerState;\n}): DiscordChannel {\n const current = params.state.channels.get(params.channelId);\n if (current) {\n return current;\n }\n const channel: DiscordChannel = params.guildId\n ? {\n guild_id: params.guildId,\n id: params.channelId,\n last_message_id: null,\n name: params.parentId ? \"crabline-thread\" : \"crabline-channel\",\n parent_id: params.parentId ?? null,\n type: params.parentId ? 11 : 0,\n }\n : {\n id: params.channelId,\n last_message_id: null,\n recipients: params.sender ? [params.sender] : [],\n type: 1,\n };\n params.state.channels.set(params.channelId, channel);\n if (params.guildId) {\n const guild = ensureGuild(params.state, params.guildId);\n const channels = Array.isArray(guild.channels) ? guild.channels : [];\n guild.channels = [...channels, channel];\n }\n return channel;\n}\n\nfunction parseMentions(content: string, state: DiscordServerState): DiscordUser[] {\n const ids = new Set<string>();\n for (const match of content.matchAll(/<@!?(\\d{17,20})>/gu)) {\n ids.add(match[1]!);\n }\n return [...ids].map((id) =>\n id === state.botUser.id ? state.botUser : discordUser(id, `user-${id.slice(-6)}`),\n );\n}\n\nfunction resolveMessageReference(\n state: DiscordServerState,\n channelId: string,\n value: unknown,\n): DiscordMessage[\"message_reference\"] | undefined {\n if (!isJsonObject(value)) {\n return undefined;\n }\n const messageId = readTrimmedString(value.message_id);\n if (!messageId) {\n return undefined;\n }\n const referencedChannelId = readTrimmedString(value.channel_id) ?? channelId;\n const channel = state.channels.get(referencedChannelId);\n return {\n channel_id: referencedChannelId,\n ...(channel?.guild_id ? { guild_id: channel.guild_id } : {}),\n message_id: messageId,\n };\n}\n\nfunction findMessage(\n state: DiscordServerState,\n channelId: string,\n messageId: string,\n): DiscordMessage | undefined {\n return state.messages.get(channelId)?.find((message) => message.id === messageId);\n}\n\nfunction createMessage(params: {\n author: DiscordUser;\n body: Record<string, unknown>;\n channel: DiscordChannel;\n state: DiscordServerState;\n}): DiscordMessage {\n const content = typeof params.body.content === \"string\" ? params.body.content : \"\";\n const embeds = Array.isArray(params.body.embeds) ? params.body.embeds : [];\n const components = Array.isArray(params.body.components) ? params.body.components : [];\n const attachments = Array.isArray(params.body.attachments) ? params.body.attachments : [];\n if (!content && embeds.length === 0 && components.length === 0 && attachments.length === 0) {\n throw new DiscordRequestError(400, 50_006, \"Cannot send an empty message\");\n }\n if (content.length > 2_000) {\n throw new DiscordRequestError(400, 50_035, \"Invalid Form Body\");\n }\n const reference = resolveMessageReference(\n params.state,\n params.channel.id,\n params.body.message_reference,\n );\n const referencedMessage = reference\n ? (findMessage(params.state, reference.channel_id, reference.message_id) ?? null)\n : undefined;\n const failIfNotExists = isJsonObject(params.body.message_reference)\n ? params.body.message_reference.fail_if_not_exists\n : undefined;\n if (reference && referencedMessage === null && failIfNotExists !== false) {\n throw new DiscordRequestError(404, 10_008, \"Unknown Message\");\n }\n const message: DiscordMessage = {\n ...(params.body.allowed_mentions !== undefined\n ? { allowed_mentions: params.body.allowed_mentions }\n : {}),\n attachments,\n author: params.author,\n channel_id: params.channel.id,\n components,\n content,\n edited_timestamp: null,\n embeds,\n flags: typeof params.body.flags === \"number\" ? params.body.flags : 0,\n ...(params.channel.guild_id ? { guild_id: params.channel.guild_id } : {}),\n id: discordSnowflake(params.state.nextSequence),\n mention_everyone: /@(everyone|here)\\b/u.test(content),\n mention_roles: [...content.matchAll(/<@&(\\d{17,20})>/gu)].map((match) => match[1]!),\n mentions: parseMentions(content, params.state),\n ...(reference\n ? {\n message_reference: reference,\n ...(referencedMessage !== undefined ? { referenced_message: referencedMessage } : {}),\n }\n : {}),\n ...(typeof params.body.nonce === \"string\" || typeof params.body.nonce === \"number\"\n ? { nonce: params.body.nonce }\n : {}),\n pinned: false,\n timestamp: new Date().toISOString(),\n tts: params.body.tts === true,\n type: reference ? 19 : 0,\n };\n params.state.messages.set(params.channel.id, [\n ...(params.state.messages.get(params.channel.id) ?? []),\n message,\n ]);\n params.channel.last_message_id = message.id;\n return message;\n}\n\nfunction sendGatewayPayload(socket: WebSocket, payload: unknown): boolean {\n if (socket.readyState !== WebSocket.OPEN) {\n return false;\n }\n socket.send(JSON.stringify(payload));\n return true;\n}\n\nfunction dispatchGatewayEvent(state: DiscordServerState, type: string, data: unknown): void {\n const payload = { d: data, op: 0, s: state.nextSequence++, t: type };\n for (const client of state.gatewayClients) {\n if (client.identified) {\n sendGatewayPayload(client.socket, payload);\n if (client.sessionId) {\n const session = state.sessions.get(client.sessionId);\n if (session) {\n session.lastSequence = payload.s;\n }\n }\n }\n }\n}\n\nfunction recordGatewayEvent(state: DiscordServerState, body: unknown, accepted: boolean): void {\n const pending = recordCommittedServerEvent({\n event: {\n accepted,\n at: new Date().toISOString(),\n body,\n method: \"WS\",\n path: \"/gateway\",\n query: {},\n type: \"api\",\n } as DiscordRecorderEvent,\n onEvent: state.onEvent,\n recorderPath: state.recorderPath,\n });\n state.pendingRecorderEvents.add(pending);\n void pending.then(\n () => state.pendingRecorderEvents.delete(pending),\n () => state.pendingRecorderEvents.delete(pending),\n );\n}\n\nfunction readyPayload(state: DiscordServerState, sessionId: string) {\n return {\n application: { flags: 0, id: state.applicationId },\n guilds: [...state.guilds.values()].map((guild) => ({ id: guild.id, unavailable: true })),\n resume_gateway_url: state.gatewayUrl!,\n session_id: sessionId,\n user: state.botUser,\n v: 10,\n };\n}\n\nfunction attachGatewayServer(params: {\n server: import(\"node:http\").Server;\n state: DiscordServerState;\n}) {\n const gatewayServer = new WebSocketServer({\n maxPayload: params.state.maxGatewayPayloadBytes,\n noServer: true,\n });\n const onUpgrade = (request: IncomingMessage, socket: Duplex, head: Buffer) => {\n const url = new URL(request.url ?? \"/\", \"http://127.0.0.1\");\n if (url.pathname !== \"/gateway\") {\n socket.destroy();\n return;\n }\n if ((url.searchParams.get(\"v\") ?? \"10\") !== \"10\") {\n socket.destroy();\n return;\n }\n const encoding = url.searchParams.get(\"encoding\") ?? \"json\";\n if (encoding !== \"json\") {\n socket.destroy();\n return;\n }\n gatewayServer.handleUpgrade(request, socket, head, (client) => {\n gatewayServer.emit(\"connection\", client, request);\n });\n };\n params.server.on(\"upgrade\", onUpgrade);\n\n gatewayServer.on(\"connection\", (socket) => {\n const client: GatewayClient = { identified: false, socket };\n params.state.gatewayClients.add(client);\n sendGatewayPayload(socket, {\n d: { heartbeat_interval: params.state.heartbeatIntervalMs },\n op: 10,\n });\n const identifyTimeout = setTimeout(() => {\n if (!client.identified) {\n socket.close(4_003, \"Not authenticated\");\n }\n }, params.state.identifyTimeoutMs);\n identifyTimeout.unref();\n\n socket.on(\"message\", (raw: RawData) => {\n if (Buffer.byteLength(raw.toString()) > params.state.maxGatewayPayloadBytes) {\n socket.close(4_002, \"Decode error\");\n return;\n }\n let payload: unknown;\n try {\n payload = JSON.parse(raw.toString()) as unknown;\n } catch {\n socket.close(4_002, \"Decode error\");\n return;\n }\n if (!isJsonObject(payload) || typeof payload.op !== \"number\") {\n socket.close(4_002, \"Decode error\");\n return;\n }\n recordGatewayEvent(params.state, payload, true);\n if (payload.op === 1) {\n sendGatewayPayload(socket, { d: null, op: 11 });\n return;\n }\n if (payload.op === 2) {\n if (client.identified || !isJsonObject(payload.d)) {\n socket.close(4_005, \"Already authenticated\");\n return;\n }\n const token = readTrimmedString(payload.d.token);\n if (!token || !constantTimeTokenEqual(token, params.state.botToken)) {\n socket.close(4_004, \"Authentication failed\");\n return;\n }\n clearTimeout(identifyTimeout);\n client.identified = true;\n client.sessionId = randomUUID();\n params.state.sessions.set(client.sessionId, { lastSequence: params.state.nextSequence });\n if (params.state.sessions.size > 128) {\n const oldestSessionId = params.state.sessions.keys().next().value as string | undefined;\n if (oldestSessionId) {\n params.state.sessions.delete(oldestSessionId);\n }\n }\n sendGatewayPayload(socket, {\n d: readyPayload(params.state, client.sessionId),\n op: 0,\n s: params.state.nextSequence++,\n t: \"READY\",\n });\n for (const guild of params.state.guilds.values()) {\n dispatchGatewayEvent(params.state, \"GUILD_CREATE\", guild);\n }\n return;\n }\n if (payload.op === 6) {\n if (!isJsonObject(payload.d)) {\n sendGatewayPayload(socket, { d: false, op: 9 });\n return;\n }\n const token = readTrimmedString(payload.d.token);\n const sessionId = readTrimmedString(payload.d.session_id);\n const session = sessionId ? params.state.sessions.get(sessionId) : undefined;\n if (\n !token ||\n !constantTimeTokenEqual(token, params.state.botToken) ||\n !sessionId ||\n !Number.isSafeInteger(payload.d.seq) ||\n (payload.d.seq as number) < 0 ||\n !session ||\n payload.d.seq !== session.lastSequence\n ) {\n sendGatewayPayload(socket, { d: false, op: 9 });\n return;\n }\n clearTimeout(identifyTimeout);\n client.identified = true;\n client.sessionId = sessionId;\n params.state.sessions.delete(sessionId);\n params.state.sessions.set(sessionId, session);\n const resumedSequence = params.state.nextSequence++;\n session.lastSequence = resumedSequence;\n sendGatewayPayload(socket, {\n d: {},\n op: 0,\n s: resumedSequence,\n t: \"RESUMED\",\n });\n return;\n }\n if (payload.op === 3 || payload.op === 4 || payload.op === 8) {\n return;\n }\n socket.close(4_001, \"Unknown opcode\");\n });\n socket.on(\"error\", () => undefined);\n socket.once(\"close\", () => {\n clearTimeout(identifyTimeout);\n params.state.gatewayClients.delete(client);\n });\n });\n\n return async () => {\n params.server.off(\"upgrade\", onUpgrade);\n await closeWebSocketServer(gatewayServer);\n };\n}\n\nfunction commandBody(\n state: DiscordServerState,\n body: Record<string, unknown>,\n existing?: DiscordCommand,\n guildId?: string,\n): DiscordCommand {\n const name = readTrimmedString(body.name ?? existing?.name);\n if (!name || name.length > 32 || !/^[\\w-]+$/u.test(name)) {\n throw new DiscordRequestError(400, 50_035, \"Invalid Form Body\");\n }\n return {\n ...existing,\n ...body,\n application_id: state.applicationId,\n description: readTrimmedString(body.description ?? existing?.description) ?? \"\",\n ...(guildId ? { guild_id: guildId } : {}),\n id: existing?.id ?? discordSnowflake(state.nextSequence++),\n name,\n type: typeof body.type === \"number\" ? body.type : (existing?.type ?? 1),\n version: discordSnowflake(state.nextSequence++),\n };\n}\n\nasync function handleAdminInbound(params: {\n body: Record<string, unknown>;\n state: DiscordServerState;\n}): Promise<Response> {\n const requestedChannelId = requireSnowflake(params.body.channelId, \"channelId\");\n const guildId =\n params.body.guildId === undefined\n ? undefined\n : requireSnowflake(params.body.guildId, \"guildId\");\n const senderId = requireSnowflake(params.body.senderId, \"senderId\");\n const parentChannelId =\n params.body.parentChannelId === undefined\n ? undefined\n : requireSnowflake(params.body.parentChannelId, \"parentChannelId\");\n if (parentChannelId && !guildId) {\n throw new DiscordRequestError(400, 50_035, \"Threads require guildId.\");\n }\n const sender = discordUser(\n senderId,\n readTrimmedString(params.body.senderName) ?? `user-${senderId.slice(-6)}`,\n );\n const hadChannel = params.state.channels.has(requestedChannelId);\n const hadGuild = guildId ? params.state.guilds.has(guildId) : true;\n const channel = ensureChannel({\n channelId: requestedChannelId,\n ...(guildId ? { guildId } : {}),\n ...(parentChannelId ? { parentId: parentChannelId } : {}),\n sender,\n state: params.state,\n });\n const message = createMessage({\n author: sender,\n body: params.body,\n channel,\n state: params.state,\n });\n if (guildId) {\n const guild = params.state.guilds.get(guildId)!;\n const members = Array.isArray(guild.members) ? guild.members : [];\n if (\n !members.some(\n (member) =>\n isJsonObject(member) && isJsonObject(member.user) && member.user.id === sender.id,\n )\n ) {\n members.push({\n deaf: false,\n joined_at: new Date().toISOString(),\n mute: false,\n pending: false,\n roles: [],\n user: sender,\n });\n guild.members = members;\n guild.member_count = members.length;\n }\n (message as DiscordMessage & { member: Record<string, unknown> }).member = {\n deaf: false,\n joined_at: new Date().toISOString(),\n mute: false,\n pending: false,\n roles: [],\n };\n }\n if (!hadGuild && guildId) {\n dispatchGatewayEvent(params.state, \"GUILD_CREATE\", params.state.guilds.get(guildId));\n }\n if (!hadChannel) {\n dispatchGatewayEvent(params.state, \"CHANNEL_CREATE\", channel);\n }\n dispatchGatewayEvent(params.state, \"MESSAGE_CREATE\", message);\n return discordJson({ event: { d: message, op: 0, t: \"MESSAGE_CREATE\" }, message });\n}\n\nasync function handleDiscordApi(params: {\n body: unknown;\n method: string;\n pathname: string;\n state: DiscordServerState;\n}): Promise<Response> {\n const pathParts = params.pathname.split(\"/\").filter(Boolean);\n if (pathParts[0] !== \"api\" || pathParts[1] !== \"v10\") {\n return discordError(404, 0, \"404: Not Found\");\n }\n const route = pathParts.slice(2);\n if (params.method === \"GET\" && route.join(\"/\") === \"users/@me\") {\n return discordJson(params.state.botUser);\n }\n if (params.method === \"GET\" && route.join(\"/\") === \"oauth2/applications/@me\") {\n return discordJson({\n bot: params.state.botUser,\n flags: 0,\n id: params.state.applicationId,\n name: \"Crabline Discord Application\",\n owner: params.state.botUser,\n verify_key: \"crabline\",\n });\n }\n if (params.method === \"GET\" && route.join(\"/\") === \"gateway\") {\n return discordJson({ url: params.state.gatewayUrl });\n }\n if (params.method === \"GET\" && route.join(\"/\") === \"gateway/bot\") {\n return discordJson({\n session_start_limit: {\n max_concurrency: 1,\n remaining: 1_000,\n reset_after: 0,\n total: 1_000,\n },\n shards: 1,\n url: params.state.gatewayUrl,\n });\n }\n if (route[0] === \"channels\" && route.length >= 2) {\n const channelId = requireSnowflake(route[1], \"channel id\");\n const channel = params.state.channels.get(channelId);\n if (route.length === 2 && params.method === \"GET\") {\n return channel ? discordJson(channel) : discordError(404, 10_003, \"Unknown Channel\");\n }\n if (route[2] === \"typing\" && route.length === 3 && params.method === \"POST\") {\n return channel ? discordEmpty() : discordError(404, 10_003, \"Unknown Channel\");\n }\n if (route[2] === \"messages\") {\n if (!channel) {\n return discordError(404, 10_003, \"Unknown Channel\");\n }\n if (route.length === 3 && params.method === \"POST\") {\n if (!isJsonObject(params.body)) {\n throw new InvalidJsonBodyError(undefined, \"Request body must be a JSON object.\");\n }\n const message = createMessage({\n author: params.state.botUser,\n body: params.body,\n channel,\n state: params.state,\n });\n dispatchGatewayEvent(params.state, \"MESSAGE_CREATE\", message);\n return discordJson(message);\n }\n if (route.length === 3 && params.method === \"GET\") {\n return discordJson(\n [...(params.state.messages.get(channelId) ?? [])].reverse().slice(0, 50),\n );\n }\n const messageId = route[3] ? requireSnowflake(route[3], \"message id\") : undefined;\n if (\n messageId &&\n route[4] === \"reactions\" &&\n route[5] &&\n route[6] === \"@me\" &&\n (params.method === \"PUT\" || params.method === \"DELETE\")\n ) {\n return findMessage(params.state, channelId, messageId)\n ? discordEmpty()\n : discordError(404, 10_008, \"Unknown Message\");\n }\n if (messageId && params.method === \"GET\") {\n const message = findMessage(params.state, channelId, messageId);\n return message ? discordJson(message) : discordError(404, 10_008, \"Unknown Message\");\n }\n }\n }\n if (params.method === \"POST\" && route.join(\"/\") === \"users/@me/channels\") {\n if (!isJsonObject(params.body)) {\n throw new InvalidJsonBodyError(undefined, \"Request body must be a JSON object.\");\n }\n const recipientId = requireSnowflake(params.body.recipient_id, \"recipient_id\");\n const recipient = discordUser(recipientId, `user-${recipientId.slice(-6)}`);\n const channelId = discordDirectChannelId(params.state.botUser.id, recipientId);\n return discordJson(ensureChannel({ channelId, sender: recipient, state: params.state }));\n }\n if (route[0] === \"guilds\" && route[1]) {\n const guildId = requireSnowflake(route[1], \"guild id\");\n const guild = params.state.guilds.get(guildId);\n if (!guild) {\n return discordError(404, 10_004, \"Unknown Guild\");\n }\n if (route.length === 2 && params.method === \"GET\") {\n return discordJson(guild);\n }\n if (route[2] === \"channels\" && params.method === \"GET\") {\n return discordJson(\n [...params.state.channels.values()].filter((channel) => channel.guild_id === guildId),\n );\n }\n if (route[2] === \"roles\" && params.method === \"GET\") {\n return discordJson(guild.roles ?? []);\n }\n if (route[2] === \"members\" && route[3] && params.method === \"GET\") {\n const userId = requireSnowflake(route[3], \"user id\");\n const user =\n userId === params.state.botUser.id\n ? params.state.botUser\n : discordUser(userId, `user-${userId.slice(-6)}`);\n return discordJson({\n deaf: false,\n joined_at: new Date().toISOString(),\n mute: false,\n pending: false,\n roles: [],\n user,\n });\n }\n }\n if (route[0] === \"applications\" && route[1] === params.state.applicationId) {\n let commandOffset = 2;\n let guildId: string | undefined;\n if (route[2] === \"guilds\" && route[3] && route[4] === \"commands\") {\n guildId = requireSnowflake(route[3], \"guild id\");\n commandOffset = 4;\n }\n if (route[commandOffset] === \"commands\") {\n const commands = guildId\n ? (params.state.guildCommands.get(guildId) ?? new Map<string, DiscordCommand>())\n : params.state.commands;\n if (guildId && !params.state.guildCommands.has(guildId)) {\n params.state.guildCommands.set(guildId, commands);\n }\n const commandId = route[commandOffset + 1];\n if (!commandId && params.method === \"GET\") {\n return discordJson([...commands.values()]);\n }\n if (!commandId && params.method === \"PUT\") {\n if (!Array.isArray(params.body) || params.body.some((entry) => !isJsonObject(entry))) {\n throw new DiscordRequestError(400, 50_035, \"Invalid Form Body\");\n }\n commands.clear();\n for (const body of params.body as Record<string, unknown>[]) {\n const command = commandBody(params.state, body, undefined, guildId);\n commands.set(command.id, command);\n }\n return discordJson([...commands.values()]);\n }\n if (!commandId && params.method === \"POST\") {\n if (!isJsonObject(params.body)) {\n throw new DiscordRequestError(400, 50_035, \"Invalid Form Body\");\n }\n const name = readTrimmedString(params.body.name);\n const type = typeof params.body.type === \"number\" ? params.body.type : 1;\n const existing = [...commands.values()].find(\n (command) => command.name === name && command.type === type,\n );\n const command = commandBody(params.state, params.body, existing, guildId);\n commands.set(command.id, command);\n return discordJson(command, existing ? 200 : 201);\n }\n if (commandId) {\n const existing = commands.get(commandId);\n if (!existing) {\n return discordError(404, 10_063, \"Unknown application command\");\n }\n if (params.method === \"PATCH\") {\n if (!isJsonObject(params.body)) {\n throw new DiscordRequestError(400, 50_035, \"Invalid Form Body\");\n }\n const command = commandBody(params.state, params.body, existing, guildId);\n commands.set(commandId, command);\n return discordJson(command);\n }\n if (params.method === \"DELETE\") {\n commands.delete(commandId);\n return discordEmpty();\n }\n }\n }\n }\n return discordError(404, 0, \"404: Not Found\");\n}\n\nasync function handleRequest(params: {\n request: IncomingMessage;\n state: DiscordServerState;\n}): Promise<Response> {\n const url = new URL(params.request.url ?? \"/\", \"http://127.0.0.1\");\n const method = params.request.method ?? \"GET\";\n if (url.pathname === \"/crabline/discord/inbound\") {\n if (method !== \"POST\") {\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 throw new InvalidJsonBodyError(undefined, \"Request body must be a JSON object.\");\n }\n const event: DiscordRecorderEvent = {\n at: new Date().toISOString(),\n body,\n method,\n path: url.pathname,\n query: queryRecord(url),\n type: \"admin\",\n };\n const response = await handleAdminInbound({ body, state: params.state });\n event.accepted = response.ok;\n await recordCommittedServerEvent({\n event,\n onEvent: params.state.onEvent,\n recorderPath: params.state.recorderPath,\n });\n return response;\n }\n const authError =\n method === \"GET\" && url.pathname === \"/api/v10/gateway\"\n ? null\n : authorizationError(params.request, params.state);\n if (authError) {\n params.request.resume();\n return authError;\n }\n const body =\n method === \"GET\" || method === \"DELETE\" ? {} : await parseUnknownRequestBody(params.request);\n const event: DiscordRecorderEvent = {\n at: new Date().toISOString(),\n ...(isJsonObject(body) && Object.keys(body).length > 0 ? { body } : {}),\n method,\n path: url.pathname,\n query: queryRecord(url),\n type: \"api\",\n };\n const response = await handleDiscordApi({\n body,\n method,\n pathname: url.pathname,\n state: params.state,\n });\n event.accepted = response.ok;\n await (response.ok ? recordCommittedServerEvent : recordServerEvent)({\n event,\n onEvent: params.state.onEvent,\n recorderPath: params.state.recorderPath,\n });\n return response;\n}\n\nexport async function startDiscordServer(\n params: StartDiscordServerParams = {},\n): Promise<StartedDiscordServer> {\n const host = params.host ?? \"127.0.0.1\";\n const applicationId = params.applicationId ?? \"135000000000000001\";\n const botUserId = params.botUserId ?? applicationId;\n requireSnowflake(applicationId, \"applicationId\");\n requireSnowflake(botUserId, \"botUserId\");\n const encodedApplicationId = Buffer.from(applicationId, \"utf8\").toString(\"base64url\");\n const externallyBound = !isLoopbackHost(host);\n const state: DiscordServerState = {\n adminToken: params.adminToken ?? randomBytes(24).toString(\"base64url\"),\n applicationId,\n botToken:\n params.botToken ??\n (externallyBound\n ? `${encodedApplicationId}.${randomBytes(6).toString(\"base64url\")}.${randomBytes(24).toString(\"base64url\")}`\n : `${encodedApplicationId}.crabline.discord`),\n botUser: discordUser(botUserId, params.botUsername ?? \"crabline\", true),\n channels: new Map(),\n commands: new Map(),\n gatewayClients: new Set(),\n guildCommands: new Map(),\n guilds: new Map(),\n heartbeatIntervalMs: positiveInteger(\n params.heartbeatIntervalMs,\n DEFAULT_HEARTBEAT_INTERVAL_MS,\n \"heartbeatIntervalMs\",\n ),\n identifyTimeoutMs: positiveInteger(\n params.identifyTimeoutMs,\n DEFAULT_IDENTIFY_TIMEOUT_MS,\n \"identifyTimeoutMs\",\n ),\n maxGatewayPayloadBytes: positiveInteger(\n params.maxGatewayPayloadBytes,\n DEFAULT_MAX_GATEWAY_PAYLOAD_BYTES,\n \"maxGatewayPayloadBytes\",\n ),\n messages: new Map(),\n nextSequence: 1,\n onEvent: params.onEvent,\n pendingRecorderEvents: new Set(),\n recorderPath: params.recorderPath ?? path.resolve(\".crabline\", \"servers\", \"discord.jsonl\"),\n sessions: new Map(),\n };\n const httpServer = await startHttpJsonServer({\n handle: (request) => handleRequest({ request, state }),\n handleError: (error) => {\n if (error instanceof DiscordRequestError) {\n return discordError(error.status, error.code, error.message);\n }\n if (error instanceof InvalidJsonBodyError) {\n return discordError(400, 50_035, \"Invalid Form Body\");\n }\n if (error instanceof RequestBodyTooLargeError) {\n return discordError(413, 40_005, \"Request entity too large\");\n }\n return undefined;\n },\n host,\n port: params.port ?? 0,\n serverName: \"Discord\",\n });\n state.gatewayUrl = `${httpServer.baseUrl.replace(/^http/u, \"ws\")}/gateway`;\n const closeGateway = attachGatewayServer({ server: httpServer.server, state });\n return {\n async close() {\n await closeGateway();\n await httpServer.close();\n await Promise.all([...state.pendingRecorderEvents]);\n state.sessions.clear();\n },\n manifest: {\n adminToken: state.adminToken,\n applicationId: state.applicationId,\n baseUrl: httpServer.baseUrl,\n botToken: state.botToken,\n botUserId: state.botUser.id,\n endpoints: {\n adminInboundUrl: `${httpServer.baseUrl}/crabline/discord/inbound`,\n apiRoot: `${httpServer.baseUrl}/api`,\n gatewayBotUrl: `${httpServer.baseUrl}/api/v10/gateway/bot`,\n gatewayUrl: state.gatewayUrl,\n },\n env: { DISCORD_BOT_TOKEN: state.botToken },\n provider: \"discord\",\n recorderPath: state.recorderPath,\n version: 1,\n },\n };\n}\n"]}
@@ -14,29 +14,40 @@ export type HttpJsonHandlerResult = Response | {
14
14
  };
15
15
  export declare const ADMIN_TOKEN_HEADER = "x-crabline-admin-token";
16
16
  export declare const DEFAULT_MAX_REQUEST_BODY_BYTES: number;
17
+ export declare const DEFAULT_MAX_RESPONSE_BODY_BYTES: number;
17
18
  export declare const DEFAULT_SERVER_SHUTDOWN_GRACE_MS = 250;
18
19
  export declare class InvalidJsonBodyError extends Error {
19
- constructor(cause: unknown);
20
+ constructor(cause: unknown, message?: string);
20
21
  }
21
22
  export declare class RequestBodyTooLargeError extends Error {
22
23
  readonly maxBytes: number;
23
24
  constructor(maxBytes: number);
24
25
  }
26
+ export declare class ResponseBodyTooLargeError extends Error {
27
+ readonly maxBytes: number;
28
+ constructor(maxBytes: number);
29
+ }
25
30
  export declare function jsonResponse(value: unknown, status?: number): Response;
26
31
  export declare function drainRequestBody(request: IncomingMessage): void;
27
32
  export declare function readBody(request: IncomingMessage, maxBytes?: number): Promise<Buffer>;
28
33
  export declare function parseUnknownRequestBody(request: IncomingMessage, maxBytes?: number): Promise<unknown>;
34
+ export declare function isJsonMediaType(value: string): boolean;
29
35
  export declare function parseRequestBody(request: IncomingMessage): Promise<Record<string, unknown>>;
30
36
  export declare function isJsonObject(value: unknown): value is Record<string, unknown>;
31
37
  export declare function queryRecord(url: URL): Record<string, string>;
32
38
  export declare function formatUrlHost(host: string): string;
39
+ export declare function isLoopbackAddress(address: string): boolean;
33
40
  export declare function isLoopbackHost(host: string): boolean;
34
- export declare function writeResponse(response: ServerResponse, fetchResponse: Response): Promise<void>;
41
+ export declare function advertisedHostForBindAddress(host: string, boundAddress: string): string;
42
+ export declare function assertLoopbackBindAddress(configuredHost: string, boundAddress: string, serverName: string): void;
43
+ export declare function writeFetchResponseHeaders(response: ServerResponse, fetchResponse: Response): void;
44
+ export declare function writeResponse(response: ServerResponse, fetchResponse: Response, maxBytes?: number): Promise<void>;
35
45
  export declare function closeServer(server: Server, graceMs?: number): Promise<void>;
36
46
  export declare function startHttpJsonServer(params: {
37
47
  handle: (request: IncomingMessage, response: ServerResponse) => Promise<HttpJsonHandlerResult>;
38
48
  handleError?: (error: unknown, request: IncomingMessage) => Response | undefined;
39
49
  host: string;
50
+ maxResponseBodyBytes?: number | undefined;
40
51
  port: number;
41
52
  serverName: string;
42
53
  }): Promise<{
@@ -47,5 +58,6 @@ export declare function startHttpJsonServer(params: {
47
58
  export declare function readString(value: unknown): string | undefined;
48
59
  export declare function readTrimmedString(value: unknown): string | undefined;
49
60
  export declare function readInteger(value: unknown): number | undefined;
61
+ export declare function constantTimeTokenEqual(providedToken: string, expectedToken: string): boolean;
50
62
  export declare function hasAdminToken(request: IncomingMessage, expectedToken: string): boolean;
51
63
  export declare function adminAuthError(): Response;
@@ -1,12 +1,33 @@
1
1
  import { createServer } from "node:http";
2
- import { timingSafeEqual } from "node:crypto";
2
+ import { createHash, timingSafeEqual } from "node:crypto";
3
+ import { BlockList, isIP } from "node:net";
3
4
  import { CrablineError } from "../core/errors.js";
4
5
  export const ADMIN_TOKEN_HEADER = "x-crabline-admin-token";
5
6
  export const DEFAULT_MAX_REQUEST_BODY_BYTES = 1024 * 1024;
7
+ export const DEFAULT_MAX_RESPONSE_BODY_BYTES = 8 * 1024 * 1024;
6
8
  export const DEFAULT_SERVER_SHUTDOWN_GRACE_MS = 250;
9
+ const DRAINING_REQUESTS = new WeakSet();
10
+ const LOOPBACK_ADDRESSES = new BlockList();
11
+ LOOPBACK_ADDRESSES.addSubnet("127.0.0.0", 8, "ipv4");
12
+ LOOPBACK_ADDRESSES.addAddress("::1", "ipv6");
13
+ LOOPBACK_ADDRESSES.addSubnet("::ffff:127.0.0.0", 104, "ipv6");
14
+ const UNSPECIFIED_ADDRESSES = new BlockList();
15
+ UNSPECIFIED_ADDRESSES.addAddress("0.0.0.0", "ipv4");
16
+ UNSPECIFIED_ADDRESSES.addAddress("::", "ipv6");
17
+ const HOP_BY_HOP_RESPONSE_HEADERS = new Set([
18
+ "connection",
19
+ "keep-alive",
20
+ "proxy-authenticate",
21
+ "proxy-authorization",
22
+ "proxy-connection",
23
+ "te",
24
+ "trailer",
25
+ "transfer-encoding",
26
+ "upgrade",
27
+ ]);
7
28
  export class InvalidJsonBodyError extends Error {
8
- constructor(cause) {
9
- super("Request body is not valid JSON.", { cause });
29
+ constructor(cause, message = "Request body is not valid JSON.") {
30
+ super(message, { cause });
10
31
  this.name = "InvalidJsonBodyError";
11
32
  }
12
33
  }
@@ -18,16 +39,30 @@ export class RequestBodyTooLargeError extends Error {
18
39
  this.name = "RequestBodyTooLargeError";
19
40
  }
20
41
  }
42
+ export class ResponseBodyTooLargeError extends Error {
43
+ maxBytes;
44
+ constructor(maxBytes) {
45
+ super(`Response body exceeds the ${maxBytes} byte limit.`);
46
+ this.maxBytes = maxBytes;
47
+ this.name = "ResponseBodyTooLargeError";
48
+ }
49
+ }
21
50
  export function jsonResponse(value, status = 200) {
22
51
  return Response.json(value, { status });
23
52
  }
24
53
  export function drainRequestBody(request) {
54
+ if (request.readableEnded || DRAINING_REQUESTS.has(request)) {
55
+ return;
56
+ }
57
+ DRAINING_REQUESTS.add(request);
25
58
  const ignoreError = () => { };
26
59
  request.on("error", ignoreError);
27
- if (request.destroyed || request.readableEnded) {
60
+ if (request.destroyed) {
61
+ // IncomingMessage may emit its terminal error after destroyed becomes true.
28
62
  return;
29
63
  }
30
64
  const cleanup = () => {
65
+ DRAINING_REQUESTS.delete(request);
31
66
  request.off("close", cleanup);
32
67
  request.off("end", cleanup);
33
68
  request.off("error", ignoreError);
@@ -37,6 +72,10 @@ export function drainRequestBody(request) {
37
72
  request.resume();
38
73
  }
39
74
  export async function readBody(request, maxBytes = DEFAULT_MAX_REQUEST_BODY_BYTES) {
75
+ requirePositiveSafeInteger(maxBytes, "maxBytes");
76
+ if (request.aborted) {
77
+ throw new Error("Request body stream was aborted.");
78
+ }
40
79
  const contentLengthHeader = request.headers["content-length"];
41
80
  const contentLengthValue = Array.isArray(contentLengthHeader)
42
81
  ? contentLengthHeader[0]
@@ -90,6 +129,9 @@ export async function readBody(request, maxBytes = DEFAULT_MAX_REQUEST_BODY_BYTE
90
129
  request.on("data", onData);
91
130
  request.on("end", onEnd);
92
131
  request.on("error", onError);
132
+ if (request.aborted) {
133
+ onAborted();
134
+ }
93
135
  });
94
136
  }
95
137
  export async function parseUnknownRequestBody(request, maxBytes = DEFAULT_MAX_REQUEST_BODY_BYTES) {
@@ -98,10 +140,10 @@ export async function parseUnknownRequestBody(request, maxBytes = DEFAULT_MAX_RE
98
140
  return {};
99
141
  }
100
142
  const contentType = request.headers["content-type"] ?? "";
101
- const includesJson = Array.isArray(contentType)
102
- ? contentType.some((entry) => entry.toLowerCase().includes("json"))
103
- : contentType.toLowerCase().includes("json");
104
- if (includesJson) {
143
+ const isJson = Array.isArray(contentType)
144
+ ? contentType.some(isJsonMediaType)
145
+ : isJsonMediaType(contentType);
146
+ if (isJson) {
105
147
  try {
106
148
  return JSON.parse(body.toString("utf8"));
107
149
  }
@@ -112,8 +154,17 @@ export async function parseUnknownRequestBody(request, maxBytes = DEFAULT_MAX_RE
112
154
  const params = new URLSearchParams(body.toString("utf8"));
113
155
  return Object.fromEntries(params.entries());
114
156
  }
157
+ export function isJsonMediaType(value) {
158
+ const mediaType = value.split(";", 1)[0]?.trim().toLowerCase();
159
+ return (mediaType === "application/json" ||
160
+ /^[a-z0-9!#$%&'*+.^_`|~-]+\/[a-z0-9!#$%&'*+.^_`|~-]+\+json$/u.test(mediaType ?? ""));
161
+ }
115
162
  export async function parseRequestBody(request) {
116
- return (await parseUnknownRequestBody(request, Number.MAX_SAFE_INTEGER));
163
+ const body = await parseUnknownRequestBody(request);
164
+ if (!isJsonObject(body)) {
165
+ throw new InvalidJsonBodyError(undefined, "Request body must be a JSON object.");
166
+ }
167
+ return body;
117
168
  }
118
169
  export function isJsonObject(value) {
119
170
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -124,71 +175,171 @@ export function queryRecord(url) {
124
175
  export function formatUrlHost(host) {
125
176
  return host.includes(":") ? `[${host}]` : host;
126
177
  }
127
- export function isLoopbackHost(host) {
128
- const normalized = host
178
+ function normalizeHost(host) {
179
+ return host
129
180
  .trim()
130
181
  .replace(/^\[(.*)\]$/u, "$1")
131
- .toLowerCase();
132
- return (normalized === "localhost" ||
133
- normalized.endsWith(".localhost") ||
134
- normalized === "::1" ||
135
- normalized.startsWith("::ffff:127.") ||
136
- /^127(?:\.\d{1,3}){3}$/u.test(normalized));
182
+ .toLowerCase()
183
+ .replace(/\.$/u, "");
184
+ }
185
+ export function isLoopbackAddress(address) {
186
+ const normalized = normalizeHost(address);
187
+ const family = isIP(normalized);
188
+ return family === 4
189
+ ? LOOPBACK_ADDRESSES.check(normalized, "ipv4")
190
+ : family === 6
191
+ ? LOOPBACK_ADDRESSES.check(normalized, "ipv6")
192
+ : false;
193
+ }
194
+ export function isLoopbackHost(host) {
195
+ const normalized = normalizeHost(host);
196
+ if (normalized === "localhost" || normalized.endsWith(".localhost")) {
197
+ return true;
198
+ }
199
+ return isLoopbackAddress(normalized);
200
+ }
201
+ export function advertisedHostForBindAddress(host, boundAddress) {
202
+ const normalizedBoundAddress = normalizeHost(boundAddress);
203
+ const boundFamily = isIP(normalizedBoundAddress);
204
+ if (boundFamily === 4 && UNSPECIFIED_ADDRESSES.check(normalizedBoundAddress, "ipv4")) {
205
+ return "127.0.0.1";
206
+ }
207
+ if (boundFamily === 6 && UNSPECIFIED_ADDRESSES.check(normalizedBoundAddress, "ipv6")) {
208
+ return "::1";
209
+ }
210
+ return isLoopbackHost(host) && isLoopbackAddress(boundAddress) ? boundAddress : host;
137
211
  }
138
- export async function writeResponse(response, fetchResponse) {
139
- response.statusCode = fetchResponse.status;
212
+ export function assertLoopbackBindAddress(configuredHost, boundAddress, serverName) {
213
+ if (isLoopbackHost(configuredHost) && !isLoopbackAddress(boundAddress)) {
214
+ throw new CrablineError(`${serverName} resolved a loopback hostname to non-loopback address ${boundAddress}.`, { kind: "connectivity" });
215
+ }
216
+ }
217
+ export function writeFetchResponseHeaders(response, fetchResponse) {
218
+ const preserveRepresentationLength = response.req?.method === "HEAD" || fetchResponse.status === 304;
219
+ const connectionHeaders = new Set((fetchResponse.headers.get("connection") ?? "")
220
+ .split(",")
221
+ .map((name) => name.trim().toLowerCase())
222
+ .filter(Boolean));
223
+ if (connectionHeaders.has("close")) {
224
+ response.shouldKeepAlive = false;
225
+ }
140
226
  for (const [name, value] of fetchResponse.headers) {
141
- if (name.toLowerCase() === "set-cookie") {
227
+ const normalizedName = name.toLowerCase();
228
+ if (normalizedName === "set-cookie" ||
229
+ HOP_BY_HOP_RESPONSE_HEADERS.has(normalizedName) ||
230
+ connectionHeaders.has(normalizedName) ||
231
+ (normalizedName === "content-length" && !preserveRepresentationLength)) {
142
232
  continue;
143
233
  }
144
234
  response.setHeader(name, value);
145
235
  }
146
236
  const setCookies = fetchResponse.headers.getSetCookie();
147
- if (setCookies.length > 0) {
237
+ if (setCookies.length > 0 && !connectionHeaders.has("set-cookie")) {
148
238
  response.setHeader("set-cookie", setCookies);
149
239
  }
150
- const body = Buffer.from(await fetchResponse.arrayBuffer());
151
- await new Promise((resolve, reject) => {
240
+ }
241
+ export async function writeResponse(response, fetchResponse, maxBytes = DEFAULT_MAX_RESPONSE_BODY_BYTES) {
242
+ requirePositiveSafeInteger(maxBytes, "maxResponseBodyBytes");
243
+ const reader = fetchResponse.body?.getReader();
244
+ let cancellation;
245
+ let rejectStopped;
246
+ let stoppedError;
247
+ const stopped = new Promise((_, reject) => {
248
+ rejectStopped = reject;
249
+ });
250
+ void stopped.catch(() => { });
251
+ const cancelBody = (reason) => {
252
+ if (!reader || cancellation) {
253
+ return;
254
+ }
255
+ cancellation = reader.cancel(reason).catch(() => { });
256
+ };
257
+ const stop = (error) => {
258
+ if (stoppedError) {
259
+ return;
260
+ }
261
+ stoppedError = error;
262
+ cancelBody(error);
263
+ rejectStopped(error);
264
+ };
265
+ const onClose = () => {
266
+ if (!response.writableFinished) {
267
+ stop(new Error("HTTP response closed before delivery completed."));
268
+ }
269
+ };
270
+ const onError = (error) => stop(error);
271
+ const onRequestAborted = () => stop(new Error("HTTP response request was aborted."));
272
+ response.once("close", onClose);
273
+ response.once("error", onError);
274
+ response.req?.once("aborted", onRequestAborted);
275
+ try {
152
276
  if (response.destroyed ||
153
277
  response.req?.aborted ||
154
278
  response.req?.socket.destroyed ||
155
279
  response.socket?.destroyed) {
156
- reject(new Error("HTTP response closed before delivery completed."));
280
+ throw new Error("HTTP response closed before delivery completed.");
281
+ }
282
+ if (response.req?.method === "HEAD") {
283
+ cancelBody(new Error("HEAD response body is not transferred."));
284
+ response.statusCode = fetchResponse.status;
285
+ writeFetchResponseHeaders(response, fetchResponse);
286
+ let onFinish;
287
+ const finished = new Promise((resolve) => {
288
+ onFinish = resolve;
289
+ response.once("finish", onFinish);
290
+ });
291
+ try {
292
+ response.end();
293
+ await Promise.race([finished, stopped]);
294
+ }
295
+ finally {
296
+ response.off("finish", onFinish);
297
+ }
157
298
  return;
158
299
  }
159
- const cleanup = () => {
160
- response.off("close", onClose);
161
- response.off("error", onError);
162
- response.off("finish", onFinish);
163
- };
164
- const onClose = () => {
165
- if (response.writableFinished) {
166
- cleanup();
167
- resolve();
168
- return;
300
+ const chunks = [];
301
+ let bodyLength = 0;
302
+ if (reader) {
303
+ while (true) {
304
+ const chunk = await Promise.race([reader.read(), stopped]);
305
+ if (chunk.done) {
306
+ break;
307
+ }
308
+ if (chunk.value.byteLength > 0) {
309
+ if (bodyLength + chunk.value.byteLength > maxBytes) {
310
+ throw new ResponseBodyTooLargeError(maxBytes);
311
+ }
312
+ const buffer = Buffer.from(chunk.value);
313
+ chunks.push(buffer);
314
+ bodyLength += buffer.length;
315
+ }
169
316
  }
170
- cleanup();
171
- reject(new Error("HTTP response closed before delivery completed."));
172
- };
173
- const onError = (error) => {
174
- cleanup();
175
- reject(error);
176
- };
177
- const onFinish = () => {
178
- cleanup();
179
- resolve();
180
- };
181
- response.once("close", onClose);
182
- response.once("error", onError);
183
- response.once("finish", onFinish);
317
+ }
318
+ const body = Buffer.concat(chunks, bodyLength);
319
+ response.statusCode = fetchResponse.status;
320
+ writeFetchResponseHeaders(response, fetchResponse);
321
+ let onFinish;
322
+ const finished = new Promise((resolve) => {
323
+ onFinish = resolve;
324
+ response.once("finish", onFinish);
325
+ });
184
326
  try {
185
327
  response.end(body);
328
+ await Promise.race([finished, stopped]);
186
329
  }
187
- catch (error) {
188
- cleanup();
189
- reject(error);
330
+ finally {
331
+ response.off("finish", onFinish);
190
332
  }
191
- });
333
+ }
334
+ catch (error) {
335
+ cancelBody(error instanceof Error ? error : new Error(String(error)));
336
+ throw error;
337
+ }
338
+ finally {
339
+ response.off("close", onClose);
340
+ response.off("error", onError);
341
+ response.req?.off("aborted", onRequestAborted);
342
+ }
192
343
  }
193
344
  export function closeServer(server, graceMs = DEFAULT_SERVER_SHUTDOWN_GRACE_MS) {
194
345
  return new Promise((resolve, reject) => {
@@ -211,12 +362,14 @@ export function closeServer(server, graceMs = DEFAULT_SERVER_SHUTDOWN_GRACE_MS)
211
362
  });
212
363
  }
213
364
  export async function startHttpJsonServer(params) {
365
+ const maxResponseBodyBytes = requirePositiveSafeInteger(params.maxResponseBodyBytes ?? DEFAULT_MAX_RESPONSE_BODY_BYTES, "maxResponseBodyBytes");
214
366
  const handleRequest = async (request, response) => {
215
367
  try {
216
368
  const result = await params.handle(request, response);
369
+ drainRequestBody(request);
217
370
  const handled = result instanceof Response ? { response: result } : result;
218
371
  try {
219
- await writeResponse(response, handled.response);
372
+ await writeResponse(response, handled.response, maxResponseBodyBytes);
220
373
  }
221
374
  catch (error) {
222
375
  await handled.onWriteFailure?.();
@@ -230,6 +383,7 @@ export async function startHttpJsonServer(params) {
230
383
  }
231
384
  }
232
385
  catch (error) {
386
+ drainRequestBody(request);
233
387
  let handled;
234
388
  try {
235
389
  handled = params.handleError?.(error, request);
@@ -242,7 +396,7 @@ export async function startHttpJsonServer(params) {
242
396
  jsonResponse({
243
397
  error: "internal server error",
244
398
  ok: false,
245
- }, 500));
399
+ }, 500), maxResponseBodyBytes);
246
400
  }
247
401
  catch {
248
402
  response.destroy();
@@ -265,14 +419,28 @@ export async function startHttpJsonServer(params) {
265
419
  kind: "connectivity",
266
420
  });
267
421
  }
422
+ try {
423
+ assertLoopbackBindAddress(params.host, address.address, params.serverName);
424
+ }
425
+ catch (error) {
426
+ await closeServer(server);
427
+ throw error;
428
+ }
429
+ const advertisedHost = advertisedHostForBindAddress(params.host, address.address);
268
430
  return {
269
- baseUrl: `http://${formatUrlHost(params.host)}:${address.port}`,
431
+ baseUrl: `http://${formatUrlHost(advertisedHost)}:${address.port}`,
270
432
  async close() {
271
433
  await closeServer(server);
272
434
  },
273
435
  server,
274
436
  };
275
437
  }
438
+ function requirePositiveSafeInteger(value, name) {
439
+ if (!Number.isSafeInteger(value) || value <= 0) {
440
+ throw new RangeError(`${name} must be a positive safe integer.`);
441
+ }
442
+ return value;
443
+ }
276
444
  export function readString(value) {
277
445
  if (typeof value === "string" && value.length > 0) {
278
446
  return value;
@@ -304,6 +472,11 @@ function readBearerToken(authorization) {
304
472
  }
305
473
  return trimmed.slice(7);
306
474
  }
475
+ export function constantTimeTokenEqual(providedToken, expectedToken) {
476
+ const provided = createHash("sha256").update(providedToken).digest();
477
+ const expected = createHash("sha256").update(expectedToken).digest();
478
+ return timingSafeEqual(provided, expected);
479
+ }
307
480
  export function hasAdminToken(request, expectedToken) {
308
481
  const header = request.headers[ADMIN_TOKEN_HEADER];
309
482
  const directToken = Array.isArray(header) ? header[0] : header;
@@ -311,9 +484,7 @@ export function hasAdminToken(request, expectedToken) {
311
484
  if (!providedToken) {
312
485
  return false;
313
486
  }
314
- const provided = Buffer.from(providedToken);
315
- const expected = Buffer.from(expectedToken);
316
- return provided.length === expected.length && timingSafeEqual(provided, expected);
487
+ return constantTimeTokenEqual(providedToken, expectedToken);
317
488
  }
318
489
  export function adminAuthError() {
319
490
  return new Response("unauthorized", {