@rebasepro/server 0.13.0 → 0.13.1-canary.g06dbe5b

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 (125) hide show
  1. package/dist/{admin_block-CcSGdH7M.js → admin_block-H86dCPsj.js} +62 -2
  2. package/dist/admin_block-H86dCPsj.js.map +1 -0
  3. package/dist/api/ast-schema-editor.d.ts +74 -6
  4. package/dist/api/errors.d.ts +0 -6
  5. package/dist/api/openapi-generator.d.ts +14 -0
  6. package/dist/api/rest/api-generator.d.ts +1 -1
  7. package/dist/api/rest/idempotency.d.ts +62 -4
  8. package/dist/api/rest/query-parser.d.ts +15 -1
  9. package/dist/api/rest/write-validation.d.ts +52 -9
  10. package/dist/auth/adapter-middleware.d.ts +3 -1
  11. package/dist/auth/apple-oauth.d.ts +16 -11
  12. package/dist/auth/bitbucket-oauth.d.ts +2 -4
  13. package/dist/auth/builtin-auth-adapter.d.ts +2 -0
  14. package/dist/auth/discord-oauth.d.ts +5 -6
  15. package/dist/auth/facebook-oauth.d.ts +2 -4
  16. package/dist/auth/github-oauth.d.ts +2 -4
  17. package/dist/auth/gitlab-oauth.d.ts +6 -4
  18. package/dist/auth/google-oauth.d.ts +1 -0
  19. package/dist/auth/index.d.ts +8 -1
  20. package/dist/auth/interfaces.d.ts +68 -1
  21. package/dist/auth/jwt.d.ts +40 -0
  22. package/dist/auth/linkedin-oauth.d.ts +2 -4
  23. package/dist/auth/mfa-gate.d.ts +42 -0
  24. package/dist/auth/mfa-routes.d.ts +26 -1
  25. package/dist/auth/mfa.d.ts +16 -0
  26. package/dist/auth/microsoft-oauth.d.ts +19 -4
  27. package/dist/auth/oauth-code-flow.d.ts +66 -0
  28. package/dist/auth/oauth-signin-policy.d.ts +61 -0
  29. package/dist/auth/oidc-id-token.d.ts +61 -0
  30. package/dist/auth/rate-limiter.d.ts +37 -2
  31. package/dist/auth/rls-scope.d.ts +25 -0
  32. package/dist/auth/routes.d.ts +8 -0
  33. package/dist/auth/slack-oauth.d.ts +2 -4
  34. package/dist/auth/spotify-oauth.d.ts +2 -4
  35. package/dist/auth/twitter-oauth.d.ts +2 -5
  36. package/dist/{auth-CuC9M2x6.js → auth-DkAHqvf5.js} +1604 -391
  37. package/dist/auth-DkAHqvf5.js.map +1 -0
  38. package/dist/{backup-CVggVhR2.js → backup-DLluVyuA.js} +2 -2
  39. package/dist/{backup-CVggVhR2.js.map → backup-DLluVyuA.js.map} +1 -1
  40. package/dist/boot/boot.d.ts +19 -0
  41. package/dist/boot/ddl-bootstrap.d.ts +70 -0
  42. package/dist/{contract-routes-Dj8i5AiM.js → contract-routes-BB1U05sS.js} +3 -3
  43. package/dist/{contract-routes-Dj8i5AiM.js.map → contract-routes-BB1U05sS.js.map} +1 -1
  44. package/dist/cron/cron-scheduler.d.ts +8 -3
  45. package/dist/cron/define-cron.d.ts +17 -3
  46. package/dist/{cron-loader-B1S2MCSl.js → cron-loader-3U5aGILy.js} +2 -2
  47. package/dist/{cron-loader-B1S2MCSl.js.map → cron-loader-3U5aGILy.js.map} +1 -1
  48. package/dist/{cron-routes-CrQ0tK-_.js → cron-routes-rZgwlOz4.js} +2 -2
  49. package/dist/{cron-routes-CrQ0tK-_.js.map → cron-routes-rZgwlOz4.js.map} +1 -1
  50. package/dist/{cron-scheduler-B3RFt0HS.js → cron-scheduler-FJAaCAXm.js} +30 -5
  51. package/dist/cron-scheduler-FJAaCAXm.js.map +1 -0
  52. package/dist/{cron-store-BywZsyfZ.js → cron-store-9NmUDfzL.js} +66 -47
  53. package/dist/cron-store-9NmUDfzL.js.map +1 -0
  54. package/dist/ddl-bootstrap-BhXbTnBl.js +183 -0
  55. package/dist/ddl-bootstrap-BhXbTnBl.js.map +1 -0
  56. package/dist/email/html.d.ts +54 -0
  57. package/dist/email/index.d.ts +3 -0
  58. package/dist/email/link-base.d.ts +39 -0
  59. package/dist/email/smtp-email-service.d.ts +7 -1
  60. package/dist/email/templates.d.ts +9 -1
  61. package/dist/email/types.d.ts +11 -1
  62. package/dist/{errors-CgkCzoj7.js → errors-B1WZEdsK.js} +3 -11
  63. package/dist/errors-B1WZEdsK.js.map +1 -0
  64. package/dist/function-loader-D1SwtCa5.js +139 -0
  65. package/dist/function-loader-D1SwtCa5.js.map +1 -0
  66. package/dist/{function-routes-C0cLIy3N.js → function-routes-Btcez1T-.js} +18 -6
  67. package/dist/function-routes-Btcez1T-.js.map +1 -0
  68. package/dist/functions/define-function.d.ts +25 -6
  69. package/dist/functions/function-loader.d.ts +23 -0
  70. package/dist/functions/function-routes.d.ts +7 -1
  71. package/dist/functions/request-timeout.d.ts +34 -0
  72. package/dist/history/history-routes.d.ts +6 -0
  73. package/dist/index.d.ts +2 -1
  74. package/dist/index.es.js +1960 -794
  75. package/dist/index.es.js.map +1 -1
  76. package/dist/init/docs.d.ts +10 -1
  77. package/dist/init/process-safety.d.ts +25 -0
  78. package/dist/init.d.ts +27 -0
  79. package/dist/{jwt-DD6EtpGj.js → jwt-Cuq6MwNy.js} +70 -8
  80. package/dist/jwt-Cuq6MwNy.js.map +1 -0
  81. package/dist/logger-DfvF_8r-.js +190 -0
  82. package/dist/logger-DfvF_8r-.js.map +1 -0
  83. package/dist/openapi-generator-BQxxxDpb.js +865 -0
  84. package/dist/openapi-generator-BQxxxDpb.js.map +1 -0
  85. package/dist/request-timeout-RivJsME0.js +65 -0
  86. package/dist/request-timeout-RivJsME0.js.map +1 -0
  87. package/dist/schema-editor-routes-DZFKGXgq.js +437 -0
  88. package/dist/schema-editor-routes-DZFKGXgq.js.map +1 -0
  89. package/dist/serve-spa.d.ts +5 -4
  90. package/dist/services/outbound-url-guard.d.ts +53 -0
  91. package/dist/services/routed-realtime-service.d.ts +10 -2
  92. package/dist/services/webhook-service.d.ts +76 -1
  93. package/dist/singleton.d.ts +25 -8
  94. package/dist/{src-Cum9kox5.js → src-By48Ffg0.js} +322 -70
  95. package/dist/src-By48Ffg0.js.map +1 -0
  96. package/dist/{src-_qQ3RNCK.js → src-Ca6NhxKs.js} +79 -2
  97. package/dist/src-Ca6NhxKs.js.map +1 -0
  98. package/dist/storage/LocalStorageController.d.ts +12 -1
  99. package/dist/storage/image-transform.d.ts +57 -0
  100. package/dist/storage/keys.d.ts +98 -0
  101. package/dist/storage/routes.d.ts +11 -0
  102. package/dist/storage/tus-handler.d.ts +7 -1
  103. package/dist/utils/logger.d.ts +18 -0
  104. package/dist/utils/logging.d.ts +0 -4
  105. package/dist/utils/sql.d.ts +11 -6
  106. package/package.json +7 -6
  107. package/dist/admin_block-CcSGdH7M.js.map +0 -1
  108. package/dist/auth-CuC9M2x6.js.map +0 -1
  109. package/dist/backend-CIxN4FVm.js +0 -15
  110. package/dist/backend-CIxN4FVm.js.map +0 -1
  111. package/dist/cron-scheduler-B3RFt0HS.js.map +0 -1
  112. package/dist/cron-store-BywZsyfZ.js.map +0 -1
  113. package/dist/errors-CgkCzoj7.js.map +0 -1
  114. package/dist/function-loader-B_1fYfUY.js +0 -86
  115. package/dist/function-loader-B_1fYfUY.js.map +0 -1
  116. package/dist/function-routes-C0cLIy3N.js.map +0 -1
  117. package/dist/jwt-DD6EtpGj.js.map +0 -1
  118. package/dist/logger-BYU66ENZ.js +0 -94
  119. package/dist/logger-BYU66ENZ.js.map +0 -1
  120. package/dist/openapi-generator-BEwyiaAr.js +0 -597
  121. package/dist/openapi-generator-BEwyiaAr.js.map +0 -1
  122. package/dist/schema-editor-routes-CbF20Mf1.js +0 -248
  123. package/dist/schema-editor-routes-CbF20Mf1.js.map +0 -1
  124. package/dist/src-Cum9kox5.js.map +0 -1
  125. package/dist/src-_qQ3RNCK.js.map +0 -1
