@openclaw/crabline 0.1.10 → 0.1.12

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 (197) hide show
  1. package/README.md +99 -12
  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 +264 -50
  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/matrix-ids.d.ts +5 -0
  31. package/dist/src/matrix-ids.js +83 -0
  32. package/dist/src/matrix-ids.js.map +1 -0
  33. package/dist/src/openclaw/artifact-generation.d.ts +12 -2
  34. package/dist/src/openclaw/artifact-generation.js +436 -15
  35. package/dist/src/openclaw/artifact-generation.js.map +1 -1
  36. package/dist/src/openclaw/bridges/matrix.js +21 -4
  37. package/dist/src/openclaw/bridges/matrix.js.map +1 -1
  38. package/dist/src/openclaw/bridges/mattermost.js +13 -8
  39. package/dist/src/openclaw/bridges/mattermost.js.map +1 -1
  40. package/dist/src/openclaw/bridges/probe-response.d.ts +1 -0
  41. package/dist/src/openclaw/bridges/probe-response.js +5 -0
  42. package/dist/src/openclaw/bridges/probe-response.js.map +1 -0
  43. package/dist/src/openclaw/bridges/signal.js +15 -6
  44. package/dist/src/openclaw/bridges/signal.js.map +1 -1
  45. package/dist/src/openclaw/bridges/slack.js +116 -23
  46. package/dist/src/openclaw/bridges/slack.js.map +1 -1
  47. package/dist/src/openclaw/bridges/telegram.js +45 -19
  48. package/dist/src/openclaw/bridges/telegram.js.map +1 -1
  49. package/dist/src/openclaw/bridges/whatsapp.js +32 -16
  50. package/dist/src/openclaw/bridges/whatsapp.js.map +1 -1
  51. package/dist/src/openclaw/bridges/zalo.js +8 -3
  52. package/dist/src/openclaw/bridges/zalo.js.map +1 -1
  53. package/dist/src/openclaw/private-file.d.ts +40 -3
  54. package/dist/src/openclaw/private-file.js +2070 -95
  55. package/dist/src/openclaw/private-file.js.map +1 -1
  56. package/dist/src/openclaw/shared.d.ts +1 -0
  57. package/dist/src/openclaw/shared.js +48 -13
  58. package/dist/src/openclaw/shared.js.map +1 -1
  59. package/dist/src/openclaw/smoke-lock.d.ts +9 -0
  60. package/dist/src/openclaw/smoke-lock.js +696 -187
  61. package/dist/src/openclaw/smoke-lock.js.map +1 -1
  62. package/dist/src/openclaw.js +352 -29
  63. package/dist/src/openclaw.js.map +1 -1
  64. package/dist/src/platform/process-owned-lock.d.ts +11 -0
  65. package/dist/src/platform/process-owned-lock.js +1698 -0
  66. package/dist/src/platform/process-owned-lock.js.map +1 -0
  67. package/dist/src/platform/recorder-directory.d.ts +1 -0
  68. package/dist/src/platform/recorder-directory.js +14 -0
  69. package/dist/src/platform/recorder-directory.js.map +1 -0
  70. package/dist/src/platform/windows-acl.d.ts +18 -0
  71. package/dist/src/platform/windows-acl.js +1367 -0
  72. package/dist/src/platform/windows-acl.js.map +1 -0
  73. package/dist/src/platform/windows-lock-root.d.ts +13 -0
  74. package/dist/src/platform/windows-lock-root.js +98 -0
  75. package/dist/src/platform/windows-lock-root.js.map +1 -0
  76. package/dist/src/providers/builtin/discord.d.ts +4 -0
  77. package/dist/src/providers/builtin/discord.js +52 -9
  78. package/dist/src/providers/builtin/discord.js.map +1 -1
  79. package/dist/src/providers/builtin/external-webhook-auth.d.ts +1 -0
  80. package/dist/src/providers/builtin/external-webhook-auth.js +38 -1
  81. package/dist/src/providers/builtin/external-webhook-auth.js.map +1 -1
  82. package/dist/src/providers/builtin/feishu.d.ts +1 -0
  83. package/dist/src/providers/builtin/feishu.js +96 -26
  84. package/dist/src/providers/builtin/feishu.js.map +1 -1
  85. package/dist/src/providers/builtin/googlechat.d.ts +1 -0
  86. package/dist/src/providers/builtin/googlechat.js +95 -26
  87. package/dist/src/providers/builtin/googlechat.js.map +1 -1
  88. package/dist/src/providers/builtin/imessage.js +60 -17
  89. package/dist/src/providers/builtin/imessage.js.map +1 -1
  90. package/dist/src/providers/builtin/loopback.js +88 -35
  91. package/dist/src/providers/builtin/loopback.js.map +1 -1
  92. package/dist/src/providers/builtin/matrix.d.ts +2 -2
  93. package/dist/src/providers/builtin/matrix.js +78 -21
  94. package/dist/src/providers/builtin/matrix.js.map +1 -1
  95. package/dist/src/providers/builtin/mattermost.d.ts +11 -7
  96. package/dist/src/providers/builtin/mattermost.js +138 -24
  97. package/dist/src/providers/builtin/mattermost.js.map +1 -1
  98. package/dist/src/providers/builtin/msteams.d.ts +1 -0
  99. package/dist/src/providers/builtin/msteams.js +118 -38
  100. package/dist/src/providers/builtin/msteams.js.map +1 -1
  101. package/dist/src/providers/builtin/native-local-mock.js +4 -4
  102. package/dist/src/providers/builtin/native-local-mock.js.map +1 -1
  103. package/dist/src/providers/builtin/script.js +1057 -146
  104. package/dist/src/providers/builtin/script.js.map +1 -1
  105. package/dist/src/providers/builtin/slack.d.ts +8 -1
  106. package/dist/src/providers/builtin/slack.js +327 -24
  107. package/dist/src/providers/builtin/slack.js.map +1 -1
  108. package/dist/src/providers/builtin/telegram.d.ts +1 -1
  109. package/dist/src/providers/builtin/telegram.js +55 -14
  110. package/dist/src/providers/builtin/telegram.js.map +1 -1
  111. package/dist/src/providers/builtin/whatsapp.d.ts +4 -3
  112. package/dist/src/providers/builtin/whatsapp.js +157 -29
  113. package/dist/src/providers/builtin/whatsapp.js.map +1 -1
  114. package/dist/src/providers/builtin/zalo.d.ts +5 -2
  115. package/dist/src/providers/builtin/zalo.js +31 -7
  116. package/dist/src/providers/builtin/zalo.js.map +1 -1
  117. package/dist/src/providers/catalog.d.ts +1 -1
  118. package/dist/src/providers/catalog.js +1 -1
  119. package/dist/src/providers/catalog.js.map +1 -1
  120. package/dist/src/providers/local-mock.d.ts +4 -0
  121. package/dist/src/providers/local-mock.js +162 -35
  122. package/dist/src/providers/local-mock.js.map +1 -1
  123. package/dist/src/providers/native-ids.d.ts +2 -0
  124. package/dist/src/providers/native-ids.js +3 -0
  125. package/dist/src/providers/native-ids.js.map +1 -1
  126. package/dist/src/providers/recorder.d.ts +14 -3
  127. package/dist/src/providers/recorder.js +532 -42
  128. package/dist/src/providers/recorder.js.map +1 -1
  129. package/dist/src/providers/registry.d.ts +1 -0
  130. package/dist/src/providers/registry.js +65 -20
  131. package/dist/src/providers/registry.js.map +1 -1
  132. package/dist/src/providers/signed-jwt.d.ts +6 -1
  133. package/dist/src/providers/signed-jwt.js +241 -50
  134. package/dist/src/providers/signed-jwt.js.map +1 -1
  135. package/dist/src/providers/slack-ids.d.ts +1 -0
  136. package/dist/src/providers/slack-ids.js +5 -0
  137. package/dist/src/providers/slack-ids.js.map +1 -1
  138. package/dist/src/providers/target-normalizers.d.ts +9 -1
  139. package/dist/src/providers/target-normalizers.js +177 -58
  140. package/dist/src/providers/target-normalizers.js.map +1 -1
  141. package/dist/src/providers/webhook-server.d.ts +3 -0
  142. package/dist/src/providers/webhook-server.js +268 -47
  143. package/dist/src/providers/webhook-server.js.map +1 -1
  144. package/dist/src/servers/http.d.ts +14 -2
  145. package/dist/src/servers/http.js +229 -58
  146. package/dist/src/servers/http.js.map +1 -1
  147. package/dist/src/servers/matrix.d.ts +3 -0
  148. package/dist/src/servers/matrix.js +268 -110
  149. package/dist/src/servers/matrix.js.map +1 -1
  150. package/dist/src/servers/mattermost.d.ts +5 -0
  151. package/dist/src/servers/mattermost.js +389 -91
  152. package/dist/src/servers/mattermost.js.map +1 -1
  153. package/dist/src/servers/recorder.d.ts +11 -0
  154. package/dist/src/servers/recorder.js +1241 -22
  155. package/dist/src/servers/recorder.js.map +1 -1
  156. package/dist/src/servers/signal.d.ts +1 -0
  157. package/dist/src/servers/signal.js +279 -44
  158. package/dist/src/servers/signal.js.map +1 -1
  159. package/dist/src/servers/slack.d.ts +15 -0
  160. package/dist/src/servers/slack.js +259 -51
  161. package/dist/src/servers/slack.js.map +1 -1
  162. package/dist/src/servers/telegram-identity.d.ts +6 -0
  163. package/dist/src/servers/telegram-identity.js +27 -0
  164. package/dist/src/servers/telegram-identity.js.map +1 -0
  165. package/dist/src/servers/telegram.d.ts +17 -6
  166. package/dist/src/servers/telegram.js +1193 -118
  167. package/dist/src/servers/telegram.js.map +1 -1
  168. package/dist/src/servers/webhook-target.d.ts +12 -4
  169. package/dist/src/servers/webhook-target.js +226 -28
  170. package/dist/src/servers/webhook-target.js.map +1 -1
  171. package/dist/src/servers/whatsapp-baileys-websocket.d.ts +60 -1
  172. package/dist/src/servers/whatsapp-baileys-websocket.js +782 -112
  173. package/dist/src/servers/whatsapp-baileys-websocket.js.map +1 -1
  174. package/dist/src/servers/whatsapp-jid.d.ts +1 -0
  175. package/dist/src/servers/whatsapp-jid.js +9 -5
  176. package/dist/src/servers/whatsapp-jid.js.map +1 -1
  177. package/dist/src/servers/whatsapp-wire/binary-node.d.ts +1 -0
  178. package/dist/src/servers/whatsapp-wire/binary-node.js +37 -13
  179. package/dist/src/servers/whatsapp-wire/binary-node.js.map +1 -1
  180. package/dist/src/servers/whatsapp-wire/crypto.d.ts +3 -0
  181. package/dist/src/servers/whatsapp-wire/crypto.js +23 -8
  182. package/dist/src/servers/whatsapp-wire/crypto.js.map +1 -1
  183. package/dist/src/servers/whatsapp-wire/handshake.d.ts +9 -3
  184. package/dist/src/servers/whatsapp-wire/handshake.js +173 -12
  185. package/dist/src/servers/whatsapp-wire/handshake.js.map +1 -1
  186. package/dist/src/servers/whatsapp-wire/signal.js +3 -3
  187. package/dist/src/servers/whatsapp-wire/signal.js.map +1 -1
  188. package/dist/src/servers/whatsapp.d.ts +7 -0
  189. package/dist/src/servers/whatsapp.js +149 -24
  190. package/dist/src/servers/whatsapp.js.map +1 -1
  191. package/dist/src/servers/zalo.d.ts +1 -0
  192. package/dist/src/servers/zalo.js +193 -82
  193. package/dist/src/servers/zalo.js.map +1 -1
  194. package/docs/channel-setup.md +185 -43
  195. package/fixtures/examples/crabline.example.yaml +3 -2
  196. package/package.json +18 -10
  197. package/fixtures/examples/openclaw-bridge.yaml +0 -125
