@rebasepro/server 0.24.0 → 0.24.1-canary.gcb918fc

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 (224) hide show
  1. package/README.md +27 -2
  2. package/dist/GCSStorageController-fv6JAZ87.js +402 -0
  3. package/dist/GCSStorageController-fv6JAZ87.js.map +1 -0
  4. package/dist/S3StorageController-BNg-pXiY.js +480 -0
  5. package/dist/S3StorageController-BNg-pXiY.js.map +1 -0
  6. package/dist/api/mount-path.d.ts +30 -0
  7. package/dist/api/mount.d.ts +6 -13
  8. package/dist/api/rest/api-generator.d.ts +53 -1
  9. package/dist/api/rest/auth-collection-writes.d.ts +28 -21
  10. package/dist/api/rest/field-access-query.d.ts +28 -8
  11. package/dist/api/rest/field-ops.d.ts +19 -7
  12. package/dist/api/rest/query-body.d.ts +10 -0
  13. package/dist/api/rest/write-validation.d.ts +7 -5
  14. package/dist/api/schema-editor-routes.d.ts +10 -1
  15. package/dist/api/sql-export-routes.d.ts +8 -0
  16. package/dist/api/types.d.ts +35 -0
  17. package/dist/{ast-schema-editor-CWqS_sLJ.js → ast-schema-editor-mCeSC03x.js} +3 -3
  18. package/dist/{ast-schema-editor-CWqS_sLJ.js.map → ast-schema-editor-mCeSC03x.js.map} +1 -1
  19. package/dist/auth/access.d.ts +57 -8
  20. package/dist/auth/admin-user-ops.d.ts +24 -2
  21. package/dist/auth/admin-users-route.d.ts +1 -0
  22. package/dist/auth/api-keys/api-key-middleware.d.ts +10 -3
  23. package/dist/auth/api-keys/api-key-routes.d.ts +4 -1
  24. package/dist/auth/builtin-auth-adapter.d.ts +13 -0
  25. package/dist/auth/email-change-routes.d.ts +3 -0
  26. package/dist/auth/expired-token-sweep.d.ts +5 -1
  27. package/dist/auth/interfaces.d.ts +10 -0
  28. package/dist/auth/jwks-routes.d.ts +5 -1
  29. package/dist/auth/jwt-crypto.d.ts +7 -0
  30. package/dist/auth/jwt-keys.d.ts +4 -0
  31. package/dist/auth/jwt.d.ts +282 -166
  32. package/dist/auth/magic-link-routes.d.ts +3 -0
  33. package/dist/auth/mfa-crypto.d.ts +9 -3
  34. package/dist/auth/mfa-gate.d.ts +4 -2
  35. package/dist/auth/mfa-routes.d.ts +6 -0
  36. package/dist/auth/middleware.d.ts +9 -2
  37. package/dist/auth/otp-routes.d.ts +3 -0
  38. package/dist/auth/rate-limiter.d.ts +61 -34
  39. package/dist/auth/registration-policy.d.ts +17 -0
  40. package/dist/auth/require-auth.d.ts +1 -1
  41. package/dist/auth/routes.d.ts +16 -0
  42. package/dist/auth/session-routes.d.ts +6 -0
  43. package/dist/auth/user-picking.d.ts +37 -0
  44. package/dist/auth/verify-credential.d.ts +25 -4
  45. package/dist/{auth-DMLngxn_.js → auth-GnONzteu.js} +2869 -1871
  46. package/dist/auth-GnONzteu.js.map +1 -0
  47. package/dist/auth_adapter-CIItCTc8.js +21 -0
  48. package/dist/auth_adapter-CIItCTc8.js.map +1 -0
  49. package/dist/backend/create-backend.d.ts +281 -0
  50. package/dist/backend/default-backend.d.ts +35 -0
  51. package/dist/backend/options.d.ts +912 -0
  52. package/dist/backend/scope.d.ts +23 -0
  53. package/dist/backend/services.d.ts +54 -0
  54. package/dist/backend-DTAOsLQc.js.map +1 -1
  55. package/dist/backup/backup-common.d.ts +14 -3
  56. package/dist/backup/backup-routes.d.ts +23 -2
  57. package/dist/backup/backup-storage.d.ts +3 -1
  58. package/dist/backup/index.d.ts +3 -1
  59. package/dist/{backup-CN0s50D2.js → backup-BnvkSLHi.js} +176 -35
  60. package/dist/backup-BnvkSLHi.js.map +1 -0
  61. package/dist/boot/boot.d.ts +2 -2
  62. package/dist/boot/driver.d.ts +3 -0
  63. package/dist/boot/env.d.ts +9 -2
  64. package/dist/boot/http-server.d.ts +22 -0
  65. package/dist/boot/options.d.ts +16 -1
  66. package/dist/boot/provision.d.ts +4 -2
  67. package/dist/boot/runtime-cors.d.ts +17 -0
  68. package/dist/boot/sources.d.ts +2 -0
  69. package/dist/boot/static-routing.d.ts +9 -0
  70. package/dist/{contract-routes-fz8i4pxs.js → contract-routes-Ey6ftnKH.js} +4 -20
  71. package/dist/contract-routes-Ey6ftnKH.js.map +1 -0
  72. package/dist/cron/cron-loader.d.ts +77 -18
  73. package/dist/cron/cron-routes.d.ts +1 -1
  74. package/dist/cron/cron-scheduler.d.ts +69 -3
  75. package/dist/cron/cron-store.d.ts +33 -5
  76. package/dist/cron/define-cron.d.ts +6 -2
  77. package/dist/cron/index.d.ts +3 -3
  78. package/dist/cron-loader-B-u0snqq.js +202 -0
  79. package/dist/cron-loader-B-u0snqq.js.map +1 -0
  80. package/dist/{cron-routes-Bc-SB0Se.js → cron-routes-OD6BstUj.js} +27 -4
  81. package/dist/cron-routes-OD6BstUj.js.map +1 -0
  82. package/dist/{cron-scheduler-CYQgco86.js → cron-scheduler-idtLPoN-.js} +299 -33
  83. package/dist/cron-scheduler-idtLPoN-.js.map +1 -0
  84. package/dist/cron-store-CZ30ZBi-.js +577 -0
  85. package/dist/cron-store-CZ30ZBi-.js.map +1 -0
  86. package/dist/email/smtp-email-service.d.ts +23 -0
  87. package/dist/email/types.d.ts +18 -0
  88. package/dist/env.d.ts +0 -37
  89. package/dist/filter-dialect-O1HK6Nvr.js +1628 -0
  90. package/dist/filter-dialect-O1HK6Nvr.js.map +1 -0
  91. package/dist/{function-loader-D7o5Epjj.js → function-loader-iKhOZatS.js} +68 -38
  92. package/dist/function-loader-iKhOZatS.js.map +1 -0
  93. package/dist/{function-routes-CaNG4waN.js → function-routes-j9TwpvQe.js} +5 -4
  94. package/dist/function-routes-j9TwpvQe.js.map +1 -0
  95. package/dist/functions/context.d.ts +9 -0
  96. package/dist/functions/define-function.d.ts +10 -6
  97. package/dist/functions/function-loader.d.ts +75 -18
  98. package/dist/functions/function-routes.d.ts +2 -1
  99. package/dist/functions/index.d.ts +5 -4
  100. package/dist/functions/index.js +42 -13
  101. package/dist/functions/index.js.map +1 -1
  102. package/dist/functions/internal.d.ts +2 -2
  103. package/dist/functions/proxy.d.ts +6 -2
  104. package/dist/functions/request-timeout.d.ts +7 -5
  105. package/dist/history/history-routes.d.ts +9 -0
  106. package/dist/history/retention-sweep.d.ts +81 -0
  107. package/dist/{history-recorder-Nr8zLvoU.js → history-recorder-BfWRwmPy.js} +3 -3
  108. package/dist/{history-recorder-Nr8zLvoU.js.map → history-recorder-BfWRwmPy.js.map} +1 -1
  109. package/dist/{history-store-rcAm_xFR.js → history-store-DPofGVDp.js} +2 -2
  110. package/dist/{history-store-rcAm_xFR.js.map → history-store-DPofGVDp.js.map} +1 -1
  111. package/dist/index.d.ts +23 -10
  112. package/dist/index.es.js +24423 -20038
  113. package/dist/index.es.js.map +1 -1
  114. package/dist/init/docs.d.ts +27 -10
  115. package/dist/init/process-safety.d.ts +7 -2
  116. package/dist/init/shutdown.d.ts +18 -3
  117. package/dist/init.d.ts +49 -865
  118. package/dist/internal-tables-L2t39RdT.js +136 -0
  119. package/dist/internal-tables-L2t39RdT.js.map +1 -0
  120. package/dist/jobs/job-queue.d.ts +8 -0
  121. package/dist/jobs/job-store.d.ts +24 -0
  122. package/dist/jobs/types.d.ts +25 -4
  123. package/dist/{jobs-DqYNfquG.js → jobs-BCbflZj2.js} +234 -24
  124. package/dist/jobs-BCbflZj2.js.map +1 -0
  125. package/dist/{jwt-R6bSPMjk.js → jwt-BlvuKoR6.js} +529 -454
  126. package/dist/jwt-BlvuKoR6.js.map +1 -0
  127. package/dist/{keys-GAVZqbqx.js → keys-COzQ2aE8.js} +2 -2
  128. package/dist/{keys-GAVZqbqx.js.map → keys-COzQ2aE8.js.map} +1 -1
  129. package/dist/load-failure-L5hvfDoG.js +80 -0
  130. package/dist/load-failure-L5hvfDoG.js.map +1 -0
  131. package/dist/mcp/mcp-routes.d.ts +6 -0
  132. package/dist/mcp/mcp-tools.d.ts +8 -0
  133. package/dist/mcp/oauth-routes.d.ts +7 -0
  134. package/dist/metrics/index.d.ts +18 -0
  135. package/dist/metrics/pool-wait.d.ts +50 -0
  136. package/dist/offline-QNQgsPOq-B2yGeXkn.js +3305 -0
  137. package/dist/offline-QNQgsPOq-B2yGeXkn.js.map +1 -0
  138. package/dist/offline-store-Cm5sAX81-CALiO4Gn.js +1915 -0
  139. package/dist/offline-store-Cm5sAX81-CALiO4Gn.js.map +1 -0
  140. package/dist/{openapi-generator-DAq_XVDu.js → openapi-generator-D9zUQmEp.js} +366 -82
  141. package/dist/openapi-generator-D9zUQmEp.js.map +1 -0
  142. package/dist/policy-PdzX-Opd.js +121 -0
  143. package/dist/policy-PdzX-Opd.js.map +1 -0
  144. package/dist/project_manifest-R6y_KHms.js +59 -0
  145. package/dist/project_manifest-R6y_KHms.js.map +1 -0
  146. package/dist/{proxy-qRlqeUmO.js → proxy-CkTlMGmh.js} +4 -3
  147. package/dist/proxy-CkTlMGmh.js.map +1 -0
  148. package/dist/{query-parser-BgiKJKvc.js → query-parser-4WkMoA_K.js} +510 -15
  149. package/dist/query-parser-4WkMoA_K.js.map +1 -0
  150. package/dist/{request-timeout-DgH7j8qO.js → request-timeout-Dnl2_OBc.js} +15 -8
  151. package/dist/request-timeout-Dnl2_OBc.js.map +1 -0
  152. package/dist/resumable-upload-threshold-CKv-Ry0l.js +24 -0
  153. package/dist/resumable-upload-threshold-CKv-Ry0l.js.map +1 -0
  154. package/dist/schema-edit/apply-schema-change.d.ts +10 -0
  155. package/dist/schema-edit/local-source.d.ts +29 -0
  156. package/dist/schema-edit/remote-source.d.ts +13 -3
  157. package/dist/schema-edit/source-editor.d.ts +28 -0
  158. package/dist/{schema-editor-routes-oIyuWl3L.js → schema-editor-routes-C11Tumyd.js} +54 -10
  159. package/dist/schema-editor-routes-C11Tumyd.js.map +1 -0
  160. package/dist/services/outbound-post.d.ts +50 -0
  161. package/dist/services/outbound-url-guard.d.ts +34 -5
  162. package/dist/services/routed-realtime-service.d.ts +5 -0
  163. package/dist/services/webhook-service.d.ts +66 -14
  164. package/dist/singleton.d.ts +9 -5
  165. package/dist/soft-delete-params-DfV3vVN5.js +668 -0
  166. package/dist/soft-delete-params-DfV3vVN5.js.map +1 -0
  167. package/dist/sql-export-routes-ClRwzIsC.js +240 -0
  168. package/dist/sql-export-routes-ClRwzIsC.js.map +1 -0
  169. package/dist/{src-CatHFUym.js → src-D5Y3N-S4.js} +2 -1
  170. package/dist/{src-CatHFUym.js.map → src-D5Y3N-S4.js.map} +1 -1
  171. package/dist/storage/GCSStorageController.d.ts +46 -2
  172. package/dist/storage/LocalStorageController.d.ts +67 -2
  173. package/dist/storage/S3StorageController.d.ts +37 -3
  174. package/dist/storage/image-transform.d.ts +5 -0
  175. package/dist/storage/maintenance-routes.d.ts +23 -0
  176. package/dist/storage/maintenance.d.ts +126 -0
  177. package/dist/storage/rendition-cache.d.ts +9 -11
  178. package/dist/storage/request-principals.d.ts +30 -0
  179. package/dist/storage/routes.d.ts +20 -0
  180. package/dist/storage/source-variables.d.ts +10 -0
  181. package/dist/storage/streams.d.ts +42 -0
  182. package/dist/storage/tus-handler.d.ts +46 -2
  183. package/dist/storage/types.d.ts +82 -7
  184. package/dist/storage/upload-validation.d.ts +13 -0
  185. package/dist/storage-resumable-VO-cMpse-C_YX71pO.js +125 -0
  186. package/dist/storage-resumable-VO-cMpse-C_YX71pO.js.map +1 -0
  187. package/dist/strings.es-BeZWAodn.js +256 -0
  188. package/dist/strings.es-BeZWAodn.js.map +1 -0
  189. package/dist/upload-validation-Dd-fnsbA.js +172 -0
  190. package/dist/upload-validation-Dd-fnsbA.js.map +1 -0
  191. package/dist/utils/byte-size.d.ts +10 -0
  192. package/dist/utils/compression.d.ts +6 -0
  193. package/dist/utils/load-failure.d.ts +14 -0
  194. package/package.json +5 -5
  195. package/dist/GCSStorageController-BSiP1c-f.js +0 -256
  196. package/dist/GCSStorageController-BSiP1c-f.js.map +0 -1
  197. package/dist/S3StorageController-CAwFRgjV.js +0 -276
  198. package/dist/S3StorageController-CAwFRgjV.js.map +0 -1
  199. package/dist/auth-DMLngxn_.js.map +0 -1
  200. package/dist/backup-CN0s50D2.js.map +0 -1
  201. package/dist/contract-routes-fz8i4pxs.js.map +0 -1
  202. package/dist/cron-loader-CwaANlOG.js +0 -118
  203. package/dist/cron-loader-CwaANlOG.js.map +0 -1
  204. package/dist/cron-routes-Bc-SB0Se.js.map +0 -1
  205. package/dist/cron-scheduler-CYQgco86.js.map +0 -1
  206. package/dist/cron-store-D2Q9-Aco.js +0 -300
  207. package/dist/cron-store-D2Q9-Aco.js.map +0 -1
  208. package/dist/dynamic-import-X40pTZUQ.js +0 -23
  209. package/dist/dynamic-import-X40pTZUQ.js.map +0 -1
  210. package/dist/function-loader-D7o5Epjj.js.map +0 -1
  211. package/dist/function-routes-CaNG4waN.js.map +0 -1
  212. package/dist/jobs-DqYNfquG.js.map +0 -1
  213. package/dist/jwt-R6bSPMjk.js.map +0 -1
  214. package/dist/openapi-generator-DAq_XVDu.js.map +0 -1
  215. package/dist/proxy-qRlqeUmO.js.map +0 -1
  216. package/dist/query-parser-BgiKJKvc.js.map +0 -1
  217. package/dist/request-timeout-DgH7j8qO.js.map +0 -1
  218. package/dist/schema-editor-routes-oIyuWl3L.js.map +0 -1
  219. package/dist/soft-delete-params-BWPilMPF.js +0 -59
  220. package/dist/soft-delete-params-BWPilMPF.js.map +0 -1
  221. package/dist/src-I3aG1PcY.js +0 -6870
  222. package/dist/src-I3aG1PcY.js.map +0 -1
  223. package/dist/types-BfKcm9do.js +0 -39
  224. package/dist/types-BfKcm9do.js.map +0 -1