@@ -16,14 +16,89 @@ export interface WebhookDeliveryResult {
16
16
  success: boolean;
17
17
  attemptNumber: number;
18
18
  }
19
+ export interface WebhookDispatcherOptions {
20
+ /**
21
+ * Deliver to destinations that resolve to loopback, link-local or private
22
+ * addresses. Off by default. Turning it on re-opens SSRF: anyone who can
23
+ * choose a webhook URL can then reach the pod's metadata endpoint, the
24
+ * cluster API server and the database — and read the first 1000 bytes of
25
+ * the answer back out of `responseBody`. Only for a receiver you run
26
+ * yourself on the same host or network.
27
+ */
28
+ allowPrivateNetworks?: boolean;
29
+ /**
30
+ * Deadline for one attempt, covering the response body as well as the
31
+ * headers. Defaults to 10s.
32
+ */
33
+ timeoutMs?: number;
34
+ /**
35
+ * Called with the final result of every delivery, including the ones
36
+ * started by {@link WebhookDispatcher.enqueueEntityChange} — which return
37
+ * nothing to their caller, so this is the only place their failures
38
+ * surface.
39
+ */
40
+ onDelivery?: (result: WebhookDeliveryResult) => void;
41
+ /**
42
+ * Hostname resolver used by the destination guard. Defaults to
43
+ * `dns.lookup`; injected by tests so a unit suite never asks a resolver.
44
+ */
45
+ lookup?: (hostname: string) => Promise<string[]>;
46
+ }
19
47
  export declare class WebhookDispatcher {
20
48
  private webhooks;
21
49
  private maxRetries;
22
50
  private retryDelays;
51
+ private readonly options;
52
+ private readonly timeoutMs;
53
+ private queue;
54
+ private draining;
55
+ constructor(options?: WebhookDispatcherOptions);
23
56
  /** Register webhooks to watch */
24
57
  setWebhooks(webhooks: WebhookConfig[]): void;
25
- /** Called when a entity changes — checks if any webhook matches */
58
+ /**
59
+ * Called when a entity changes — checks if any webhook matches, and awaits
60
+ * every delivery, retries included.
61
+ *
62
+ * **Do not await this inside a collection callback.** `afterSave` and
63
+ * `afterDelete` run inside the write's Postgres transaction, so awaiting a
64
+ * delivery here holds a pooled connection and the row's locks for as long
65
+ * as the receiver takes to answer — up to ~36s across three attempts, per
66
+ * matching webhook. Use {@link enqueueEntityChange} there; this method is
67
+ * for a custom function or a job that wants the results.
68
+ */
26
69
  onEntityChange(table: string, event: "INSERT" | "UPDATE" | "DELETE", id: string, entity: Record<string, unknown> | null, previousEntity?: Record<string, unknown> | null): Promise<WebhookDeliveryResult[]>;
70
+ /**
71
+ * Queue the same deliveries and return immediately.
72
+ *
73
+ * This is the form a collection callback wants. `afterSave` is awaited
74
+ * *inside* the transaction that wrote the row, so anything it awaits is
75
+ * transaction time; queueing hands the HTTP to a drain loop that runs
76
+ * after the callback returns, and the transaction commits without waiting
77
+ * for a third party. It also means a receiver that is down can no longer
78
+ * fail the customer's write.
79
+ *
80
+ * The cost, stated plainly: the queue is in-process and in-memory. A crash
81
+ * or a deploy between the enqueue and the delivery drops the event, and a
82
+ * receiver may see the notification a few milliseconds before the row it
83
+ * describes is committed. Use {@link flush} on shutdown, and
84
+ * `onDelivery` to record failures.
85
+ */
86
+ enqueueEntityChange(table: string, event: "INSERT" | "UPDATE" | "DELETE", id: string, entity: Record<string, unknown> | null, previousEntity?: Record<string, unknown> | null): void;
87
+ /**
88
+ * Wait for every queued delivery to finish. For graceful shutdown, and for
89
+ * tests that need to observe what {@link enqueueEntityChange} sent.
90
+ */
91
+ flush(): Promise<void>;
92
+ private startDraining;
93
+ private drainQueue;
94
+ /** The payload each matching webhook gets for this change. */
95
+ private buildDeliveries;
27
96
  private deliverWithRetry;
28
97
  private deliver;
98
+ /**
99
+ * Read at most {@link MAX_RESPONSE_BYTES} of the response and cancel the
100
+ * rest, so a receiver cannot buffer a 10 GB body into the pod before the
101
+ * caller truncates it to 1000 characters.
102
+ */
103
+ private readCappedBody;
29
104
  }