@@ -1 +1 @@
1
- {"version":3,"file":"target-normalizers.js","sourceRoot":"","sources":["../../../src/providers/target-normalizers.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BuiltinAdapterId, FixtureDefinition, ProviderPlatform } from \"../config/schema.js\";\nimport { CrablineError } from \"../core/errors.js\";\nimport type { LocalMockTargetCodec } from \"./local-mock.js\";\nimport type { NativeIdRule } from \"./native-ids.js\";\nimport { slackTargetKey, SLACK_SEND_TARGET_ID_RULE, SLACK_TS_RULE } from \"./slack-ids.js\";\nimport type { NormalizedTarget } from \"./types.js\";\n\nexport type BuiltinProviderAdapterId = Exclude<BuiltinAdapterId, \"script\">;\n\nexport const DISCORD_SNOWFLAKE_RULE: NativeIdRule = {\n example: \"123456789012345678\",\n name: \"Discord snowflake id\",\n pattern: /^\\d{17,20}$/u,\n};\n\nexport const FEISHU_CHAT_ID_RULE: NativeIdRule = {\n example: \"oc_abc123\",\n name: \"Feishu chat_id\",\n pattern: /^oc_[A-Za-z0-9_-]+$/u,\n};\n\nexport const FEISHU_MESSAGE_ID_RULE: NativeIdRule = {\n example: \"om_abc123\",\n name: \"Feishu message_id\",\n pattern: /^om_[A-Za-z0-9_-]+$/u,\n};\n\nexport const GOOGLE_CHAT_SPACE_RULE: NativeIdRule = {\n example: \"spaces/AAAABbbbCCC\",\n name: \"Google Chat space name\",\n pattern: /^spaces\\/[A-Za-z0-9_-]+$/u,\n};\n\nexport const GOOGLE_CHAT_THREAD_RULE: NativeIdRule = {\n example: \"spaces/AAAABbbbCCC/threads/BBBBccccDDD\",\n name: \"Google Chat thread name\",\n pattern: /^spaces\\/[A-Za-z0-9_-]+\\/threads\\/[A-Za-z0-9_-]+$/u,\n};\n\nexport const IMESSAGE_THREAD_RULE: NativeIdRule = {\n example: \"+15551234567, user@example.com, or iMessage;-;chat-guid\",\n name: \"iMessage recipient or chat GUID\",\n pattern:\n /^(?:\\+[1-9]\\d{6,14}|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}|(?:iMessage|SMS);[+-];.+)$/u,\n};\n\nexport const MATRIX_ROOM_ID_RULE: NativeIdRule = {\n example: \"!abcdef:matrix.org\",\n name: \"Matrix room id\",\n pattern: /^!(?:[^:\\s]+:[^\\s]+|[A-Za-z0-9_-]{43})$/u,\n};\n\nexport const MATRIX_EVENT_ID_RULE: NativeIdRule = {\n example: \"$eventid:matrix.org\",\n name: \"Matrix event id\",\n pattern: /^\\$[^\\s]+(?::[^\\s]+)?$/u,\n};\n\nexport const MATTERMOST_ID_RULE: NativeIdRule = {\n example: \"abcdefghijklmnopqrstuvwx12\",\n name: \"Mattermost id\",\n pattern: /^[a-z0-9]{26}$/u,\n};\n\nexport const MSTEAMS_CONVERSATION_ID_RULE: NativeIdRule = {\n example: \"a:opaque-conversation-id\",\n name: \"Microsoft Teams conversation id\",\n pattern: /^.+$/su,\n};\n\nexport const TELEGRAM_CHAT_ID_RULE: NativeIdRule = {\n example: \"-1001234567890 or @channelusername\",\n name: \"Telegram chat id\",\n pattern: /^(?:-?[1-9]\\d*|@[A-Za-z][A-Za-z0-9_]{3,31})$/u,\n};\n\nexport const TELEGRAM_MESSAGE_THREAD_ID_RULE: NativeIdRule = {\n example: \"42\",\n name: \"Telegram message_thread_id\",\n pattern: /^[1-9]\\d*$/u,\n};\n\nexport const WHATSAPP_WA_ID_RULE: NativeIdRule = {\n example: \"15551234567\",\n name: \"WhatsApp wa_id\",\n pattern: /^\\d{7,15}$/u,\n};\n\nexport const ZALO_ID_RULE: NativeIdRule = {\n example: \"user-1\",\n name: \"Zalo string id\",\n pattern: /^\\S+$/u,\n};\n\nfunction requireNativeId(value: string, rule: NativeIdRule, label: string): string {\n if (!rule.pattern.test(value)) {\n throw new CrablineError(`${label} must be a native ${rule.name} such as ${rule.example}.`, {\n kind: \"config\",\n });\n }\n return value;\n}\n\nfunction createNativeTargetCodec(options: {\n channel: NativeIdRule;\n channelLabel?: string | undefined;\n thread?: NativeIdRule | undefined;\n threadLabel?: string | undefined;\n}): LocalMockTargetCodec {\n const channelLabel = options.channelLabel ?? \"channelId\";\n const threadLabel = options.threadLabel ?? \"threadId\";\n const threadRule = options.thread ?? options.channel;\n\n return {\n normalize(target): NormalizedTarget {\n const channelId = requireNativeId(\n target.channelId ?? target.id,\n options.channel,\n channelLabel,\n );\n const normalized: NormalizedTarget = {\n channelId,\n id: target.id,\n metadata: target.metadata,\n };\n if (target.threadId) {\n normalized.threadId = requireNativeId(target.threadId, threadRule, threadLabel);\n }\n return normalized;\n },\n resolveThreadId(target) {\n const normalized = this.normalize(target);\n return normalized.threadId ?? normalized.channelId ?? normalized.id;\n },\n };\n}\n\nexport function createGenericLocalMockTargetCodec(\n platform: ProviderPlatform,\n): LocalMockTargetCodec {\n const prefix = `${platform}:`;\n const encode = (value: string) => (value.startsWith(prefix) ? value : `${prefix}${value}`);\n return {\n normalize(target): NormalizedTarget {\n const normalized: NormalizedTarget = {\n id: target.id,\n metadata: target.metadata,\n };\n if (target.channelId) {\n normalized.channelId = encode(target.channelId);\n } else if (!target.threadId) {\n normalized.channelId = encode(target.id);\n }\n if (target.threadId) {\n normalized.channelId ??= encode(target.id);\n if (\n target.threadId.startsWith(prefix) &&\n !target.threadId.startsWith(`${normalized.channelId}:`)\n ) {\n throw new CrablineError(\n `${platform} canonical thread parent must match the target channel.`,\n { kind: \"config\" },\n );\n }\n normalized.threadId = target.threadId.startsWith(prefix)\n ? target.threadId\n : `${normalized.channelId}:${target.threadId}`;\n }\n return normalized;\n },\n resolveThreadId(target) {\n const normalized = this.normalize(target);\n return normalized.threadId ?? normalized.channelId ?? encode(normalized.id);\n },\n };\n}\n\nfunction requireSlackSendTargetId(value: string, label: string): string {\n if (!SLACK_SEND_TARGET_ID_RULE.pattern.test(value)) {\n throw new CrablineError(\n `Slack ${label} must be a native Slack conversation or user id such as C1234567890, G1234567890, D1234567890, U1234567890, or W1234567890.`,\n { kind: \"config\" },\n );\n }\n return value;\n}\n\nfunction requireSlackThreadTs(value: string, label: string): string {\n if (!SLACK_TS_RULE.pattern.test(value)) {\n throw new CrablineError(`Slack ${label} must be a Slack timestamp such as 1700000000.000100.`, {\n kind: \"config\",\n });\n }\n return value;\n}\n\nconst SLACK_TARGET_CODEC: LocalMockTargetCodec = {\n normalize(target): NormalizedTarget {\n const channelId = requireSlackSendTargetId(target.channelId ?? target.id, \"channelId\");\n const normalized: NormalizedTarget = {\n channelId,\n id: target.id,\n metadata: target.metadata,\n };\n if (target.threadId) {\n normalized.threadId = requireSlackThreadTs(target.threadId, \"threadId\");\n }\n return normalized;\n },\n resolveThreadId(target) {\n const normalized = this.normalize(target);\n const channelId = normalized.channelId ?? normalized.id;\n return slackTargetKey(channelId, normalized.threadId);\n },\n};\n\nconst TELEGRAM_BASE_CODEC = createNativeTargetCodec({\n channel: TELEGRAM_CHAT_ID_RULE,\n channelLabel: \"Telegram chat_id\",\n thread: TELEGRAM_MESSAGE_THREAD_ID_RULE,\n threadLabel: \"Telegram message_thread_id\",\n});\n\nexport function parseCanonicalTelegramTopic(\n value: string,\n): { chatId: string; topicId: string } | undefined {\n const separator = value.lastIndexOf(\":\");\n if (separator <= 0) {\n return undefined;\n }\n const chatId = value.slice(0, separator);\n const topicId = value.slice(separator + 1);\n if (\n !TELEGRAM_CHAT_ID_RULE.pattern.test(chatId) ||\n !TELEGRAM_MESSAGE_THREAD_ID_RULE.pattern.test(topicId)\n ) {\n return undefined;\n }\n return { chatId, topicId };\n}\n\nconst TELEGRAM_TARGET_CODEC: LocalMockTargetCodec = {\n normalize(target) {\n const canonicalTopic = target.threadId\n ? parseCanonicalTelegramTopic(target.threadId)\n : undefined;\n const targetChatId = target.channelId ?? target.id;\n if (\n canonicalTopic &&\n requireNativeId(targetChatId, TELEGRAM_CHAT_ID_RULE, \"Telegram chat_id\") !==\n canonicalTopic.chatId\n ) {\n throw new CrablineError(\"Telegram canonical topic chat_id must match the target chat_id.\", {\n kind: \"config\",\n });\n }\n const normalized = TELEGRAM_BASE_CODEC.normalize({\n ...target,\n ...(canonicalTopic ? { channelId: canonicalTopic.chatId } : {}),\n threadId: undefined,\n });\n if (!target.threadId) {\n return normalized;\n }\n const topicId = requireNativeId(\n canonicalTopic?.topicId ?? target.threadId,\n TELEGRAM_MESSAGE_THREAD_ID_RULE,\n \"Telegram message_thread_id\",\n );\n return {\n ...normalized,\n threadId: `${normalized.channelId}:${topicId}`,\n };\n },\n resolveThreadId(target) {\n const normalized = this.normalize(target);\n return normalized.threadId ?? normalized.channelId ?? normalized.id;\n },\n};\n\nconst BUILTIN_TARGET_CODECS = {\n discord: createNativeTargetCodec({\n channel: DISCORD_SNOWFLAKE_RULE,\n channelLabel: \"Discord channel_id\",\n thread: DISCORD_SNOWFLAKE_RULE,\n threadLabel: \"Discord thread id\",\n }),\n feishu: createNativeTargetCodec({\n channel: FEISHU_CHAT_ID_RULE,\n channelLabel: \"Feishu chat_id\",\n thread: FEISHU_MESSAGE_ID_RULE,\n threadLabel: \"Feishu message_id\",\n }),\n googlechat: createNativeTargetCodec({\n channel: GOOGLE_CHAT_SPACE_RULE,\n channelLabel: \"Google Chat space.name\",\n thread: GOOGLE_CHAT_THREAD_RULE,\n threadLabel: \"Google Chat thread.name\",\n }),\n imessage: createNativeTargetCodec({\n channel: IMESSAGE_THREAD_RULE,\n channelLabel: \"iMessage recipient or chat GUID\",\n }),\n loopback: createGenericLocalMockTargetCodec(\"loopback\"),\n matrix: createNativeTargetCodec({\n channel: MATRIX_ROOM_ID_RULE,\n channelLabel: \"Matrix room_id\",\n thread: MATRIX_EVENT_ID_RULE,\n threadLabel: \"Matrix event_id\",\n }),\n mattermost: createNativeTargetCodec({\n channel: MATTERMOST_ID_RULE,\n channelLabel: \"Mattermost channel_id\",\n }),\n msteams: createNativeTargetCodec({\n channel: MSTEAMS_CONVERSATION_ID_RULE,\n channelLabel: \"Microsoft Teams conversation.id\",\n }),\n slack: SLACK_TARGET_CODEC,\n telegram: TELEGRAM_TARGET_CODEC,\n whatsapp: createNativeTargetCodec({\n channel: WHATSAPP_WA_ID_RULE,\n channelLabel: \"WhatsApp wa_id\",\n }),\n zalo: createNativeTargetCodec({\n channel: ZALO_ID_RULE,\n channelLabel: \"Zalo user_id or oa_id\",\n }),\n} satisfies Record<BuiltinProviderAdapterId, LocalMockTargetCodec>;\n\nexport function getBuiltinTargetCodec(adapter: BuiltinProviderAdapterId): LocalMockTargetCodec {\n return BUILTIN_TARGET_CODECS[adapter];\n}\n\nexport function normalizeBuiltinTarget(\n adapter: BuiltinProviderAdapterId,\n target: FixtureDefinition[\"target\"],\n): NormalizedTarget {\n return getBuiltinTargetCodec(adapter).normalize(target);\n}\n"]}
1
+ {"version":3,"file":"target-normalizers.js","sourceRoot":"","sources":["../../../src/providers/target-normalizers.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BuiltinAdapterId, FixtureDefinition, ProviderPlatform } from \"../config/schema.js\";\nimport { CrablineError } from \"../core/errors.js\";\nimport { isMatrixEventId, isMatrixRoomId } from \"../matrix-ids.js\";\nimport {\n canonicalizeTelegramUsername,\n TELEGRAM_NATIVE_CHAT_ID_MAX,\n} from \"../servers/telegram-identity.js\";\nimport type { LocalMockTargetCodec } from \"./local-mock.js\";\nimport { matchesNativeId, type NativeIdRule } from \"./native-ids.js\";\nimport { slackTargetKey, SLACK_SEND_TARGET_ID_RULE, SLACK_TS_RULE } from \"./slack-ids.js\";\nimport type { NormalizedTarget } from \"./types.js\";\n\nexport type BuiltinProviderAdapterId = Exclude<BuiltinAdapterId, \"script\">;\n\nexport const DISCORD_SNOWFLAKE_RULE: NativeIdRule = {\n example: \"123456789012345678\",\n name: \"Discord snowflake id\",\n pattern: /^[1-9]\\d{0,19}$/u,\n validate: (value) => BigInt(value) <= 18_446_744_073_709_551_615n,\n};\n\nexport const FEISHU_CHAT_ID_RULE: NativeIdRule = {\n example: \"oc_abc123\",\n name: \"Feishu chat_id\",\n pattern: /^oc_[A-Za-z0-9_-]+$/u,\n};\n\nexport const FEISHU_MESSAGE_ID_RULE: NativeIdRule = {\n example: \"om_abc123\",\n name: \"Feishu message_id\",\n pattern: /^om_[A-Za-z0-9_-]+$/u,\n};\n\nexport const GOOGLE_CHAT_SPACE_RULE: NativeIdRule = {\n example: \"spaces/AAAABbbbCCC\",\n name: \"Google Chat space name\",\n pattern: /^spaces\\/[A-Za-z0-9_-]+$/u,\n};\n\nexport const GOOGLE_CHAT_THREAD_RULE: NativeIdRule = {\n example: \"spaces/AAAABbbbCCC/threads/BBBBccccDDD\",\n name: \"Google Chat thread name\",\n pattern: /^spaces\\/[A-Za-z0-9_-]+\\/threads\\/[A-Za-z0-9_-]+$/u,\n};\n\nexport const IMESSAGE_THREAD_RULE: NativeIdRule = {\n example: \"+15551234567, user@example.com, or iMessage;-;chat-guid\",\n name: \"iMessage recipient or chat GUID\",\n pattern:\n /^(?:\\+[1-9]\\d{6,14}|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}|(?:iMessage|SMS);[+-];.+)$/u,\n};\n\nexport const MATRIX_ROOM_ID_RULE: NativeIdRule = {\n example: \"!abcdef:matrix.org\",\n name: \"Matrix room id\",\n pattern: /^!/u,\n validate: isMatrixRoomId,\n};\n\nexport const MATRIX_EVENT_ID_RULE: NativeIdRule = {\n example: \"$eventid:matrix.org\",\n name: \"Matrix event id\",\n pattern: /^\\$/u,\n validate: isMatrixEventId,\n};\n\nexport { isMatrixEventId, isMatrixRoomId } from \"../matrix-ids.js\";\n\nexport const MATTERMOST_ID_RULE: NativeIdRule = {\n example: \"abcdefghijklmnopqrstuvwx12\",\n name: \"Mattermost id\",\n pattern: /^[a-z0-9]{26}$/u,\n};\n\nexport const MSTEAMS_CONVERSATION_ID_RULE: NativeIdRule = {\n example: \"a:opaque-conversation-id\",\n name: \"Microsoft Teams conversation id\",\n pattern: /^.+$/su,\n};\n\nexport const TELEGRAM_CHAT_ID_RULE: NativeIdRule = {\n example: \"-1001234567890 or @channelusername\",\n name: \"Telegram chat id\",\n pattern: /^(?:-?[1-9]\\d*|@[A-Za-z][A-Za-z0-9_]{4,31})$/u,\n validate: (value) =>\n value.startsWith(\"@\") || BigInt(value.replace(/^-/u, \"\")) <= TELEGRAM_NATIVE_CHAT_ID_MAX,\n};\n\nexport const TELEGRAM_INBOUND_CHAT_ID_RULE: NativeIdRule = {\n example: \"-1001234567890\",\n name: \"Telegram inbound chat id\",\n pattern: /^-?[1-9]\\d*$/u,\n validate: (value) => BigInt(value.replace(/^-/u, \"\")) <= TELEGRAM_NATIVE_CHAT_ID_MAX,\n};\n\nexport const TELEGRAM_MESSAGE_THREAD_ID_RULE: NativeIdRule = {\n example: \"42\",\n name: \"Telegram message_thread_id\",\n pattern: /^[1-9]\\d*$/u,\n validate: (value) => BigInt(value) <= BigInt(Number.MAX_SAFE_INTEGER),\n};\n\nexport const WHATSAPP_WA_ID_RULE: NativeIdRule = {\n example: \"15551234567\",\n name: \"WhatsApp wa_id\",\n pattern: /^\\d{7,15}$/u,\n};\n\nexport const ZALO_ID_RULE: NativeIdRule = {\n example: \"user-1\",\n name: \"Zalo string id\",\n pattern: /^\\S+$/u,\n};\n\nexport const ZALO_UNSUPPORTED_THREAD_TARGET_ERROR = \"Zalo does not support thread targets.\";\nexport const WHATSAPP_UNSUPPORTED_THREAD_TARGET_ERROR = \"WhatsApp does not support thread targets.\";\n\nfunction requireNativeId(value: string, rule: NativeIdRule, label: string): string {\n if (!matchesNativeId(value, rule)) {\n throw new CrablineError(`${label} must be a native ${rule.name} such as ${rule.example}.`, {\n kind: \"config\",\n });\n }\n return value;\n}\n\nfunction createNativeTargetCodec(options: {\n channel: NativeIdRule;\n channelLabel?: string | undefined;\n thread?: NativeIdRule | undefined;\n threadLabel?: string | undefined;\n}): LocalMockTargetCodec {\n const channelLabel = options.channelLabel ?? \"channelId\";\n const threadLabel = options.threadLabel ?? \"threadId\";\n const threadRule = options.thread ?? options.channel;\n\n return {\n normalize(target): NormalizedTarget {\n const channelId = requireNativeId(\n target.channelId ?? target.id,\n options.channel,\n channelLabel,\n );\n const normalized: NormalizedTarget = {\n channelId,\n id: target.id,\n metadata: target.metadata,\n };\n if (target.threadId) {\n normalized.threadId = requireNativeId(target.threadId, threadRule, threadLabel);\n }\n return normalized;\n },\n resolveThreadId(target) {\n const normalized = this.normalize(target);\n return normalized.threadId ?? normalized.channelId ?? normalized.id;\n },\n };\n}\n\nexport function createGenericLocalMockTargetCodec(\n platform: ProviderPlatform,\n): LocalMockTargetCodec {\n const prefix = `${platform}:`;\n const encodeComponent = (value: string, label: string) => {\n try {\n return encodeURIComponent(value);\n } catch (error) {\n throw new CrablineError(`${platform} ${label} cannot be encoded.`, {\n cause: error,\n kind: \"config\",\n });\n }\n };\n const requireCanonicalComponent = (value: string, label: string) => {\n try {\n if (\n !value ||\n value.includes(\":\") ||\n encodeURIComponent(decodeURIComponent(value)) !== value\n ) {\n throw new Error(\"non-canonical component\");\n }\n } catch (error) {\n throw new CrablineError(`${platform} canonical ${label} is malformed.`, {\n cause: error,\n kind: \"config\",\n });\n }\n };\n const normalizeChannel = (value: string) => {\n if (!value) {\n throw new CrablineError(`${platform} channelId must not be empty.`, { kind: \"config\" });\n }\n if (!value.startsWith(prefix)) {\n return `${prefix}${encodeComponent(value, \"channelId\")}`;\n }\n requireCanonicalComponent(value.slice(prefix.length), \"channelId\");\n return value;\n };\n return {\n normalize(target): NormalizedTarget {\n const channelId = normalizeChannel(target.channelId ?? target.id);\n const normalized: NormalizedTarget = {\n channelId,\n id: target.id,\n metadata: target.metadata,\n };\n if (target.threadId) {\n if (target.threadId.startsWith(prefix)) {\n const canonicalPrefix = `${channelId}:`;\n if (!target.threadId.startsWith(canonicalPrefix)) {\n throw new CrablineError(\n `${platform} canonical thread parent must match the target channel.`,\n { kind: \"config\" },\n );\n }\n requireCanonicalComponent(target.threadId.slice(canonicalPrefix.length), \"threadId\");\n normalized.threadId = target.threadId;\n } else {\n normalized.threadId = `${channelId}:${encodeComponent(target.threadId, \"threadId\")}`;\n }\n }\n return normalized;\n },\n resolveThreadId(target) {\n const normalized = this.normalize(target);\n return normalized.threadId ?? normalized.channelId ?? normalizeChannel(normalized.id);\n },\n };\n}\n\nfunction requireSlackSendTargetId(value: string, label: string): string {\n if (!SLACK_SEND_TARGET_ID_RULE.pattern.test(value)) {\n throw new CrablineError(\n `Slack ${label} must be a native Slack conversation or user id such as C1234567890, G1234567890, D1234567890, U1234567890, or W1234567890.`,\n { kind: \"config\" },\n );\n }\n return value;\n}\n\nfunction requireSlackThreadTs(value: string, label: string): string {\n if (!SLACK_TS_RULE.pattern.test(value)) {\n throw new CrablineError(`Slack ${label} must be a Slack timestamp such as 1700000000.000100.`, {\n kind: \"config\",\n });\n }\n return value;\n}\n\nconst SLACK_TARGET_CODEC: LocalMockTargetCodec = {\n normalize(target): NormalizedTarget {\n const channelId = requireSlackSendTargetId(target.channelId ?? target.id, \"channelId\");\n const normalized: NormalizedTarget = {\n channelId,\n id: target.id,\n metadata: target.metadata,\n };\n if (target.threadId) {\n normalized.threadId = requireSlackThreadTs(target.threadId, \"threadId\");\n }\n return normalized;\n },\n resolveThreadId(target) {\n const normalized = this.normalize(target);\n const channelId = normalized.channelId ?? normalized.id;\n return slackTargetKey(channelId, normalized.threadId);\n },\n};\n\nexport function parseCanonicalTelegramTopic(\n value: string,\n): { chatId: string; topicId: string } | undefined {\n return parseCanonicalTelegramTopicWithRule(value, TELEGRAM_CHAT_ID_RULE);\n}\n\nexport function parseCanonicalTelegramInboundTopic(\n value: string,\n): { chatId: string; topicId: string } | undefined {\n return parseCanonicalTelegramTopicWithRule(value, TELEGRAM_INBOUND_CHAT_ID_RULE);\n}\n\nfunction parseCanonicalTelegramTopicWithRule(\n value: string,\n chatRule: NativeIdRule,\n): { chatId: string; topicId: string } | undefined {\n const separator = value.lastIndexOf(\":\");\n if (separator <= 0) {\n return undefined;\n }\n const chatId = value.slice(0, separator);\n const topicId = value.slice(separator + 1);\n if (\n !matchesNativeId(chatId, chatRule) ||\n !matchesNativeId(topicId, TELEGRAM_MESSAGE_THREAD_ID_RULE)\n ) {\n return undefined;\n }\n const canonicalChatId =\n chatId.startsWith(\"@\") && chatRule === TELEGRAM_CHAT_ID_RULE\n ? canonicalizeTelegramUsername(chatId)\n : chatId;\n return canonicalChatId ? { chatId: canonicalChatId, topicId } : undefined;\n}\n\nconst TELEGRAM_TARGET_CODEC: LocalMockTargetCodec = {\n normalize(target) {\n const canonicalTopic = target.threadId\n ? parseCanonicalTelegramTopic(target.threadId)\n : undefined;\n const targetChatIdValue = requireNativeId(\n target.channelId ?? target.id,\n TELEGRAM_CHAT_ID_RULE,\n \"Telegram chat_id\",\n );\n const targetChatId = targetChatIdValue.startsWith(\"@\")\n ? canonicalizeTelegramUsername(targetChatIdValue)!\n : targetChatIdValue;\n if (canonicalTopic && targetChatId !== canonicalTopic.chatId) {\n throw new CrablineError(\"Telegram canonical topic chat_id must match the target chat_id.\", {\n kind: \"config\",\n });\n }\n const normalized: NormalizedTarget = {\n channelId: canonicalTopic?.chatId ?? targetChatId,\n id: target.id,\n metadata: target.metadata,\n };\n if (!target.threadId) {\n return normalized;\n }\n const topicId = requireNativeId(\n canonicalTopic?.topicId ?? target.threadId,\n TELEGRAM_MESSAGE_THREAD_ID_RULE,\n \"Telegram message_thread_id\",\n );\n return {\n ...normalized,\n threadId: `${normalized.channelId}:${topicId}`,\n };\n },\n resolveThreadId(target) {\n const normalized = this.normalize(target);\n return normalized.threadId ?? normalized.channelId ?? normalized.id;\n },\n};\n\nconst GOOGLE_CHAT_TARGET_CODEC: LocalMockTargetCodec = {\n normalize(target) {\n const channelId = requireNativeId(\n target.channelId ?? target.id,\n GOOGLE_CHAT_SPACE_RULE,\n \"Google Chat space.name\",\n );\n const normalized: NormalizedTarget = {\n channelId,\n id: target.id,\n metadata: target.metadata,\n };\n if (target.threadId) {\n const threadId = requireNativeId(\n target.threadId,\n GOOGLE_CHAT_THREAD_RULE,\n \"Google Chat thread.name\",\n );\n if (!threadId.startsWith(`${channelId}/threads/`)) {\n throw new CrablineError(\"Google Chat thread.name must belong to the target space.name.\", {\n kind: \"config\",\n });\n }\n normalized.threadId = threadId;\n }\n return normalized;\n },\n resolveThreadId(target) {\n const normalized = this.normalize(target);\n return normalized.threadId ?? normalized.channelId ?? normalized.id;\n },\n};\n\nconst MATRIX_TARGET_CODEC: LocalMockTargetCodec = {\n normalize(target) {\n const channelId = target.channelId ?? target.id;\n if (!isMatrixRoomId(channelId)) {\n throw new CrablineError(\n `Matrix room_id must be a native ${MATRIX_ROOM_ID_RULE.name} such as ${MATRIX_ROOM_ID_RULE.example}.`,\n { kind: \"config\" },\n );\n }\n const normalized: NormalizedTarget = {\n channelId,\n id: target.id,\n metadata: target.metadata,\n };\n if (target.threadId) {\n if (!isMatrixEventId(target.threadId)) {\n throw new CrablineError(\n `Matrix event_id must be a native ${MATRIX_EVENT_ID_RULE.name} such as ${MATRIX_EVENT_ID_RULE.example}.`,\n { kind: \"config\" },\n );\n }\n normalized.threadId = target.threadId;\n }\n return normalized;\n },\n resolveThreadId(target) {\n const normalized = this.normalize(target);\n return normalized.threadId ?? normalized.channelId ?? normalized.id;\n },\n};\n\nconst ZALO_BASE_TARGET_CODEC = createNativeTargetCodec({\n channel: ZALO_ID_RULE,\n channelLabel: \"Zalo user_id or oa_id\",\n});\n\nconst ZALO_TARGET_CODEC: LocalMockTargetCodec = {\n normalize(target) {\n if (target.threadId) {\n throw new CrablineError(ZALO_UNSUPPORTED_THREAD_TARGET_ERROR, { kind: \"config\" });\n }\n return ZALO_BASE_TARGET_CODEC.normalize(target);\n },\n resolveThreadId(target) {\n const normalized = this.normalize(target);\n return normalized.channelId ?? normalized.id;\n },\n};\n\nconst WHATSAPP_BASE_TARGET_CODEC = createNativeTargetCodec({\n channel: WHATSAPP_WA_ID_RULE,\n channelLabel: \"WhatsApp wa_id\",\n});\n\nconst WHATSAPP_TARGET_CODEC: LocalMockTargetCodec = {\n normalize(target) {\n if (target.threadId) {\n throw new CrablineError(WHATSAPP_UNSUPPORTED_THREAD_TARGET_ERROR, { kind: \"config\" });\n }\n return WHATSAPP_BASE_TARGET_CODEC.normalize(target);\n },\n resolveThreadId(target) {\n const normalized = this.normalize(target);\n return normalized.channelId ?? normalized.id;\n },\n};\n\nconst BUILTIN_TARGET_CODECS = {\n discord: createNativeTargetCodec({\n channel: DISCORD_SNOWFLAKE_RULE,\n channelLabel: \"Discord channel_id\",\n thread: DISCORD_SNOWFLAKE_RULE,\n threadLabel: \"Discord thread id\",\n }),\n feishu: createNativeTargetCodec({\n channel: FEISHU_CHAT_ID_RULE,\n channelLabel: \"Feishu chat_id\",\n thread: FEISHU_MESSAGE_ID_RULE,\n threadLabel: \"Feishu message_id\",\n }),\n googlechat: GOOGLE_CHAT_TARGET_CODEC,\n imessage: createNativeTargetCodec({\n channel: IMESSAGE_THREAD_RULE,\n channelLabel: \"iMessage recipient or chat GUID\",\n }),\n loopback: createGenericLocalMockTargetCodec(\"loopback\"),\n matrix: MATRIX_TARGET_CODEC,\n mattermost: createNativeTargetCodec({\n channel: MATTERMOST_ID_RULE,\n channelLabel: \"Mattermost channel_id\",\n }),\n msteams: createNativeTargetCodec({\n channel: MSTEAMS_CONVERSATION_ID_RULE,\n channelLabel: \"Microsoft Teams conversation.id\",\n }),\n slack: SLACK_TARGET_CODEC,\n telegram: TELEGRAM_TARGET_CODEC,\n whatsapp: WHATSAPP_TARGET_CODEC,\n zalo: ZALO_TARGET_CODEC,\n} satisfies Record<BuiltinProviderAdapterId, LocalMockTargetCodec>;\n\nexport function getBuiltinTargetCodec(adapter: BuiltinProviderAdapterId): LocalMockTargetCodec {\n return BUILTIN_TARGET_CODECS[adapter];\n}\n\nexport function normalizeBuiltinTarget(\n adapter: BuiltinProviderAdapterId,\n target: FixtureDefinition[\"target\"],\n): NormalizedTarget {\n return getBuiltinTargetCodec(adapter).normalize(target);\n}\n"]}
@@ -11,4 +11,7 @@ export declare function startWebhookServer(params: {
11
11
  onError?: ((error: unknown) => void) | undefined;
12
12
  path: string;
13
13
  port: number;
14
+ preflight?: ((request: Request) => Promise<Response | undefined> | Response | undefined) | undefined;
15
+ signal?: AbortSignal | undefined;
16
+ shutdownGraceMs?: number | undefined;
14
17
  }): Promise<StartedWebhookServer>;