@@ -0,0 +1,50 @@
1
+ import { type AddressJudge, type OutboundUrlGuardOptions } from "./outbound-url-guard.js";
2
+ /**
3
+ * How the webhook dispatcher sends a POST to a destination that came from data.
4
+ *
5
+ * On Node, through an http(s) Agent whose `lookup` is the destination guard's
6
+ * ({@link guardedLookup}): the name is resolved once per new connection, every
7
+ * address it answers with is judged, and the socket connects to an address
8
+ * that was. It used to be validate-then-fetch — a `dns.lookup` per delivery
9
+ * attempt on the libuv threadpool, and then a second resolution inside `fetch`
10
+ * that the guard never saw, so a TTL-0 name that flipped between the two
11
+ * could still land on a blocked address. Keep-alive connections are reused, so
12
+ * a steady stream of deliveries to one receiver resolves its name about once.
13
+ *
14
+ * With `allowPrivateNetworks` there is nothing to judge, and on a runtime
15
+ * without `node:http` there is no Agent to hand a resolver to: both send with
16
+ * `fetch`, after {@link assertAllowedOutboundUrl}, as before.
17
+ *
18
+ * Internal to the server.
19
+ */
20
+ /** What the dispatcher reads of a response, from either transport. */
21
+ export interface OutboundResponse {
22
+ status: number;
23
+ header(name: string): string | null;
24
+ /** The body as a stream, so a reader can stop at a cap and cancel the rest. */
25
+ body: ReadableStream<Uint8Array> | null;
26
+ text(): Promise<string>;
27
+ }
28
+ export interface OutboundPostInit {
29
+ headers: Record<string, string>;
30
+ body: string;
31
+ /** Aborts the request — and the response body, while it is being read. */
32
+ signal: AbortSignal;
33
+ }
34
+ /**
35
+ * POST `body` to `rawUrl`, never following a redirect: a redirect would send
36
+ * the POST — signature and all — somewhere the guard never judged.
37
+ *
38
+ * @throws BlockedUrlError when the guard refuses the destination.
39
+ */
40
+ export type OutboundPost = (rawUrl: string, init: OutboundPostInit) => Promise<OutboundResponse>;
41
+ export declare function createOutboundPost(options?: OutboundUrlGuardOptions): OutboundPost;
42
+ /** Validate-then-fetch: the path for `allowPrivateNetworks`, and for a runtime without `node:http`. */
43
+ export declare function createFetchPost(options?: OutboundUrlGuardOptions): OutboundPost;
44
+ /**
45
+ * The guarded Node transport, or `undefined` on a runtime without
46
+ * `node:http`. Loaded on use, like the guard's own resolver, so that this
47
+ * module imports on a runtime that has neither. `judge` is for tests that
48
+ * need a receiver on loopback.
49
+ */
50
+ export declare function createNodePost(options?: OutboundUrlGuardOptions, judge?: AddressJudge): Promise<OutboundPost | undefined>;
@@ -1,3 +1,4 @@
1
+ import type { LookupFunction } from "node:net";
1
2
  /**
2
3
  * Refusal to send a request to a destination the guard does not allow.
3
4
  *
@@ -29,6 +30,8 @@ export interface OutboundUrlGuardOptions {
29
30
  * outbound call whose destination comes from data.
30
31
  */