@@ -22,14 +22,30 @@ export declare function _resetRebaseMock(): void;
22
22
  * **Admin data plane** (`rebase.dataAsAdmin`):
23
23
  * Backed by the native DataDriver — calls go directly to the database without
24
24
  * JSON serialization, HTTP dispatch, or middleware overhead. The driver is
25
- * scoped as `{ uid: "service", roles: ["admin"] }`, so **every read and write
26
- * bypasses row-level-security policies**. No `REBASE_SERVICE_KEY` is required.
25
+ * scoped once as `{ uid: "service", roles: ["admin"] }` (`SERVICE_IDENTITY`),
26
+ * which makes it **admin-scoped, not RLS-bypassing**: every read and write runs
27
+ * in a transaction that has done `SET LOCAL ROLE rebase_user` with
28
+ * `app.uid = 'service'`, and policies are evaluated against that. No
29
+ * `REBASE_SERVICE_KEY` is required.
27
30
  *
28
- * ⚠️ Because it bypasses RLS, `rebase.dataAsAdmin` is for trusted background
29
- * work (cron jobs, migrations, service tasks) — **not** for serving user-facing
30
- * data. Inside a request handler, run user-scoped queries through the
31
- * request-scoped driver (`c.var.driver`), which carries the caller's identity
32
- * so RLS applies.
31
+ * It clears the default policies through their `rolesOverlap(['admin'])` arm —
32
+ * which is why the difference rarely shows. It shows when you write your own:
33
+ *
34
+ * - `policy.serverContext()` compiles to `auth.uid() IS NULL` and is therefore
35
+ * **false** for this accessor. A collection with `disableDefaultPolicies:
36
+ * true` whose rule is `serverContext()` denies these writes (`42501`) and
37
+ * returns zero rows — HTTP 200, empty — for these reads.
38
+ * - Its reach equals an `admin`-roled application user's reach. It is not a
39
+ * private door.
40
+ *
41
+ * `rebase.sql()` *is* an unconditional bypass — it runs on the owner connection
42
+ * and never goes through `withAuth`. Of the two accessors on this object, the
43
+ * quieter one is the more privileged.
44
+ *
45
+ * ⚠️ `rebase.dataAsAdmin` is for trusted background work (cron jobs,
46
+ * migrations, service tasks) — **not** for serving user-facing data. Inside a
47
+ * request handler, run user-scoped queries through the request-scoped driver
48
+ * (`c.var.driver`), which carries the caller's identity.
33
49
  *
34
50
  * `rebase.data` is **gone from the type**: `RebaseServerClient` omits it, so the
35
51
  * admin-scoped accessor has exactly one name and the privilege is visible at the
@@ -45,7 +61,8 @@ export declare function _resetRebaseMock(): void;
45
61
  * ```typescript
46
62
  * import { rebase } from "@rebasepro/server";
47
63
  *
48
- * // In a cron job, hook, or trusted service file (admin scope, bypasses RLS):
64
+ * // In a cron job, hook, or trusted service file (admin scope, RLS evaluated
65
+ * // as `{ uid: "service", roles: ["admin"] }`):
49
66
  * await rebase.email.send({ to: "admin@co.com", subject: "Alert", html: "<p>Hi</p>" });
50
67
  * const jobs = await rebase.dataAsAdmin.jobs.find({ limit: 10 });
51
68
  * ```