@openclaw/crabline 0.1.11 → 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 +7 -2
  34. package/dist/src/openclaw/artifact-generation.js +399 -27
  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 +38 -3
  54. package/dist/src/openclaw/private-file.js +2008 -87
  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 +626 -172
  61. package/dist/src/openclaw/smoke-lock.js.map +1 -1
  62. package/dist/src/openclaw.js +225 -42
  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 +521 -41
  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 +1072 -69
  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 +1169 -107
  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
package/README.md CHANGED
@@ -41,6 +41,11 @@ pnpm dev fixtures --config fixtures/examples/crabline.example.yaml
41
41
  pnpm dev roundtrip telegram-dm --config fixtures/examples/crabline.example.yaml
42
42
  ```
43
43
 
44
+ The source checkout does not link its own `crabline` bin into
45
+ `node_modules/.bin`, so use `pnpm dev` there rather than
46
+ `pnpm exec crabline`. An installed package exposes the `crabline` command used
47
+ in the examples below.
48
+
44
49
  ## Quality Gate
45
50
 
46
51
  ```bash
@@ -98,6 +103,10 @@ Telegram `secretToken`, and Zalo `webhookSecret` enforce provider-native
98
103
  webhook authentication. Feishu `verificationToken` remains an additional or
99
104
  loopback-only callback check. Microsoft Teams also requires `appId` for
100
105
  non-loopback or explicitly public webhook endpoints.
106
+ Authenticated external webhook ingress must advertise an HTTPS `publicUrl`;
107
+ plain HTTP is limited to loopback-local testing.
108
+ Feishu text callbacks require valid JSON-encoded `message.content`; malformed
109
+ content is rejected.
101
110
 
102
111
  ## Built-In Mock Channels
103
112
 
@@ -138,11 +147,54 @@ them only from sources you trust and review changes before use.
138
147
  preferred Smoke CI path because OpenClaw still uses its normal channel adapter,
139
148
  but the provider endpoint is local and deterministic.
140
149
 
150
+ Commands in this section use the installed-package form. In a source checkout,
151
+ replace `crabline` with `pnpm dev`.
152
+
153
+ `serve` never accepts credential values in command-line arguments. Set
154
+ `CRABLINE_ACCESS_TOKEN`, `CRABLINE_ADMIN_TOKEN`, `CRABLINE_BOT_TOKEN`, or
155
+ `CRABLINE_SIGNING_SECRET`, or pass a bounded JSON object through a file
156
+ descriptor. Package runners should use stdin:
157
+
158
+ ```bash
159
+ pnpm dev --json serve slack --credentials-fd 0 < .crabline/serve-credentials.json
160
+ ```
161
+
162
+ The installed CLI can also use an inherited descriptor when its launcher
163
+ preserves descriptors above 2:
164
+
165
+ ```bash
166
+ crabline --json serve slack --credentials-fd 3 3< .crabline/serve-credentials.json
167
+ ```
168
+
169
+ The JSON fields are `accessToken`, `adminToken`, `botToken`, and
170
+ `signingSecret`. File-descriptor values override environment fallbacks. Do not
171
+ pass descriptors above 2 through package runners such as `pnpm`; use fd 0
172
+ instead. Keep credential files owner-readable or pipe the JSON directly from a
173
+ secret manager.
174
+
175
+ Ready files contain generated provider and admin credentials. Crabline creates
176
+ or replaces them with POSIX mode `0600`, but the parent directory still needs
177
+ to be private. Exclude ready files from version control and CI artifact
178
+ collection, and delete them after use. On non-POSIX or shared filesystems,
179
+ verify the effective ACLs before publishing one.
180
+
141
181
  Library callers can pass `onEvent` to `startCrablineServer`, an individual
142
182
  provider server, or `startOpenClawCrablineAdapter`. Crabline awaits the callback
143
183
  after appending each API/admin event to `recorderPath`, so callers can react in
144
184
  process while retaining the JSONL artifact as durable evidence.
145
185
 