31
32
  export declare function blockedAddressReason(address: string): string | null;
33
+ /** Why an address may not be connected to, or `null`: {@link blockedAddressReason}. */
34
+ export type AddressJudge = (address: string) => string | null;
32
35
  /**
33
36
  * Resolve and validate a destination before anything connects to it.
34
37
  *
@@ -40,14 +43,40 @@ export declare function blockedAddressReason(address: string): string | null;
40
43
  * Known limit: this is validate-then-fetch. Between the lookup here and the
41
44
  * connection the runtime makes there is a second resolution this code does not
42
45
  * see, so a TTL-0 name that flips between answers can still land on a blocked
43
- * address. Closing that needs the socket pinned to the address checked here,
44
- * which Node's global `fetch` does not expose without an undici dispatcher.
45
- * The redirect policy in {@link WebhookDispatcher} closes the much wider
46
- * version of the same hole — a receiver that simply *points* at the internal
47
- * address.
46
+ * address. On Node the webhook dispatcher does not use this: it checks the
47
+ * address it connects to, through {@link guardedLookup}. This is the check for
48
+ * a runtime whose `fetch` cannot be handed a resolver.
48
49
  *
49
50
  * @throws BlockedUrlError when the destination is not allowed. DNS failures
50
51
  * are rethrown as they are, so callers can tell "never send this" from
51
52
  * "could not send this right now".
52
53
  */