@@ -1,22 +1,40 @@
1
1
  import { createServer } from "node:http";
2
+ import { isCanonicalHttpPath } from "../core/http-path.js";
3
+ import { advertisedHostForBindAddress, assertLoopbackBindAddress, closeServer, drainRequestBody, formatUrlHost, writeFetchResponseHeaders, } from "../servers/http.js";
2
4
  const DEFAULT_MAX_BODY_BYTES = 1024 * 1024;
3
5
  const DEFAULT_BODY_TIMEOUT_MS = 5_000;
6
+ const MAX_NODE_TIMER_DELAY_MS = 2_147_483_647;
4
7
  class RequestBodyTooLargeError extends Error {
5
8
  }
6
9
  class RequestBodyTimeoutError extends Error {
7
10
  }
11
+ class ResponseDeliveryClosedError extends Error {
12
+ }
13
+ function requirePositiveSafeInteger(value, name) {
14
+ if (!Number.isSafeInteger(value) || value <= 0) {
15
+ throw new Error(`${name} must be a positive safe integer.`);
16
+ }
17
+ return value;
18
+ }
19
+ function requireTimerDelay(value, name) {
20
+ if (!Number.isSafeInteger(value) || value <= 0 || value > MAX_NODE_TIMER_DELAY_MS) {
21
+ throw new Error(`${name} must be a positive integer no greater than ${MAX_NODE_TIMER_DELAY_MS}.`);
22
+ }
23
+ return value;
24
+ }
8
25
  async function readRequestBody(request, maxBodyBytes, bodyTimeoutMs) {
26
+ if (request.aborted) {
27
+ throw new Error("request body aborted");
28
+ }
9
29
  return await new Promise((resolve, reject) => {
10
30
  const chunks = [];
11
31
  let bodyBytes = 0;
12
32
  let settled = false;
13
- const cleanup = (preserveErrorListener = false) => {
33
+ const cleanup = () => {
14
34
  clearTimeout(timeout);
15
35
  request.off("data", onData);
16
36
  request.off("end", onEnd);
17
- if (!preserveErrorListener) {
18
- request.off("error", onError);
19
- }
37
+ request.off("error", onError);
20
38
  request.off("aborted", onAborted);
21
39
  };
22
40
  const fail = (error) => {
@@ -24,7 +42,8 @@ async function readRequestBody(request, maxBodyBytes, bodyTimeoutMs) {
24
42
  return;
25
43
  }
26
44
  settled = true;
27
- cleanup(true);
45
+ cleanup();
46
+ drainRequestBodyWithDeadline(request, bodyTimeoutMs);
28
47
  reject(error);
29
48
  };
30
49
  const onData = (chunk) => {
@@ -34,7 +53,6 @@ async function readRequestBody(request, maxBodyBytes, bodyTimeoutMs) {
34
53
  const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
35
54
  bodyBytes += buffer.length;
36
55
  if (bodyBytes > maxBodyBytes) {
37
- request.resume();
38
56
  fail(new RequestBodyTooLargeError());
39
57
  return;
40
58
  }
@@ -51,21 +69,41 @@ async function readRequestBody(request, maxBodyBytes, bodyTimeoutMs) {
51
69
  const onError = (error) => fail(error);
52
70
  const onAborted = () => fail(new Error("request body aborted"));
53
71
  const timeout = setTimeout(() => {
54
- request.resume();
55
72
  fail(new RequestBodyTimeoutError());
56
73
  }, bodyTimeoutMs);
57
74
  request.on("data", onData);
58
75
  request.once("end", onEnd);
59
76
  request.once("error", onError);
60
77
  request.once("aborted", onAborted);
78
+ if (request.aborted) {
79
+ onAborted();
80
+ }
61
81
  });
62
82
  }
63
- async function toFetchRequest(request, url, maxBodyBytes, bodyTimeoutMs) {
64
- const body = request.method === "GET" || request.method === "HEAD"
83
+ function drainRequestBodyWithDeadline(request, bodyTimeoutMs) {
84
+ if (request.destroyed || request.readableEnded) {
85
+ return;
86
+ }
87
+ const socket = request.socket;
88
+ const timeout = setTimeout(() => socket.destroy(), bodyTimeoutMs);
89
+ timeout.unref();
90
+ const cleanup = () => {
91
+ clearTimeout(timeout);
92
+ request.off("end", cleanup);
93
+ socket.off("close", cleanup);
94
+ };
95
+ request.once("end", cleanup);
96
+ socket.once("close", cleanup);
97
+ drainRequestBody(request);
98
+ }
99
+ async function toFetchRequest(request, url, maxBodyBytes, bodyTimeoutMs, signal) {
100
+ const requestBody = await readRequestBody(request, maxBodyBytes, bodyTimeoutMs);
101
+ const body = request.method === "GET" || request.method === "HEAD" || requestBody.length === 0
65
102
  ? undefined
66
- : await readRequestBody(request, maxBodyBytes, bodyTimeoutMs);
103
+ : requestBody;
67
104
  const init = {
68
105
  headers: request.headers,
106
+ signal,
69
107
  };
70
108
  if (request.method) {
71
109
  init.method = request.method;
@@ -76,51 +114,169 @@ async function toFetchRequest(request, url, maxBodyBytes, bodyTimeoutMs) {
76
114
  }
77
115
  return new Request(url, init);
78
116
  }
79
- async function writeFetchResponse(response, fetchResponse) {
80
- response.statusCode = fetchResponse.status;
81
- for (const [name, value] of fetchResponse.headers) {
82
- response.setHeader(name, value);
83
- }
84
- if (!fetchResponse.body) {
85
- response.end();
86
- return;
117
+ function toFetchRequestMetadata(request, url, signal) {
118
+ return new Request(url, {
119
+ headers: request.headers,
120
+ ...(request.method ? { method: request.method } : {}),
121
+ signal,
122
+ });
123
+ }
124
+ function trackRequestLifetime(request) {
125
+ const controller = new AbortController();
126
+ const abort = () => {
127
+ if (!controller.signal.aborted) {
128
+ controller.abort(new DOMException("Webhook client disconnected.", "AbortError"));
129
+ }
130
+ };
131
+ request.once("aborted", abort);
132
+ request.socket.once("close", abort);
133
+ if (request.aborted || request.socket.destroyed) {
134
+ abort();
87
135
  }
88
- const body = Buffer.from(await fetchResponse.arrayBuffer());
89
- response.end(body);
136
+ return {
137
+ dispose() {
138
+ request.off("aborted", abort);
139
+ request.socket.off("close", abort);
140
+ },
141
+ signal: controller.signal,
142
+ };
90
143
  }
91
- function closeServer(server) {
92
- return new Promise((resolve, reject) => {
93
- server.close((error) => {
94
- if (error) {
95
- reject(error);
96
- return;
144
+ async function writeFetchResponse(response, fetchResponse) {
145
+ response.statusCode = fetchResponse.status;
146
+ writeFetchResponseHeaders(response, fetchResponse);
147
+ const reader = fetchResponse.body?.getReader();
148
+ let cancellation;
149
+ let rejectStopped;
150
+ let stoppedError;
151
+ const stopped = new Promise((_, reject) => {
152
+ rejectStopped = reject;
153
+ });
154
+ void stopped.catch(() => { });
155
+ const cancelBody = (reason) => {
156
+ if (!reader || cancellation) {
157
+ return;
158
+ }
159
+ cancellation = reader.cancel(reason).catch(() => { });
160
+ };
161
+ const stop = (error) => {
162
+ if (stoppedError) {
163
+ return;
164
+ }
165
+ stoppedError = error;
166
+ cancelBody(error);
167
+ rejectStopped(error);
168
+ };
169
+ const onClose = () => {
170
+ if (!response.writableFinished) {
171
+ stop(new ResponseDeliveryClosedError("Webhook response delivery closed before completion."));
172
+ }
173
+ };
174
+ const onError = (error) => stop(error);
175
+ response.once("close", onClose);
176
+ response.once("error", onError);
177
+ try {
178
+ if (response.destroyed ||
179
+ response.req?.aborted ||
180
+ response.req?.socket.destroyed ||
181
+ response.socket?.destroyed) {
182
+ throw new ResponseDeliveryClosedError("Webhook response delivery closed before it started.");
183
+ }
184
+ if (reader) {
185
+ while (true) {
186
+ const chunk = await Promise.race([reader.read(), stopped]);
187
+ if (chunk.done) {
188
+ break;
189
+ }
190
+ if (chunk.value.byteLength > 0 && !response.write(chunk.value)) {
191
+ let onDrain;
192
+ const drained = new Promise((resolve) => {
193
+ onDrain = resolve;
194
+ response.once("drain", onDrain);
195
+ });
196
+ try {
197
+ await Promise.race([drained, stopped]);
198
+ }
199
+ finally {
200
+ response.off("drain", onDrain);
201
+ }
202
+ }
97
203
  }
98
- resolve();
204
+ }
205
+ let onFinish;
206
+ const finished = new Promise((resolve) => {
207
+ onFinish = resolve;
208
+ response.once("finish", onFinish);
99
209
  });
100
- server.closeAllConnections();
101
- });
210
+ try {
211
+ response.end();
212
+ await Promise.race([finished, stopped]);
213
+ }
214
+ finally {
215
+ response.off("finish", onFinish);
216
+ }
217
+ }
218
+ catch (error) {
219
+ cancelBody(error instanceof Error ? error : new Error(String(error)));
220
+ throw error;
221
+ }
222
+ finally {
223
+ response.off("close", onClose);
224
+ response.off("error", onError);
225
+ }
102
226
  }
103
- function formatUrlHost(host) {
104
- return host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
227
+ function clearUnsentResponseHeaders(response) {
228
+ if (response.headersSent) {
229
+ return;
230
+ }
231
+ for (const name of response.getHeaderNames()) {
232
+ response.removeHeader(name);
233
+ }
105
234
  }
106
235
  export async function startWebhookServer(params) {
236
+ params.signal?.throwIfAborted();
237
+ if (!isCanonicalHttpPath(params.path)) {
238
+ throw new Error("Webhook path must be a canonical URL pathname.");
239
+ }
107
240
  const methods = new Set(params.methods ?? ["POST"]);
108
- const maxBodyBytes = params.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
109
- const bodyTimeoutMs = params.bodyTimeoutMs ?? DEFAULT_BODY_TIMEOUT_MS;
241
+ const maxBodyBytes = requirePositiveSafeInteger(params.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES, "Webhook maxBodyBytes");
242
+ const bodyTimeoutMs = requireTimerDelay(params.bodyTimeoutMs ?? DEFAULT_BODY_TIMEOUT_MS, "Webhook bodyTimeoutMs");
243
+ const shutdownGraceMs = params.shutdownGraceMs === undefined
244
+ ? undefined
245
+ : requireTimerDelay(params.shutdownGraceMs, "Webhook shutdownGraceMs");
246
+ let closing = false;
110
247
  const server = createServer(async (request, response) => {
248
+ const requestLifetime = trackRequestLifetime(request);
111
249
  try {
250
+ if (closing) {
251
+ drainRequestBodyWithDeadline(request, bodyTimeoutMs);
252
+ await writeFetchResponse(response, new Response("provider is shutting down", {
253
+ headers: { connection: "close" },
254
+ status: 503,
255
+ }));
256
+ return;
257
+ }
112
258
  const method = request.method ?? "GET";
113
259
  const host = request.headers.host ?? "127.0.0.1";
114
260
  const url = new URL(request.url ?? "/", `http://${host}`);
115
261
  if (!methods.has(method) || url.pathname !== params.path) {
116
- request.resume();
262
+ drainRequestBodyWithDeadline(request, bodyTimeoutMs);
117
263
  await writeFetchResponse(response, new Response("not found", { status: 404 }));
118
264
  return;
119
265
  }
120
- const fetchRequest = await toFetchRequest(request, url, maxBodyBytes, bodyTimeoutMs);
266
+ const preflightResponse = await params.preflight?.(toFetchRequestMetadata(request, url, requestLifetime.signal));
267
+ if (preflightResponse) {
268
+ drainRequestBodyWithDeadline(request, bodyTimeoutMs);
269
+ await writeFetchResponse(response, preflightResponse);
270
+ return;
271
+ }
272
+ const fetchRequest = await toFetchRequest(request, url, maxBodyBytes, bodyTimeoutMs, requestLifetime.signal);
121
273
  await writeFetchResponse(response, await params.handle(fetchRequest));
122
274
  }
123
275
  catch (error) {
276
+ if (error instanceof ResponseDeliveryClosedError) {
277
+ response.destroy();
278
+ return;
279
+ }
124
280
  const status = error instanceof RequestBodyTooLargeError
125
281
  ? 413
126
282
  : error instanceof RequestBodyTimeoutError
@@ -134,32 +290,97 @@ export async function startWebhookServer(params) {
134
290
  // Error reporting must not change the public response.
135
291
  }
136
292
  }
137
- await writeFetchResponse(response, new Response(status === 413
138
- ? "request body too large"
139
- : status === 408
140
- ? "request body timeout"
141
- : "internal server error", {
142
- ...(status === 408 ? { headers: { connection: "close" } } : {}),
143
- status,
144
- }));
293
+ if (response.headersSent || response.destroyed) {
294
+ response.destroy();
295
+ return;
296
+ }
297
+ clearUnsentResponseHeaders(response);
298
+ try {
299
+ await writeFetchResponse(response, new Response(status === 413
300
+ ? "request body too large"
301
+ : status === 408
302
+ ? "request body timeout"
303
+ : "internal server error", {
304
+ ...(status === 408 || status === 413 ? { headers: { connection: "close" } } : {}),
305
+ status,
306
+ }));
307
+ }
308
+ catch {
309
+ response.destroy();
310
+ }
311
+ }
312
+ finally {
313
+ requestLifetime.dispose();
145
314
  }
146
315
  });
147
316
  await new Promise((resolve, reject) => {
148
- server.once("error", reject);
317
+ let abortCloseStarted = false;
318
+ let aborting = false;
319
+ let settled = false;
320
+ const cleanup = () => {
321
+ server.off("error", onError);
322
+ params.signal?.removeEventListener("abort", onAbort);
323
+ };
324
+ const fail = (error) => {
325
+ if (settled) {
326
+ return;
327
+ }
328
+ settled = true;
329
+ cleanup();
330
+ reject(error);
331
+ };
332
+ const onError = (error) => fail(error);
333
+ const closeAbortedStartup = () => {
334
+ if (!aborting || abortCloseStarted || !server.listening) {
335
+ return;
336
+ }
337
+ abortCloseStarted = true;
338
+ const reason = params.signal?.reason ?? new DOMException("Webhook startup aborted", "AbortError");
339
+ void closeServer(server, shutdownGraceMs).then(() => fail(reason), (closeError) => fail(new AggregateError([reason, closeError], "Webhook startup was aborted and listener cleanup failed.")));
340
+ };
341
+ const onAbort = () => {
342
+ if (settled || aborting) {
343
+ return;
344
+ }
345
+ aborting = true;
346
+ closing = true;
347
+ closeAbortedStartup();
348
+ };
349
+ server.once("error", onError);
350
+ params.signal?.addEventListener("abort", onAbort, { once: true });
149
351
  server.listen(params.port, params.host, () => {
150
- server.off("error", reject);
352
+ if (aborting) {
353
+ closeAbortedStartup();
354
+ return;
355
+ }
356
+ settled = true;
357
+ cleanup();
151
358
  resolve();
152
359
  });
360
+ if (params.signal?.aborted) {
361
+ onAbort();
362
+ }
153
363
  });
154
364
  const address = server.address();
155
365
  if (!address || typeof address === "string") {
156
366
  throw new Error("Unable to resolve webhook server address.");
157
367
  }
368
+ try {
369
+ assertLoopbackBindAddress(params.host, address.address, "Webhook server");
370
+ }
371
+ catch (error) {
372
+ await closeServer(server, shutdownGraceMs);
373
+ throw error;
374
+ }
375
+ const advertisedHost = advertisedHostForBindAddress(params.host, address.address);
376
+ let closingPromise = null;
158
377
  return {
159
378
  async close() {
160
- await closeServer(server);
379
+ closing = true;
380
+ closingPromise ??= closeServer(server, shutdownGraceMs);
381
+ await closingPromise;
161
382
  },
162
- endpointUrl: `http://${formatUrlHost(params.host)}:${address.port}${params.path}`,
383
+ endpointUrl: `http://${formatUrlHost(advertisedHost)}:${address.port}${params.path}`,
163
384
  };
164
385
  }
165
386
  //# sourceMappingURL=webhook-server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"webhook-server.js","sourceRoot":"","sources":["../../../src/providers/webhook-server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\n\nexport type StartedWebhookServer = {\n close(): Promise<void>;\n endpointUrl: string;\n};\n\nconst DEFAULT_MAX_BODY_BYTES = 1024 * 1024;\nconst DEFAULT_BODY_TIMEOUT_MS = 5_000;\n\nclass RequestBodyTooLargeError extends Error {}\nclass RequestBodyTimeoutError extends Error {}\n\nasync function readRequestBody(\n request: IncomingMessage,\n maxBodyBytes: number,\n bodyTimeoutMs: number,\n): Promise<Buffer> {\n return await new Promise<Buffer>((resolve, reject) => {\n const chunks: Buffer[] = [];\n let bodyBytes = 0;\n let settled = false;\n\n const cleanup = (preserveErrorListener = false) => {\n clearTimeout(timeout);\n request.off(\"data\", onData);\n request.off(\"end\", onEnd);\n if (!preserveErrorListener) {\n request.off(\"error\", onError);\n }\n request.off(\"aborted\", onAborted);\n };\n const fail = (error: unknown) => {\n if (settled) {\n return;\n }\n settled = true;\n cleanup(true);\n reject(error);\n };\n const onData = (chunk: Buffer | string) => {\n if (settled) {\n return;\n }\n\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n bodyBytes += buffer.length;\n if (bodyBytes > maxBodyBytes) {\n request.resume();\n fail(new RequestBodyTooLargeError());\n return;\n }\n chunks.push(buffer);\n };\n const onEnd = () => {\n if (settled) {\n return;\n }\n settled = true;\n cleanup();\n resolve(Buffer.concat(chunks));\n };\n const onError = (error: Error) => fail(error);\n const onAborted = () => fail(new Error(\"request body aborted\"));\n const timeout = setTimeout(() => {\n request.resume();\n fail(new RequestBodyTimeoutError());\n }, bodyTimeoutMs);\n\n request.on(\"data\", onData);\n request.once(\"end\", onEnd);\n request.once(\"error\", onError);\n request.once(\"aborted\", onAborted);\n });\n}\n\nasync function toFetchRequest(\n request: IncomingMessage,\n url: URL,\n maxBodyBytes: number,\n bodyTimeoutMs: number,\n): Promise<Request> {\n const body =\n request.method === \"GET\" || request.method === \"HEAD\"\n ? undefined\n : await readRequestBody(request, maxBodyBytes, bodyTimeoutMs);\n\n const init: RequestInit = {\n headers: request.headers as Record<string, string>,\n };\n if (request.method) {\n init.method = request.method;\n }\n if (body) {\n init.body = body;\n init.duplex = \"half\";\n }\n\n return new Request(url, init);\n}\n\nasync function writeFetchResponse(\n response: ServerResponse<IncomingMessage>,\n fetchResponse: Response,\n): Promise<void> {\n response.statusCode = fetchResponse.status;\n\n for (const [name, value] of fetchResponse.headers) {\n response.setHeader(name, value);\n }\n\n if (!fetchResponse.body) {\n response.end();\n return;\n }\n\n const body = Buffer.from(await fetchResponse.arrayBuffer());\n response.end(body);\n}\n\nfunction closeServer(server: Server): Promise<void> {\n return new Promise((resolve, reject) => {\n server.close((error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n server.closeAllConnections();\n });\n}\n\nfunction formatUrlHost(host: string): string {\n return host.includes(\":\") && !host.startsWith(\"[\") ? `[${host}]` : host;\n}\n\nexport async function startWebhookServer(params: {\n handle(request: Request): Promise<Response>;\n bodyTimeoutMs?: number | undefined;\n host: string;\n maxBodyBytes?: number;\n methods?: readonly string[] | undefined;\n onError?: ((error: unknown) => void) | undefined;\n path: string;\n port: number;\n}): Promise<StartedWebhookServer> {\n const methods = new Set(params.methods ?? [\"POST\"]);\n const maxBodyBytes = params.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;\n const bodyTimeoutMs = params.bodyTimeoutMs ?? DEFAULT_BODY_TIMEOUT_MS;\n const server = createServer(async (request, response) => {\n try {\n const method = request.method ?? \"GET\";\n const host = request.headers.host ?? \"127.0.0.1\";\n const url = new URL(request.url ?? \"/\", `http://${host}`);\n if (!methods.has(method) || url.pathname !== params.path) {\n request.resume();\n await writeFetchResponse(response, new Response(\"not found\", { status: 404 }));\n return;\n }\n\n const fetchRequest = await toFetchRequest(request, url, maxBodyBytes, bodyTimeoutMs);\n await writeFetchResponse(response, await params.handle(fetchRequest));\n } catch (error) {\n const status =\n error instanceof RequestBodyTooLargeError\n ? 413\n : error instanceof RequestBodyTimeoutError\n ? 408\n : 500;\n if (status === 500) {\n try {\n params.onError?.(error);\n } catch {\n // Error reporting must not change the public response.\n }\n }\n await writeFetchResponse(\n response,\n new Response(\n status === 413\n ? \"request body too large\"\n : status === 408\n ? \"request body timeout\"\n : \"internal server error\",\n {\n ...(status === 408 ? { headers: { connection: \"close\" } } : {}),\n status,\n },\n ),\n );\n }\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(params.port, params.host, () => {\n server.off(\"error\", reject);\n resolve();\n });\n });\n\n const address = server.address();\n if (!address || typeof address === \"string\") {\n throw new Error(\"Unable to resolve webhook server address.\");\n }\n\n return {\n async close() {\n await closeServer(server);\n },\n endpointUrl: `http://${formatUrlHost(params.host)}:${address.port}${params.path}`,\n };\n}\n"]}
1
+ {"version":3,"file":"webhook-server.js","sourceRoot":"","sources":["../../../src/providers/webhook-server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { isCanonicalHttpPath } from \"../core/http-path.js\";\nimport {\n advertisedHostForBindAddress,\n assertLoopbackBindAddress,\n closeServer,\n drainRequestBody,\n formatUrlHost,\n writeFetchResponseHeaders,\n} from \"../servers/http.js\";\n\nexport type StartedWebhookServer = {\n close(): Promise<void>;\n endpointUrl: string;\n};\n\nconst DEFAULT_MAX_BODY_BYTES = 1024 * 1024;\nconst DEFAULT_BODY_TIMEOUT_MS = 5_000;\nconst MAX_NODE_TIMER_DELAY_MS = 2_147_483_647;\n\nclass RequestBodyTooLargeError extends Error {}\nclass RequestBodyTimeoutError extends Error {}\nclass ResponseDeliveryClosedError extends Error {}\n\nfunction requirePositiveSafeInteger(value: number, name: string): number {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new Error(`${name} must be a positive safe integer.`);\n }\n return value;\n}\n\nfunction requireTimerDelay(value: number, name: string): number {\n if (!Number.isSafeInteger(value) || value <= 0 || value > MAX_NODE_TIMER_DELAY_MS) {\n throw new Error(\n `${name} must be a positive integer no greater than ${MAX_NODE_TIMER_DELAY_MS}.`,\n );\n }\n return value;\n}\n\nasync function readRequestBody(\n request: IncomingMessage,\n maxBodyBytes: number,\n bodyTimeoutMs: number,\n): Promise<Buffer> {\n if (request.aborted) {\n throw new Error(\"request body aborted\");\n }\n return await new Promise<Buffer>((resolve, reject) => {\n const chunks: Buffer[] = [];\n let bodyBytes = 0;\n let settled = false;\n\n const cleanup = () => {\n clearTimeout(timeout);\n request.off(\"data\", onData);\n request.off(\"end\", onEnd);\n request.off(\"error\", onError);\n request.off(\"aborted\", onAborted);\n };\n const fail = (error: unknown) => {\n if (settled) {\n return;\n }\n settled = true;\n cleanup();\n drainRequestBodyWithDeadline(request, bodyTimeoutMs);\n reject(error);\n };\n const onData = (chunk: Buffer | string) => {\n if (settled) {\n return;\n }\n\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n bodyBytes += buffer.length;\n if (bodyBytes > maxBodyBytes) {\n fail(new RequestBodyTooLargeError());\n return;\n }\n chunks.push(buffer);\n };\n const onEnd = () => {\n if (settled) {\n return;\n }\n settled = true;\n cleanup();\n resolve(Buffer.concat(chunks));\n };\n const onError = (error: Error) => fail(error);\n const onAborted = () => fail(new Error(\"request body aborted\"));\n const timeout = setTimeout(() => {\n fail(new RequestBodyTimeoutError());\n }, bodyTimeoutMs);\n\n request.on(\"data\", onData);\n request.once(\"end\", onEnd);\n request.once(\"error\", onError);\n request.once(\"aborted\", onAborted);\n if (request.aborted) {\n onAborted();\n }\n });\n}\n\nfunction drainRequestBodyWithDeadline(request: IncomingMessage, bodyTimeoutMs: number): void {\n if (request.destroyed || request.readableEnded) {\n return;\n }\n const socket = request.socket;\n const timeout = setTimeout(() => socket.destroy(), bodyTimeoutMs);\n timeout.unref();\n const cleanup = () => {\n clearTimeout(timeout);\n request.off(\"end\", cleanup);\n socket.off(\"close\", cleanup);\n };\n request.once(\"end\", cleanup);\n socket.once(\"close\", cleanup);\n drainRequestBody(request);\n}\n\nasync function toFetchRequest(\n request: IncomingMessage,\n url: URL,\n maxBodyBytes: number,\n bodyTimeoutMs: number,\n signal: AbortSignal,\n): Promise<Request> {\n const requestBody = await readRequestBody(request, maxBodyBytes, bodyTimeoutMs);\n const body =\n request.method === \"GET\" || request.method === \"HEAD\" || requestBody.length === 0\n ? undefined\n : requestBody;\n\n const init: RequestInit & { duplex?: \"half\" } = {\n headers: request.headers as Record<string, string>,\n signal,\n };\n if (request.method) {\n init.method = request.method;\n }\n if (body) {\n init.body = body;\n init.duplex = \"half\";\n }\n\n return new Request(url, init);\n}\n\nfunction toFetchRequestMetadata(request: IncomingMessage, url: URL, signal: AbortSignal): Request {\n return new Request(url, {\n headers: request.headers as Record<string, string>,\n ...(request.method ? { method: request.method } : {}),\n signal,\n });\n}\n\nfunction trackRequestLifetime(request: IncomingMessage): {\n dispose(): void;\n signal: AbortSignal;\n} {\n const controller = new AbortController();\n const abort = () => {\n if (!controller.signal.aborted) {\n controller.abort(new DOMException(\"Webhook client disconnected.\", \"AbortError\"));\n }\n };\n request.once(\"aborted\", abort);\n request.socket.once(\"close\", abort);\n if (request.aborted || request.socket.destroyed) {\n abort();\n }\n return {\n dispose() {\n request.off(\"aborted\", abort);\n request.socket.off(\"close\", abort);\n },\n signal: controller.signal,\n };\n}\n\nasync function writeFetchResponse(\n response: ServerResponse<IncomingMessage>,\n fetchResponse: Response,\n): Promise<void> {\n response.statusCode = fetchResponse.status;\n writeFetchResponseHeaders(response, fetchResponse);\n\n const reader = fetchResponse.body?.getReader();\n let cancellation: Promise<void> | undefined;\n let rejectStopped!: (error: Error) => void;\n let stoppedError: Error | undefined;\n const stopped = new Promise<never>((_, reject) => {\n rejectStopped = reject;\n });\n void stopped.catch(() => {});\n\n const cancelBody = (reason: Error) => {\n if (!reader || cancellation) {\n return;\n }\n cancellation = reader.cancel(reason).catch(() => {});\n };\n const stop = (error: Error) => {\n if (stoppedError) {\n return;\n }\n stoppedError = error;\n cancelBody(error);\n rejectStopped(error);\n };\n const onClose = () => {\n if (!response.writableFinished) {\n stop(new ResponseDeliveryClosedError(\"Webhook response delivery closed before completion.\"));\n }\n };\n const onError = (error: Error) => stop(error);\n response.once(\"close\", onClose);\n response.once(\"error\", onError);\n\n try {\n if (\n response.destroyed ||\n response.req?.aborted ||\n response.req?.socket.destroyed ||\n response.socket?.destroyed\n ) {\n throw new ResponseDeliveryClosedError(\"Webhook response delivery closed before it started.\");\n }\n\n if (reader) {\n while (true) {\n const chunk = await Promise.race([reader.read(), stopped]);\n if (chunk.done) {\n break;\n }\n if (chunk.value.byteLength > 0 && !response.write(chunk.value)) {\n let onDrain!: () => void;\n const drained = new Promise<void>((resolve) => {\n onDrain = resolve;\n response.once(\"drain\", onDrain);\n });\n try {\n await Promise.race([drained, stopped]);\n } finally {\n response.off(\"drain\", onDrain);\n }\n }\n }\n }\n\n let onFinish!: () => void;\n const finished = new Promise<void>((resolve) => {\n onFinish = resolve;\n response.once(\"finish\", onFinish);\n });\n try {\n response.end();\n await Promise.race([finished, stopped]);\n } finally {\n response.off(\"finish\", onFinish);\n }\n } catch (error) {\n cancelBody(error instanceof Error ? error : new Error(String(error)));\n throw error;\n } finally {\n response.off(\"close\", onClose);\n response.off(\"error\", onError);\n }\n}\n\nfunction clearUnsentResponseHeaders(response: ServerResponse<IncomingMessage>): void {\n if (response.headersSent) {\n return;\n }\n for (const name of response.getHeaderNames()) {\n response.removeHeader(name);\n }\n}\n\nexport async function startWebhookServer(params: {\n handle(request: Request): Promise<Response>;\n bodyTimeoutMs?: number | undefined;\n host: string;\n maxBodyBytes?: number;\n methods?: readonly string[] | undefined;\n onError?: ((error: unknown) => void) | undefined;\n path: string;\n port: number;\n preflight?:\n | ((request: Request) => Promise<Response | undefined> | Response | undefined)\n | undefined;\n signal?: AbortSignal | undefined;\n shutdownGraceMs?: number | undefined;\n}): Promise<StartedWebhookServer> {\n params.signal?.throwIfAborted();\n if (!isCanonicalHttpPath(params.path)) {\n throw new Error(\"Webhook path must be a canonical URL pathname.\");\n }\n const methods = new Set(params.methods ?? [\"POST\"]);\n const maxBodyBytes = requirePositiveSafeInteger(\n params.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES,\n \"Webhook maxBodyBytes\",\n );\n const bodyTimeoutMs = requireTimerDelay(\n params.bodyTimeoutMs ?? DEFAULT_BODY_TIMEOUT_MS,\n \"Webhook bodyTimeoutMs\",\n );\n const shutdownGraceMs =\n params.shutdownGraceMs === undefined\n ? undefined\n : requireTimerDelay(params.shutdownGraceMs, \"Webhook shutdownGraceMs\");\n let closing = false;\n const server = createServer(async (request, response) => {\n const requestLifetime = trackRequestLifetime(request);\n try {\n if (closing) {\n drainRequestBodyWithDeadline(request, bodyTimeoutMs);\n await writeFetchResponse(\n response,\n new Response(\"provider is shutting down\", {\n headers: { connection: \"close\" },\n status: 503,\n }),\n );\n return;\n }\n const method = request.method ?? \"GET\";\n const host = request.headers.host ?? \"127.0.0.1\";\n const url = new URL(request.url ?? \"/\", `http://${host}`);\n if (!methods.has(method) || url.pathname !== params.path) {\n drainRequestBodyWithDeadline(request, bodyTimeoutMs);\n await writeFetchResponse(response, new Response(\"not found\", { status: 404 }));\n return;\n }\n\n const preflightResponse = await params.preflight?.(\n toFetchRequestMetadata(request, url, requestLifetime.signal),\n );\n if (preflightResponse) {\n drainRequestBodyWithDeadline(request, bodyTimeoutMs);\n await writeFetchResponse(response, preflightResponse);\n return;\n }\n\n const fetchRequest = await toFetchRequest(\n request,\n url,\n maxBodyBytes,\n bodyTimeoutMs,\n requestLifetime.signal,\n );\n await writeFetchResponse(response, await params.handle(fetchRequest));\n } catch (error) {\n if (error instanceof ResponseDeliveryClosedError) {\n response.destroy();\n return;\n }\n const status =\n error instanceof RequestBodyTooLargeError\n ? 413\n : error instanceof RequestBodyTimeoutError\n ? 408\n : 500;\n if (status === 500) {\n try {\n params.onError?.(error);\n } catch {\n // Error reporting must not change the public response.\n }\n }\n if (response.headersSent || response.destroyed) {\n response.destroy();\n return;\n }\n clearUnsentResponseHeaders(response);\n try {\n await writeFetchResponse(\n response,\n new Response(\n status === 413\n ? \"request body too large\"\n : status === 408\n ? \"request body timeout\"\n : \"internal server error\",\n {\n ...(status === 408 || status === 413 ? { headers: { connection: \"close\" } } : {}),\n status,\n },\n ),\n );\n } catch {\n response.destroy();\n }\n } finally {\n requestLifetime.dispose();\n }\n });\n\n await new Promise<void>((resolve, reject) => {\n let abortCloseStarted = false;\n let aborting = false;\n let settled = false;\n const cleanup = () => {\n server.off(\"error\", onError);\n params.signal?.removeEventListener(\"abort\", onAbort);\n };\n const fail = (error: unknown) => {\n if (settled) {\n return;\n }\n settled = true;\n cleanup();\n reject(error);\n };\n const onError = (error: Error) => fail(error);\n const closeAbortedStartup = () => {\n if (!aborting || abortCloseStarted || !server.listening) {\n return;\n }\n abortCloseStarted = true;\n const reason =\n params.signal?.reason ?? new DOMException(\"Webhook startup aborted\", \"AbortError\");\n void closeServer(server, shutdownGraceMs).then(\n () => fail(reason),\n (closeError: unknown) =>\n fail(\n new AggregateError(\n [reason, closeError],\n \"Webhook startup was aborted and listener cleanup failed.\",\n ),\n ),\n );\n };\n const onAbort = () => {\n if (settled || aborting) {\n return;\n }\n aborting = true;\n closing = true;\n closeAbortedStartup();\n };\n server.once(\"error\", onError);\n params.signal?.addEventListener(\"abort\", onAbort, { once: true });\n server.listen(params.port, params.host, () => {\n if (aborting) {\n closeAbortedStartup();\n return;\n }\n settled = true;\n cleanup();\n resolve();\n });\n if (params.signal?.aborted) {\n onAbort();\n }\n });\n\n const address = server.address();\n if (!address || typeof address === \"string\") {\n throw new Error(\"Unable to resolve webhook server address.\");\n }\n try {\n assertLoopbackBindAddress(params.host, address.address, \"Webhook server\");\n } catch (error) {\n await closeServer(server, shutdownGraceMs);\n throw error;\n }\n const advertisedHost = advertisedHostForBindAddress(params.host, address.address);\n\n let closingPromise: Promise<void> | null = null;\n return {\n async close() {\n closing = true;\n closingPromise ??= closeServer(server, shutdownGraceMs);\n await closingPromise;\n },\n endpointUrl: `http://${formatUrlHost(advertisedHost)}:${address.port}${params.path}`,\n };\n}\n"]}