186
+ Recorder files should normally have one filesystem name. If multiple processes
187
+ cannot share the same OS account home, the home is read-only, or they write
188
+ through hardlinks to the same recorder inode, set
189
+ `CRABLINE_RECORDER_LOCK_DIR` to the same absolute writable directory for every
190
+ writer. Pre-create that directory with the ownership, group, or ACLs required
191
+ by those writers. Crabline refuses hardlinked server-recorder writes without
192
+ this shared lock namespace. The configured path must be canonical and contain
193
+ no symlink components. Scope each lock directory to one recorder filesystem;
194
+ lock identities omit device numbers so containers that mount the same inode
195
+ under different device IDs still coordinate. Otherwise, Unix writers coordinate
196
+ through the OS account's `~/.cache/crabline/locks/server-recorder` namespace.
197
+
146
198
  Mattermost:
147
199
 
148
200
  ```bash
@@ -153,6 +205,7 @@ The JSON manifest contains:
153
205
 
154
206
  - `baseUrl`: OpenClaw `channels.mattermost.baseUrl` / `MATTERMOST_URL`
155
207
  - `botToken`: OpenClaw `channels.mattermost.botToken` / `MATTERMOST_BOT_TOKEN`
208
+ - `webhookToken` / `MATTERMOST_TOKEN`: verifies native outgoing webhook posts
156
209
  - `endpoints.websocketUrl`: native Mattermost WebSocket endpoint
157
210
  - `adminToken`: send this as the `X-Crabline-Admin-Token` header when posting
158
211
  test user messages
@@ -163,7 +216,10 @@ The server implements a Mattermost API subset for text DM and channel
163
216
  roundtrips, including REST authentication/status codes, WebSocket
164
217
  authentication and `hello`, sequenced events, typing, and post
165
218
  create/edit/delete events. Admin ingress is only the test control plane;
166
- injected messages are delivered to clients as native `posted` events.
219
+ injected messages require native 26-character lowercase channel/user IDs and
220
+ are delivered to clients as channel-scoped native `posted` events. Optional
221
+ `channelName` and `channelDisplayName` values populate the native event fields.
222
+ `POST /api/v4/posts` requires a JSON media type.
167
223
 
168
224
  Matrix:
169
225
 
@@ -187,7 +243,9 @@ The server implements an unencrypted Matrix Client-Server API subset including
187
243
  `whoami`, filters, push rules, joined rooms and members, room state, `/sync`,
188
244
  room event sends, typing, and read receipts. Admin ingress is only the test
189
245
  control plane; injected messages are delivered to clients as native
190
- `m.room.message` events through `/sync`.
246
+ `m.room.message` events through `/sync`. Optional `roomName` sets newly created
247
+ room state, `direct: true` publishes `m.direct` account data, and `threadId`
248
+ accepts the raw Matrix root event ID used in the native thread relation.
191
249
 
192
250
  Slack:
193
251
 
@@ -208,8 +266,8 @@ The JSON manifest contains:
208
266
  - `endpoints.eventsUrl`: local Slack Events API endpoint
209
267
  - `recorderPath`: JSONL file of local provider API/admin traffic
210
268
 
211
- The admin token is generated randomly unless `--admin-token <token>` is
212
- provided. Implemented Slack Web API endpoints include `auth.test`,
269
+ The admin token is generated randomly unless `adminToken` is supplied through
270
+ the credential ingress above. Implemented Slack Web API endpoints include `auth.test`,
213
271
  `chat.postMessage`, `conversations.open`, `conversations.info`,
214
272
  `conversations.history`, and `conversations.replies`.
215
273
 
@@ -251,16 +309,19 @@ The JSON manifest contains:
251
309
  messages; OpenClaw reads them through Telegram `getUpdates`
252
310
  - `recorderPath`: JSONL file of local provider API/admin traffic
253
311
 
254
- The admin token is generated randomly unless `--admin-token <token>` is
255
- provided. The inbound endpoint rejects requests without the matching admin
256
- header (or `Authorization: Bearer <token>`).
312
+ The admin token is generated randomly unless `adminToken` is supplied through
313
+ the credential ingress above. The inbound endpoint rejects requests without
314
+ the matching admin header (or `Authorization: Bearer <token>`).
257
315
 
258
316
  Implemented Telegram Bot API endpoints include `getMe`, `sendMessage`,
259
317
  `sendPhoto`, `sendDocument`, `sendVideo`, `sendAudio`, `sendAnimation`, `editMessageText`,
260
318
  `deleteMessage`, `setMessageReaction`, `createForumTopic`, `editForumTopic`,
261
319
  `pinChatMessage`, `unpinChatMessage`, `getUpdates`, `deleteWebhook`,
262
320
  `setWebhook`, `setMyCommands`, `deleteMyCommands`, `sendChatAction`, and
263
- `answerCallbackQuery`.
321
+ `answerCallbackQuery`. Webhook secrets use Telegram's 1-256 character
322
+ letter/digit/underscore/hyphen alphabet. Text and caption fields enforce native
323
+ string types and 4,096/1,024 UTF-16 limits, entity metadata is retained, and
324
+ `@username` method targets resolve to numeric `Chat.id` values.
264
325
 
265
326
  WhatsApp:
266
327
 
@@ -301,7 +362,8 @@ Group outbound uses sender-key `skmsg` encryption and is outside this supported
301
362
  subset, so OpenClaw Crabline outbound targets are direct users only. Group
302
363
  inbound injection remains supported. The WebSocket endpoint rejects clients
303
364
  that do not present the access token embedded in the manifest URL. The admin
304
- token is generated randomly unless `--admin-token <token>` is provided.
365
+ token is generated randomly unless `adminToken` is supplied through the
366
+ credential ingress above.
305
367
 
306
368
  OpenClaw bridge callers should post injected user messages with the
307
369
  `providerUrl`, `providerHeaders`, and `providerBody` returned by
@@ -331,7 +393,9 @@ API methods accept GET query parameters or POST requests. Admin
331
393
  ingress injects a native Zalo update into the active polling or webhook
332
394
  transport. Webhook delivery posts the native `{ event_name, message }` update
333
395
  directly. OpenClaw-specific endpoint, config, and target mapping remain in the
334
- isolated bridge.
396
+ isolated bridge. Programmatic `startZaloServer()` callers can tune the retained
397
+ polling queue with `maxPendingInboundEvents` and `maxPendingInboundBytes`; the
398
+ byte limit defaults to 64 MiB.
335
399
 
336
400
  The admin ingress accepts JSON like:
337
401
 
@@ -367,13 +431,34 @@ target:
367
431
  Examples:
368
432
 
369
433
  - Slack conversations: `C1234567890`, `G1234567890`, or `D1234567890`
434
+ - Slack direct sends may also target user IDs such as `U1234567890` or
435
+ `W1234567890`
370
436
  - Slack threads: `1700000000.000100`
371
437
  - Telegram chats: `-1001234567890` or `@channelusername`
372
438
  - Telegram topics: `42`
373
- - WhatsApp Cloud API users: digits-only `wa_id` values such as `15551234567`
374
- - WhatsApp groups: `120363001234567890@g.us`
439
+ - Telegram username targets require `@`, contain 5-32 letters, digits, or
440
+ underscores, and normalize to lowercase. Numeric chat IDs must be nonzero and
441
+ have an absolute value no greater than `2^52 - 1`.
442
+ - Built-in WhatsApp Cloud API users: digits-only `wa_id` values such as
443
+ `15551234567`
444
+ - Built-in WhatsApp Cloud API fixtures do not support `threadId` targets.
445
+ - OpenClaw WhatsApp bridge users: `15551234567@s.whatsapp.net`
446
+ (legacy `15551234567@c.us` inputs are accepted and canonicalized)
447
+ - OpenClaw WhatsApp bridge groups: `120363001234567890@g.us`
375
448
  - Discord channels and threads: Discord snowflake ids such as
376
449
  `123456789012345678`
450
+ - iMessage recipients: E.164 phone numbers such as `+15551234567`, email
451
+ addresses such as `user@example.com`, or chat GUIDs such as
452
+ `iMessage;-;chat-guid` and `SMS;+;chat-guid`
453
+ - Matrix rooms: scoped IDs such as `!abcdef:matrix.org` or Matrix v12
454
+ domainless room IDs; thread IDs are raw root event IDs such as
455
+ `$eventid:matrix.org`
456
+ - Mattermost channels, users, and root posts: exactly 26 lowercase alphanumeric
457
+ characters, such as `abcdefghijklmnopqrstuvwx12`
458
+ - Microsoft Teams: non-empty opaque Bot Connector `conversation.id` values such
459
+ as `a:opaque-conversation-id` or `19:conversation@thread.v2`
460
+ - Zalo users, OAs, and chats: non-whitespace provider IDs such as `user-1` or
461
+ `group-1`
377
462
 
378
463
  ## Webhooks
379
464
 
@@ -403,6 +488,8 @@ Nested message payloads are also accepted:
403
488
  ```
