@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.
- package/README.md +27 -2
- package/dist/GCSStorageController-fv6JAZ87.js +402 -0
- package/dist/GCSStorageController-fv6JAZ87.js.map +1 -0
- package/dist/S3StorageController-BNg-pXiY.js +480 -0
- package/dist/S3StorageController-BNg-pXiY.js.map +1 -0
- package/dist/api/mount-path.d.ts +30 -0
- package/dist/api/mount.d.ts +6 -13
- package/dist/api/rest/api-generator.d.ts +53 -1
- package/dist/api/rest/auth-collection-writes.d.ts +28 -21
- package/dist/api/rest/field-access-query.d.ts +28 -8
- package/dist/api/rest/field-ops.d.ts +19 -7
- package/dist/api/rest/query-body.d.ts +10 -0
- package/dist/api/rest/write-validation.d.ts +7 -5
- package/dist/api/schema-editor-routes.d.ts +10 -1
- package/dist/api/sql-export-routes.d.ts +8 -0
- package/dist/api/types.d.ts +35 -0
- package/dist/{ast-schema-editor-CWqS_sLJ.js → ast-schema-editor-mCeSC03x.js} +3 -3
- package/dist/{ast-schema-editor-CWqS_sLJ.js.map → ast-schema-editor-mCeSC03x.js.map} +1 -1
- package/dist/auth/access.d.ts +57 -8
- package/dist/auth/admin-user-ops.d.ts +24 -2
- package/dist/auth/admin-users-route.d.ts +1 -0
- package/dist/auth/api-keys/api-key-middleware.d.ts +10 -3
- package/dist/auth/api-keys/api-key-routes.d.ts +4 -1
- package/dist/auth/builtin-auth-adapter.d.ts +13 -0
- package/dist/auth/email-change-routes.d.ts +3 -0
- package/dist/auth/expired-token-sweep.d.ts +5 -1
- package/dist/auth/interfaces.d.ts +10 -0
- package/dist/auth/jwks-routes.d.ts +5 -1
- package/dist/auth/jwt-crypto.d.ts +7 -0
- package/dist/auth/jwt-keys.d.ts +4 -0
- package/dist/auth/jwt.d.ts +282 -166
- package/dist/auth/magic-link-routes.d.ts +3 -0
- package/dist/auth/mfa-crypto.d.ts +9 -3
- package/dist/auth/mfa-gate.d.ts +4 -2
- package/dist/auth/mfa-routes.d.ts +6 -0
- package/dist/auth/middleware.d.ts +9 -2
- package/dist/auth/otp-routes.d.ts +3 -0
- package/dist/auth/rate-limiter.d.ts +61 -34
- package/dist/auth/registration-policy.d.ts +17 -0
- package/dist/auth/require-auth.d.ts +1 -1
- package/dist/auth/routes.d.ts +16 -0
- package/dist/auth/session-routes.d.ts +6 -0
- package/dist/auth/user-picking.d.ts +37 -0
- package/dist/auth/verify-credential.d.ts +25 -4
- package/dist/{auth-DMLngxn_.js → auth-GnONzteu.js} +2869 -1871
- package/dist/auth-GnONzteu.js.map +1 -0
- package/dist/auth_adapter-CIItCTc8.js +21 -0
- package/dist/auth_adapter-CIItCTc8.js.map +1 -0
- package/dist/backend/create-backend.d.ts +281 -0
- package/dist/backend/default-backend.d.ts +35 -0
- package/dist/backend/options.d.ts +912 -0
- package/dist/backend/scope.d.ts +23 -0
- package/dist/backend/services.d.ts +54 -0
- package/dist/backend-DTAOsLQc.js.map +1 -1
- package/dist/backup/backup-common.d.ts +14 -3
- package/dist/backup/backup-routes.d.ts +23 -2
- package/dist/backup/backup-storage.d.ts +3 -1
- package/dist/backup/index.d.ts +3 -1
- package/dist/{backup-CN0s50D2.js → backup-BnvkSLHi.js} +176 -35
- package/dist/backup-BnvkSLHi.js.map +1 -0
- package/dist/boot/boot.d.ts +2 -2
- package/dist/boot/driver.d.ts +3 -0
- package/dist/boot/env.d.ts +9 -2
- package/dist/boot/http-server.d.ts +22 -0
- package/dist/boot/options.d.ts +16 -1
- package/dist/boot/provision.d.ts +4 -2
- package/dist/boot/runtime-cors.d.ts +17 -0
- package/dist/boot/sources.d.ts +2 -0
- package/dist/boot/static-routing.d.ts +9 -0
- package/dist/{contract-routes-fz8i4pxs.js → contract-routes-Ey6ftnKH.js} +4 -20
- package/dist/contract-routes-Ey6ftnKH.js.map +1 -0
- package/dist/cron/cron-loader.d.ts +77 -18
- package/dist/cron/cron-routes.d.ts +1 -1
- package/dist/cron/cron-scheduler.d.ts +69 -3
- package/dist/cron/cron-store.d.ts +33 -5
- package/dist/cron/define-cron.d.ts +6 -2
- package/dist/cron/index.d.ts +3 -3
- package/dist/cron-loader-B-u0snqq.js +202 -0
- package/dist/cron-loader-B-u0snqq.js.map +1 -0
- package/dist/{cron-routes-Bc-SB0Se.js → cron-routes-OD6BstUj.js} +27 -4
- package/dist/cron-routes-OD6BstUj.js.map +1 -0
- package/dist/{cron-scheduler-CYQgco86.js → cron-scheduler-idtLPoN-.js} +299 -33
- package/dist/cron-scheduler-idtLPoN-.js.map +1 -0
- package/dist/cron-store-CZ30ZBi-.js +577 -0
- package/dist/cron-store-CZ30ZBi-.js.map +1 -0
- package/dist/email/smtp-email-service.d.ts +23 -0
- package/dist/email/types.d.ts +18 -0
- package/dist/env.d.ts +0 -37
- package/dist/filter-dialect-O1HK6Nvr.js +1628 -0
- package/dist/filter-dialect-O1HK6Nvr.js.map +1 -0
- package/dist/{function-loader-D7o5Epjj.js → function-loader-iKhOZatS.js} +68 -38
- package/dist/function-loader-iKhOZatS.js.map +1 -0
- package/dist/{function-routes-CaNG4waN.js → function-routes-j9TwpvQe.js} +5 -4
- package/dist/function-routes-j9TwpvQe.js.map +1 -0
- package/dist/functions/context.d.ts +9 -0
- package/dist/functions/define-function.d.ts +10 -6
- package/dist/functions/function-loader.d.ts +75 -18
- package/dist/functions/function-routes.d.ts +2 -1
- package/dist/functions/index.d.ts +5 -4
- package/dist/functions/index.js +42 -13
- package/dist/functions/index.js.map +1 -1
- package/dist/functions/internal.d.ts +2 -2
- package/dist/functions/proxy.d.ts +6 -2
- package/dist/functions/request-timeout.d.ts +7 -5
- package/dist/history/history-routes.d.ts +9 -0
- package/dist/history/retention-sweep.d.ts +81 -0
- package/dist/{history-recorder-Nr8zLvoU.js → history-recorder-BfWRwmPy.js} +3 -3
- package/dist/{history-recorder-Nr8zLvoU.js.map → history-recorder-BfWRwmPy.js.map} +1 -1
- package/dist/{history-store-rcAm_xFR.js → history-store-DPofGVDp.js} +2 -2
- package/dist/{history-store-rcAm_xFR.js.map → history-store-DPofGVDp.js.map} +1 -1
- package/dist/index.d.ts +23 -10
- package/dist/index.es.js +24423 -20038
- package/dist/index.es.js.map +1 -1
- package/dist/init/docs.d.ts +27 -10
- package/dist/init/process-safety.d.ts +7 -2
- package/dist/init/shutdown.d.ts +18 -3
- package/dist/init.d.ts +49 -865
- package/dist/internal-tables-L2t39RdT.js +136 -0
- package/dist/internal-tables-L2t39RdT.js.map +1 -0
- package/dist/jobs/job-queue.d.ts +8 -0
- package/dist/jobs/job-store.d.ts +24 -0
- package/dist/jobs/types.d.ts +25 -4
- package/dist/{jobs-DqYNfquG.js → jobs-BCbflZj2.js} +234 -24
- package/dist/jobs-BCbflZj2.js.map +1 -0
- package/dist/{jwt-R6bSPMjk.js → jwt-BlvuKoR6.js} +529 -454
- package/dist/jwt-BlvuKoR6.js.map +1 -0
- package/dist/{keys-GAVZqbqx.js → keys-COzQ2aE8.js} +2 -2
- package/dist/{keys-GAVZqbqx.js.map → keys-COzQ2aE8.js.map} +1 -1
- package/dist/load-failure-L5hvfDoG.js +80 -0
- package/dist/load-failure-L5hvfDoG.js.map +1 -0
- package/dist/mcp/mcp-routes.d.ts +6 -0
- package/dist/mcp/mcp-tools.d.ts +8 -0
- package/dist/mcp/oauth-routes.d.ts +7 -0
- package/dist/metrics/index.d.ts +18 -0
- package/dist/metrics/pool-wait.d.ts +50 -0
- package/dist/offline-QNQgsPOq-B2yGeXkn.js +3305 -0
- package/dist/offline-QNQgsPOq-B2yGeXkn.js.map +1 -0
- package/dist/offline-store-Cm5sAX81-CALiO4Gn.js +1915 -0
- package/dist/offline-store-Cm5sAX81-CALiO4Gn.js.map +1 -0
- package/dist/{openapi-generator-DAq_XVDu.js → openapi-generator-D9zUQmEp.js} +366 -82
- package/dist/openapi-generator-D9zUQmEp.js.map +1 -0
- package/dist/policy-PdzX-Opd.js +121 -0
- package/dist/policy-PdzX-Opd.js.map +1 -0
- package/dist/project_manifest-R6y_KHms.js +59 -0
- package/dist/project_manifest-R6y_KHms.js.map +1 -0
- package/dist/{proxy-qRlqeUmO.js → proxy-CkTlMGmh.js} +4 -3
- package/dist/proxy-CkTlMGmh.js.map +1 -0
- package/dist/{query-parser-BgiKJKvc.js → query-parser-4WkMoA_K.js} +510 -15
- package/dist/query-parser-4WkMoA_K.js.map +1 -0
- package/dist/{request-timeout-DgH7j8qO.js → request-timeout-Dnl2_OBc.js} +15 -8
- package/dist/request-timeout-Dnl2_OBc.js.map +1 -0
- package/dist/resumable-upload-threshold-CKv-Ry0l.js +24 -0
- package/dist/resumable-upload-threshold-CKv-Ry0l.js.map +1 -0
- package/dist/schema-edit/apply-schema-change.d.ts +10 -0
- package/dist/schema-edit/local-source.d.ts +29 -0
- package/dist/schema-edit/remote-source.d.ts +13 -3
- package/dist/schema-edit/source-editor.d.ts +28 -0
- package/dist/{schema-editor-routes-oIyuWl3L.js → schema-editor-routes-C11Tumyd.js} +54 -10
- package/dist/schema-editor-routes-C11Tumyd.js.map +1 -0
- package/dist/services/outbound-post.d.ts +50 -0
- package/dist/services/outbound-url-guard.d.ts +34 -5
- package/dist/services/routed-realtime-service.d.ts +5 -0
- package/dist/services/webhook-service.d.ts +66 -14
- package/dist/singleton.d.ts +9 -5
- package/dist/soft-delete-params-DfV3vVN5.js +668 -0
- package/dist/soft-delete-params-DfV3vVN5.js.map +1 -0
- package/dist/sql-export-routes-ClRwzIsC.js +240 -0
- package/dist/sql-export-routes-ClRwzIsC.js.map +1 -0
- package/dist/{src-CatHFUym.js → src-D5Y3N-S4.js} +2 -1
- package/dist/{src-CatHFUym.js.map → src-D5Y3N-S4.js.map} +1 -1
- package/dist/storage/GCSStorageController.d.ts +46 -2
- package/dist/storage/LocalStorageController.d.ts +67 -2
- package/dist/storage/S3StorageController.d.ts +37 -3
- package/dist/storage/image-transform.d.ts +5 -0
- package/dist/storage/maintenance-routes.d.ts +23 -0
- package/dist/storage/maintenance.d.ts +126 -0
- package/dist/storage/rendition-cache.d.ts +9 -11
- package/dist/storage/request-principals.d.ts +30 -0
- package/dist/storage/routes.d.ts +20 -0
- package/dist/storage/source-variables.d.ts +10 -0
- package/dist/storage/streams.d.ts +42 -0
- package/dist/storage/tus-handler.d.ts +46 -2
- package/dist/storage/types.d.ts +82 -7
- package/dist/storage/upload-validation.d.ts +13 -0
- package/dist/storage-resumable-VO-cMpse-C_YX71pO.js +125 -0
- package/dist/storage-resumable-VO-cMpse-C_YX71pO.js.map +1 -0
- package/dist/strings.es-BeZWAodn.js +256 -0
- package/dist/strings.es-BeZWAodn.js.map +1 -0
- package/dist/upload-validation-Dd-fnsbA.js +172 -0
- package/dist/upload-validation-Dd-fnsbA.js.map +1 -0
- package/dist/utils/byte-size.d.ts +10 -0
- package/dist/utils/compression.d.ts +6 -0
- package/dist/utils/load-failure.d.ts +14 -0
- package/package.json +5 -5
- package/dist/GCSStorageController-BSiP1c-f.js +0 -256
- package/dist/GCSStorageController-BSiP1c-f.js.map +0 -1
- package/dist/S3StorageController-CAwFRgjV.js +0 -276
- package/dist/S3StorageController-CAwFRgjV.js.map +0 -1
- package/dist/auth-DMLngxn_.js.map +0 -1
- package/dist/backup-CN0s50D2.js.map +0 -1
- package/dist/contract-routes-fz8i4pxs.js.map +0 -1
- package/dist/cron-loader-CwaANlOG.js +0 -118
- package/dist/cron-loader-CwaANlOG.js.map +0 -1
- package/dist/cron-routes-Bc-SB0Se.js.map +0 -1
- package/dist/cron-scheduler-CYQgco86.js.map +0 -1
- package/dist/cron-store-D2Q9-Aco.js +0 -300
- package/dist/cron-store-D2Q9-Aco.js.map +0 -1
- package/dist/dynamic-import-X40pTZUQ.js +0 -23
- package/dist/dynamic-import-X40pTZUQ.js.map +0 -1
- package/dist/function-loader-D7o5Epjj.js.map +0 -1
- package/dist/function-routes-CaNG4waN.js.map +0 -1
- package/dist/jobs-DqYNfquG.js.map +0 -1
- package/dist/jwt-R6bSPMjk.js.map +0 -1
- package/dist/openapi-generator-DAq_XVDu.js.map +0 -1
- package/dist/proxy-qRlqeUmO.js.map +0 -1
- package/dist/query-parser-BgiKJKvc.js.map +0 -1
- package/dist/request-timeout-DgH7j8qO.js.map +0 -1
- package/dist/schema-editor-routes-oIyuWl3L.js.map +0 -1
- package/dist/soft-delete-params-BWPilMPF.js +0 -59
- package/dist/soft-delete-params-BWPilMPF.js.map +0 -1
- package/dist/src-I3aG1PcY.js +0 -6870
- package/dist/src-I3aG1PcY.js.map +0 -1
- package/dist/types-BfKcm9do.js +0 -39
- 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.
|
|
44
|
-
*
|
|
45
|
-
*
|
|
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
|
|
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
|
-
|
|
71
|
-
private
|
|
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
|
|
83
|
-
*
|
|
84
|
-
*
|
|
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
|
-
|
|
122
|
-
|
|
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<
|
|
133
|
-
private
|
|
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;
|
package/dist/singleton.d.ts
CHANGED
|
@@ -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
|
|
11
|
-
*
|
|
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
|
|
25
|
+
* The server-side Rebase client, as a module-level handle.
|
|
25
26
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
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
|