53
54
  export declare function assertAllowedOutboundUrl(rawUrl: string, options?: OutboundUrlGuardOptions): Promise<URL>;
55
+ /**
56
+ * Every check of {@link assertAllowedOutboundUrl} but the lookup, for a
57
+ * connection that resolves the name through {@link guardedLookup}. The scheme,
58
+ * the internal names and an address written into the URL are judged here —
59
+ * a connection to a literal address asks no resolver, so nothing else would.
60
+ *
61
+ * Internal to the server: not exported from the package.
62
+ */
63
+ export declare function assertAllowedBeforeConnecting(rawUrl: string, options?: OutboundUrlGuardOptions): URL;
64
+ /**
65
+ * A `dns.lookup` for an http(s) Agent that refuses to connect anywhere the
66
+ * guard would not send: it resolves the name, judges *every* address it got,
67
+ * and hands the connection only addresses it judged — so the address checked
68
+ * is the address connected to. Validate-then-fetch resolves twice, and a
69
+ * name whose TTL-0 record flips between the two lookups lands on whatever the
70
+ * second one says.
71
+ *
72
+ * Called once per new connection, not per request: a keep-alive connection
73
+ * is to an address already judged. Nothing is cached — an "allowed" verdict
74
+ * that outlived its lookup would be the rebinding window again.
75
+ *
76
+ * Fails with {@link BlockedUrlError}, which the connection reports as its
77
+ * error; a resolver failure is reported as itself.
78
+ *
79
+ * Internal to the server: not exported from the package. `judge` is for the
80
+ * tests that need a receiver on loopback; nothing else passes one.
81
+ */
82
+ export declare function guardedLookup(options?: OutboundUrlGuardOptions, judge?: AddressJudge): LookupFunction;
@@ -26,6 +26,11 @@ export interface WsRealtimeService extends RealtimeProvider {
26
26
  * interface and the socket's calls so it cannot happen twice.
27
27
  */
28
28
  rescopeClient(clientId: string, authContext: unknown): Promise<void>;
29
+ /**
30
+ * What the client opted into when it opened the socket (`?rebase_caps=`).
31
+ * Optional: a provider that sends nothing depending on one ignores them.
32
+ */
33
+ setClientOptIns?(clientId: string, optIns: ReadonlySet<string>): void;
29
34
  /**
30
35
  * Whether this provider actually implements channels, presence and
31
36
  * broadcast. Declared by the provider rather than inferred, because the
@@ -23,6 +23,11 @@ export interface WebhookDeliveryResult {
23
23
  statusCode: number;
24
24
  responseBody: string;
25
25
  success: boolean;
26
+ /**
27
+ * The attempt this result is from, counting from 1. `0` for a delivery
28
+ * refused before any attempt: an in-process queue that was full, with
29
+ * `statusCode: 0` and `responseBody: "queue full"`.
30
+ */
26
31
  attemptNumber: number;
27
32
  }