404
489
 
405
490
  Malformed webhooks return `400`, and non-JSON requests return `415`.
491
+ Configured webhook paths must be canonical URL pathnames without normalization,
492
+ query, or fragment ambiguity.
406
493
 
407
494
  ## Evidence Flow
408
495
 
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { runCli } from "../cli/program.js";
3
- const exitCode = await runCli(process.argv);
3
+ const exitCode = await runCli(process.argv, {
4
+ forceExit: (code) => process.exit(code),
5
+ });
4
6
  if (exitCode !== 0) {
5
7
  process.exitCode = exitCode;
6
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"crabline.js","sourceRoot":"","sources":["../../../src/bin/crabline.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC5C,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;IACnB,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAC9B,CAAC","sourcesContent":["#!/usr/bin/env node\n\nimport { runCli } from \"../cli/program.js\";\n\nconst exitCode = await runCli(process.argv);\nif (exitCode !== 0) {\n process.exitCode = exitCode;\n}\n"]}
1
+ {"version":3,"file":"crabline.js","sourceRoot":"","sources":["../../../src/bin/crabline.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;CACxC,CAAC,CAAC;AACH,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;IACnB,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAC9B,CAAC","sourcesContent":["#!/usr/bin/env node\n\nimport { runCli } from \"../cli/program.js\";\n\nconst exitCode = await runCli(process.argv, {\n forceExit: (code) => process.exit(code),\n});\nif (exitCode !== 0) {\n process.exitCode = exitCode;\n}\n"]}
@@ -16,6 +16,10 @@ type ProgramDependencies = {
16
16
  removeReadyFile?: (filePath: string, expectedContents: string, expectedIdentity: ReadyFileIdentity) => Promise<void>;
17
17
  startServer?: (params: StartCrablineServerParams) => Promise<StartedCrablineServer>;
18
18
  };
19
+ type RunCliOptions = {
20
+ dependencies?: ProgramDependencies;
21
+ forceExit?: (code: number) => never;
22
+ };
19
23
  export declare function createProgram(setExitCode?: SetExitCode, dependencies?: ProgramDependencies): Command;
20
24
  type ShutdownSignal = "SIGINT" | "SIGTERM";
21
25
  type SignalTarget = {
@@ -25,5 +29,5 @@ type SignalTarget = {
25
29
  export declare function publishReadyFile(filePath: string, contents: string): Promise<ReadyFileIdentity>;
26
30
  export declare function removeReadyFile(filePath: string, expectedContents: string, expectedIdentity: ReadyFileIdentity): Promise<void>;
27
31
  export declare function waitForShutdown(close: () => Promise<void>, signalTarget?: SignalTarget): Promise<void>;
28
- export declare function runCli(argv: string[]): Promise<number>;
32
+ export declare function runCli(argv: string[], options?: RunCliOptions): Promise<number>;
29
33
  export {};