28
33
  export interface WebhookDispatcherOptions {
@@ -48,7 +53,8 @@ export interface WebhookDispatcherOptions {
48
53
  */
49
54
  onDelivery?: (result: WebhookDeliveryResult) => void;
50
55
  /**
51
- * Hostname resolver used by the destination guard. Defaults to
56
+ * Hostname resolver used by the destination guard — once per new
57
+ * connection, and its answer is where the connection goes. Defaults to
52
58
  * `dns.lookup`; injected by tests so a unit suite never asks a resolver.
53
59
  */
54
60
  lookup?: (hostname: string) => Promise<string[]>;
@@ -61,27 +67,48 @@ export interface WebhookDispatcherOptions {
61
67
  */
62
68
  jobQueue?: JobQueueClient;
63
69
  }
70
+ /**
71
+ * What a delivery queued as a job carries: the webhook's id — never its
72
+ * secret — and the delivery id every attempt sends, so a receiver can
73
+ * deduplicate the queue's at-least-once retries. Rows queued before the id was
74
+ * stored have none; the job's own id stands in for it.
75
+ */
76
+ export interface QueuedWebhookDelivery {
77
+ webhookId: string;
78
+ event: string;
79
+ payload: Record<string, unknown>;
80
+ deliveryId?: string;
81
+ }
64
82
  export declare class WebhookDispatcher {
65
83
  private webhooks;
84
+ /** Attempts per in-process delivery, the first included. */
66
85
  private maxRetries;
86
+ /**
87
+ * The wait before each attempt after the first: 1 s before the second, 5 s
88
+ * before the third. One per retry — a third entry here was never reached.
89
+ */
67
90
  private retryDelays;
68
91
  private readonly options;
69
92
  private readonly timeoutMs;
70
- private queue;
71
- private draining;
93
+ /** In-process deliveries, one lane per webhook id. A lane is removed when it empties. */
94
+ private lanes;
95
+ /** Sends one attempt, through the destination guard — see `outbound-post.ts`. */
96
+ private readonly post;
72
97
  constructor(options?: WebhookDispatcherOptions);
73
98
  /** Register webhooks to watch */
74
99
  setWebhooks(webhooks: WebhookConfig[]): void;
75
100
  /**
76
101
  * Called when a entity changes — checks if any webhook matches, and awaits
77
- * every delivery, retries included.
102
+ * every delivery, retries included. The matching webhooks are delivered to
103
+ * at the same time, so the wait is the slowest receiver's, not the sum of
104
+ * all of them; the results come back in webhook order either way.
78
105
  *
79
106
  * **Do not await this inside a collection callback.** `afterSave` and
80
107
  * `afterDelete` run inside the write's Postgres transaction, so awaiting a
81
108
  * delivery here holds a pooled connection and the row's locks for as long
82
- * as the receiver takes to answer — up to ~36s across three attempts, per
83
- * matching webhook. Use {@link enqueueEntityChange} there; this method is
84
- * for a custom function or a job that wants the results.
109
+ * as the slowest receiver takes to answer — up to ~36s across three
110
+ * attempts. Use {@link enqueueEntityChange} there; this method is for a
111
+ * custom function or a job that wants the results.
85
112
  */
86
113
  onEntityChange(table: string, event: "INSERT" | "UPDATE" | "DELETE", id: string, entity: Record<string, unknown> | null, previousEntity?: Record<string, unknown> | null): Promise<WebhookDeliveryResult[]>;
87
114
  /**
@@ -108,6 +135,20 @@ export declare class WebhookDispatcher {
108
135
  */
109
136
  enqueueEntityChange(table: string, event: "INSERT" | "UPDATE" | "DELETE", id: string, entity: Record<string, unknown> | null, previousEntity?: Record<string, unknown> | null): void;
110
137
  private dispatchDeliveries;
138
+ /**
139
+ * Append each delivery to its webhook's lane, starting the lane if it is
140
+ * idle. Deliveries to one webhook keep their order; deliveries to
141
+ * different webhooks no longer wait for each other — one serial queue for
142
+ * every webhook meant a receiver that refused connections held every
143
+ * other receiver six seconds per queued event.
144
+ */
145
+ private enqueueInProcess;
146
+ /**
147
+ * Turn a delivery away from a full lane, and say so: through `onDelivery`
148
+ * for each one — the hook a caller of {@link enqueueEntityChange} already
149
+ * watches for failures — and in the server log once per burst.
150
+ */
151
+ private refuse;
111
152
  /**
112
153
  * Deliver one queued job, as the worker runs it.
113
154
  *
@@ -116,22 +157,33 @@ export declare class WebhookDispatcher {
116
157
  * of three job attempts is nine deliveries and about two minutes of holding
117
158
  * a worker slot — and only the queue's retries survive a restart, which is
118
159
  * the whole reason for moving.
160
+ *
161
+ * Pass the job context as the second argument —
162
+ * `ctx => dispatcher.deliverQueuedJob(ctx.payload, ctx)` — so each attempt
163
+ * sends its real `X-Webhook-Attempt`, and a row queued without a delivery
164
+ * id still sends the same `X-Webhook-Delivery` on every retry (the job's
165
+ * id). Without it, every attempt says it is the first.
119
166
  */
120
- deliverQueuedJob(job: {
121
- webhookId: string;
122
- event: string;
123
- payload: Record<string, unknown>;
167
+ deliverQueuedJob(job: QueuedWebhookDelivery, context?: {
168
+ id?: string;
169
+ attempt?: number;
124
170
  }): Promise<void>;
125
171
  /**
126
172
  * Wait for every queued delivery to finish. For graceful shutdown, and for
127
173
  * tests that need to observe what {@link enqueueEntityChange} sent.
128
174
  *
175
+ * `timeoutMs` bounds the wait: a receiver that is down costs each of its
176
+ * queued deliveries up to ~36 seconds of retries, which a shutdown cannot
177
+ * always afford. Resolves `true` when everything finished, `false` when
178
+ * the budget ran out first — those deliveries carry on in the background
179
+ * for as long as the process does. Without it, waits however long the
180
+ * deliveries take.
181
+ *
129
182
  * In-process deliveries only — with a `jobQueue` configured there is
130
183
  * nothing here to wait for, because the deliveries are rows.
131
184
  */
132
- flush(): Promise<void>;
133
- private startDraining;
134
- private drainQueue;
185
+ flush(timeoutMs?: number): Promise<boolean>;
186
+ private drainLane;
135
187
  /** The payload each matching webhook gets for this change. */
136
188
  private buildDeliveries;
137
189
  private deliverWithRetry;
@@ -7,8 +7,9 @@ import type { RebaseServerClient } from "@rebasepro/types";
7
7
  */
8
8
  export declare function _setRebaseResolver(resolve: (() => RebaseServerClient | null) | null): (() => RebaseServerClient | null) | null;
9
9
  /**
10
- * @internal Called once during server initialization to set the backing instance.
11
- * This is invoked by `initializeRebaseBackend()` — never call it manually.
10
+ * @internal Set the process default's client — what `rebase` is outside any
11
+ * backend's scope. Invoked by `setDefaultBackend()` (and so by
12
+ * `initializeRebaseBackend()`) — never call it manually.
12
13
  */
13
14
  export declare function _initRebase(client: RebaseServerClient): void;
14
15
  /**
@@ -21,10 +22,13 @@ export declare function _setRebaseMock(mockInstance: Partial<RebaseServerClient>
21
22
  */
22
23
  export declare function _resetRebaseMock(): void;
23
24
  /**
24
- * The server-side Rebase singleton.
25
+ * The server-side Rebase client, as a module-level handle.
25
26
  *
26
- * Initialized automatically during server startup. Provides access to all
27
- * app-scoped services: **data**, **auth**, **storage**, and **email**.
27
+ * Inside a request, cron run or job a backend serves, it is that backend's
28
+ * client (`backend.rebase`) — so with two backends in one process, each one's
29
+ * functions see their own. Anywhere else it is the process default's, which
30
+ * `initializeRebaseBackend` (or `setDefaultBackend`) installs. Provides access
31
+ * to all app-scoped services: **data**, **auth**, **storage**, and **email**.
28
32
  *
29
33
  * **Admin data plane** (`rebase.dataAsAdmin`):
30
34
  * Backed by the native DataDriver — calls go directly to the database without