@rebasepro/server 0.16.0 → 0.16.1-canary.g0d7af95

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 (219) hide show
  1. package/dist/{GCSStorageController-BEmDYFKc.js → GCSStorageController-Bl7nmhdv.js} +7 -6
  2. package/dist/{GCSStorageController-BEmDYFKc.js.map → GCSStorageController-Bl7nmhdv.js.map} +1 -1
  3. package/dist/{S3StorageController-B2EDXXMH.js → S3StorageController-CWvvrRpF.js} +7 -6
  4. package/dist/{S3StorageController-B2EDXXMH.js.map → S3StorageController-CWvvrRpF.js.map} +1 -1
  5. package/dist/{admin_block-DLILvzle.js → admin_block-BeypnEfb.js} +6 -6
  6. package/dist/admin_block-BeypnEfb.js.map +1 -0
  7. package/dist/api/ast-schema-editor.d.ts +23 -0
  8. package/dist/api/contract-routes.d.ts +1 -1
  9. package/dist/api/errors.d.ts +1 -1
  10. package/dist/api/index.d.ts +3 -3
  11. package/dist/api/live-schema-routes.d.ts +122 -0
  12. package/dist/api/logs-routes.d.ts +1 -1
  13. package/dist/api/mount.d.ts +41 -0
  14. package/dist/api/rest/api-generator.d.ts +2 -2
  15. package/dist/api/rest/index.d.ts +1 -1
  16. package/dist/api/rest/query-parser.d.ts +1 -1
  17. package/dist/api/schema-editor-routes.d.ts +1 -1
  18. package/dist/api/types.d.ts +12 -4
  19. package/dist/{schema-editor-routes-CV9k0w3G.js → ast-schema-editor-BrarYZCq.js} +37 -45
  20. package/dist/ast-schema-editor-BrarYZCq.js.map +1 -0
  21. package/dist/auth/adapter-middleware.d.ts +2 -2
  22. package/dist/auth/admin-roles-route.d.ts +2 -2
  23. package/dist/auth/admin-user-ops.d.ts +3 -3
  24. package/dist/auth/admin-users-route.d.ts +4 -6
  25. package/dist/auth/api-keys/api-key-middleware.d.ts +2 -2
  26. package/dist/auth/api-keys/api-key-permission-guard.d.ts +1 -1
  27. package/dist/auth/api-keys/api-key-routes.d.ts +2 -2
  28. package/dist/auth/api-keys/api-key-store.d.ts +1 -1
  29. package/dist/auth/api-keys/index.d.ts +9 -9
  30. package/dist/auth/apple-oauth.d.ts +2 -2
  31. package/dist/auth/auth-hooks.d.ts +4 -4
  32. package/dist/auth/bitbucket-oauth.d.ts +2 -2
  33. package/dist/auth/builtin-auth-adapter.d.ts +8 -4
  34. package/dist/auth/capabilities.d.ts +51 -0
  35. package/dist/auth/captcha.d.ts +86 -0
  36. package/dist/auth/cookie-utils.d.ts +2 -2
  37. package/dist/auth/discord-oauth.d.ts +2 -2
  38. package/dist/auth/facebook-oauth.d.ts +2 -2
  39. package/dist/auth/github-oauth.d.ts +2 -2
  40. package/dist/auth/gitlab-oauth.d.ts +2 -2
  41. package/dist/auth/google-oauth.d.ts +1 -1
  42. package/dist/auth/index.d.ts +58 -54
  43. package/dist/auth/jwks-routes.d.ts +1 -1
  44. package/dist/auth/jwt.d.ts +1 -1
  45. package/dist/auth/linkedin-oauth.d.ts +2 -2
  46. package/dist/auth/magic-link-routes.d.ts +10 -3
  47. package/dist/auth/mfa-gate.d.ts +1 -1
  48. package/dist/auth/mfa-routes.d.ts +3 -3
  49. package/dist/auth/microsoft-oauth.d.ts +2 -2
  50. package/dist/auth/middleware.d.ts +6 -7
  51. package/dist/auth/otp-routes.d.ts +89 -0
  52. package/dist/auth/rate-limiter.d.ts +2 -2
  53. package/dist/auth/require-auth.d.ts +1 -1
  54. package/dist/auth/reset-password-admin.d.ts +4 -4
  55. package/dist/auth/routes.d.ts +18 -10
  56. package/dist/auth/session-routes.d.ts +3 -3
  57. package/dist/auth/slack-oauth.d.ts +2 -2
  58. package/dist/auth/spotify-oauth.d.ts +2 -2
  59. package/dist/auth/token-revocation.d.ts +2 -2
  60. package/dist/auth/twitter-oauth.d.ts +2 -2
  61. package/dist/{auth-5Et5mnUA.js → auth-DU-nUjPp.js} +604 -4376
  62. package/dist/auth-DU-nUjPp.js.map +1 -0
  63. package/dist/backup/backup-common.d.ts +1 -1
  64. package/dist/backup/backup-routes.d.ts +3 -3
  65. package/dist/backup/index.d.ts +3 -3
  66. package/dist/{backup-C6ljYVTp.js → backup-CRdZkA6c.js} +7 -6
  67. package/dist/{backup-C6ljYVTp.js.map → backup-CRdZkA6c.js.map} +1 -1
  68. package/dist/boot/boot.d.ts +5 -5
  69. package/dist/boot/bundle.d.ts +10 -1
  70. package/dist/boot/driver.d.ts +1 -1
  71. package/dist/boot/env.d.ts +28 -1
  72. package/dist/boot/fetch-bundle.d.ts +144 -1
  73. package/dist/boot/options.d.ts +30 -6
  74. package/dist/boot/resource-adapters.d.ts +31 -0
  75. package/dist/boot/resource-loading.d.ts +10 -0
  76. package/dist/boot/role.d.ts +3 -2
  77. package/dist/boot/sources.d.ts +8 -2
  78. package/dist/boot/version-skew.d.ts +1 -1
  79. package/dist/collections/BackendCollectionRegistry.d.ts +1 -1
  80. package/dist/collections/loader.d.ts +1 -1
  81. package/dist/collections/validate-config.d.ts +13 -0
  82. package/dist/{contract-routes-DZ-LBpSL.js → contract-routes-D8TvxPLo.js} +8 -7
  83. package/dist/contract-routes-D8TvxPLo.js.map +1 -0
  84. package/dist/cron/cron-routes.d.ts +2 -2
  85. package/dist/cron/cron-scheduler.d.ts +3 -3
  86. package/dist/cron/index.d.ts +8 -8
  87. package/dist/{cron-loader-YhhQeVBM.js → cron-loader-d9WMFENB.js} +8 -7
  88. package/dist/{cron-loader-YhhQeVBM.js.map → cron-loader-d9WMFENB.js.map} +1 -1
  89. package/dist/{cron-routes-maM_RlUu.js → cron-routes-BsukhMGm.js} +9 -8
  90. package/dist/cron-routes-BsukhMGm.js.map +1 -0
  91. package/dist/{cron-scheduler-DIpYBmZP.js → cron-scheduler-BB82dWuU.js} +9 -9
  92. package/dist/cron-scheduler-BB82dWuU.js.map +1 -0
  93. package/dist/{cron-store-DfH_4Cd9.js → cron-store-CbFfQhbg.js} +11 -9
  94. package/dist/{cron-store-DfH_4Cd9.js.map → cron-store-CbFfQhbg.js.map} +1 -1
  95. package/dist/ddl-bootstrap-5YZCZ8qk.js +146 -0
  96. package/dist/ddl-bootstrap-5YZCZ8qk.js.map +1 -0
  97. package/dist/deploy/pod-contract.d.ts +139 -0
  98. package/dist/dev-secrets.d.ts +52 -0
  99. package/dist/{dynamic-import-Dvh-K5fl.js → dynamic-import-X40pTZUQ.js} +5 -4
  100. package/dist/{dynamic-import-Dvh-K5fl.js.map → dynamic-import-X40pTZUQ.js.map} +1 -1
  101. package/dist/email/dev-sink.d.ts +88 -0
  102. package/dist/email/index.d.ts +9 -7
  103. package/dist/email/link-base.d.ts +1 -1
  104. package/dist/email/smtp-email-service.d.ts +2 -2
  105. package/dist/email/templates.d.ts +12 -0
  106. package/dist/email/types.d.ts +18 -6
  107. package/dist/env.d.ts +1 -1
  108. package/dist/{errors-EBYiaJ2E.js → errors-DBwpj9N8.js} +8 -7
  109. package/dist/errors-DBwpj9N8.js.map +1 -0
  110. package/dist/{function-loader-DDS1v7YX.js → function-loader-LLdmBFoL.js} +9 -8
  111. package/dist/{function-loader-DDS1v7YX.js.map → function-loader-LLdmBFoL.js.map} +1 -1
  112. package/dist/{function-routes-Btcez1T-.js → function-routes-ClT6UQpD.js} +8 -7
  113. package/dist/function-routes-ClT6UQpD.js.map +1 -0
  114. package/dist/functions/context.d.ts +141 -0
  115. package/dist/functions/define-function.d.ts +1 -1
  116. package/dist/functions/function-routes.d.ts +9 -3
  117. package/dist/functions/guards.d.ts +76 -0
  118. package/dist/functions/index.d.ts +96 -5
  119. package/dist/functions/index.js +919 -0
  120. package/dist/functions/index.js.map +1 -0
  121. package/dist/functions/internal.d.ts +26 -0
  122. package/dist/functions/proxy.d.ts +1 -1
  123. package/dist/functions/request-timeout.d.ts +9 -1
  124. package/dist/functions/runtime-env.d.ts +92 -0
  125. package/dist/functions/wait-until.d.ts +74 -0
  126. package/dist/history/history-routes.d.ts +2 -2
  127. package/dist/history/index.d.ts +1 -1
  128. package/dist/history-recorder-B67maiTi.js +76 -0
  129. package/dist/history-recorder-B67maiTi.js.map +1 -0
  130. package/dist/history-store-oiqhb3HU.js +210 -0
  131. package/dist/history-store-oiqhb3HU.js.map +1 -0
  132. package/dist/index.d.ts +65 -54
  133. package/dist/index.es.js +3667 -328
  134. package/dist/index.es.js.map +1 -1
  135. package/dist/init/docs.d.ts +1 -1
  136. package/dist/init/middlewares.d.ts +1 -1
  137. package/dist/init/shutdown.d.ts +4 -0
  138. package/dist/init/storage.d.ts +1 -1
  139. package/dist/init/surfaces.d.ts +10 -0
  140. package/dist/init.d.ts +179 -22
  141. package/dist/internal-tables-DpxfPaEB.js +97 -0
  142. package/dist/internal-tables-DpxfPaEB.js.map +1 -0
  143. package/dist/jobs/index.d.ts +5 -5
  144. package/dist/{jobs-CyOKXXlu.js → jobs-B2ELModo.js} +11 -9
  145. package/dist/{jobs-CyOKXXlu.js.map → jobs-B2ELModo.js.map} +1 -1
  146. package/dist/{jwt-DxH9fLPt.js → jwt-DoHkMMWF.js} +9 -8
  147. package/dist/jwt-DoHkMMWF.js.map +1 -0
  148. package/dist/{logger-DfvF_8r-.js → logger-DS03e908.js} +104 -10
  149. package/dist/logger-DS03e908.js.map +1 -0
  150. package/dist/{logs-routes-CWBLQj2l.js → logs-routes-DB72iQSr.js} +36 -9
  151. package/dist/logs-routes-DB72iQSr.js.map +1 -0
  152. package/dist/metrics/history-recorder.d.ts +18 -0
  153. package/dist/metrics/history-store.d.ts +123 -0
  154. package/dist/metrics/index.d.ts +10 -2
  155. package/dist/{openapi-generator-BCKJRUS4.js → openapi-generator-FFGT0H6O.js} +7 -11
  156. package/dist/{openapi-generator-BCKJRUS4.js.map → openapi-generator-FFGT0H6O.js.map} +1 -1
  157. package/dist/{proxy-Bj5DVllb.js → proxy-CMymhnwG.js} +9 -6
  158. package/dist/{proxy-Bj5DVllb.js.map → proxy-CMymhnwG.js.map} +1 -1
  159. package/dist/query-parser--nstjRCh.js +355 -0
  160. package/dist/query-parser--nstjRCh.js.map +1 -0
  161. package/dist/{request-timeout-BuFoEKwT.js → request-timeout-C8gkc-j7.js} +21 -6
  162. package/dist/request-timeout-C8gkc-j7.js.map +1 -0
  163. package/dist/rls-audit/index.d.ts +111 -0
  164. package/dist/{rolldown-runtime-DSJWtz9O.js → rolldown-runtime-dW7B1o5h.js} +4 -3
  165. package/dist/schema-edit/apply-schema-change.d.ts +141 -0
  166. package/dist/schema-edit/github-repository.d.ts +67 -0
  167. package/dist/schema-edit/local-git-repository.d.ts +28 -0
  168. package/dist/schema-edit/project-root.d.ts +43 -0
  169. package/dist/schema-edit/remote-source.d.ts +25 -0
  170. package/dist/schema-edit/schema-edit-permissions.d.ts +129 -0
  171. package/dist/schema-editor-routes-Bf5h5Emf.js +87 -0
  172. package/dist/schema-editor-routes-Bf5h5Emf.js.map +1 -0
  173. package/dist/schemas-DBxgjM9A.js +4153 -0
  174. package/dist/schemas-DBxgjM9A.js.map +1 -0
  175. package/dist/{selection-_z6TM1DB.js → selection-CRpqKUbt.js} +6 -5
  176. package/dist/{selection-_z6TM1DB.js.map → selection-CRpqKUbt.js.map} +1 -1
  177. package/dist/services/webhook-service.d.ts +1 -1
  178. package/dist/singleton.d.ts +7 -0
  179. package/dist/{src-BPfYOeN4.js → src-B-CmIFMr.js} +8 -6
  180. package/dist/src-B-CmIFMr.js.map +1 -0
  181. package/dist/{src-CrCxd8km.js → src-Cdsw7DqV.js} +126 -5
  182. package/dist/src-Cdsw7DqV.js.map +1 -0
  183. package/dist/storage/GCSStorageController.d.ts +1 -1
  184. package/dist/storage/LocalStorageController.d.ts +1 -1
  185. package/dist/storage/S3StorageController.d.ts +1 -1
  186. package/dist/storage/cache-headers.d.ts +87 -0
  187. package/dist/storage/index.d.ts +11 -11
  188. package/dist/storage/path-pattern.d.ts +58 -0
  189. package/dist/storage/policies.d.ts +88 -0
  190. package/dist/storage/range.d.ts +63 -0
  191. package/dist/storage/rendition-cache.d.ts +45 -0
  192. package/dist/storage/routes.d.ts +17 -5
  193. package/dist/storage/storage-registry.d.ts +1 -1
  194. package/dist/storage/triggers.d.ts +66 -0
  195. package/dist/storage/tus-handler.d.ts +34 -3
  196. package/dist/topics/runtime.d.ts +68 -0
  197. package/dist/{types-DSnOC4mF.js → types-BfKcm9do.js} +5 -4
  198. package/dist/{types-DSnOC4mF.js.map → types-BfKcm9do.js.map} +1 -1
  199. package/dist/utils/host.d.ts +58 -0
  200. package/dist/utils/logger.d.ts +0 -15
  201. package/dist/utils/request-id.d.ts +1 -1
  202. package/functions/package.json +24 -0
  203. package/package.json +13 -7
  204. package/dist/admin_block-DLILvzle.js.map +0 -1
  205. package/dist/auth-5Et5mnUA.js.map +0 -1
  206. package/dist/contract-routes-DZ-LBpSL.js.map +0 -1
  207. package/dist/cron-routes-maM_RlUu.js.map +0 -1
  208. package/dist/cron-scheduler-DIpYBmZP.js.map +0 -1
  209. package/dist/ddl-bootstrap-Cywoj8Ta.js +0 -221
  210. package/dist/ddl-bootstrap-Cywoj8Ta.js.map +0 -1
  211. package/dist/errors-EBYiaJ2E.js.map +0 -1
  212. package/dist/function-routes-Btcez1T-.js.map +0 -1
  213. package/dist/jwt-DxH9fLPt.js.map +0 -1
  214. package/dist/logger-DfvF_8r-.js.map +0 -1
  215. package/dist/logs-routes-CWBLQj2l.js.map +0 -1
  216. package/dist/request-timeout-BuFoEKwT.js.map +0 -1
  217. package/dist/schema-editor-routes-CV9k0w3G.js.map +0 -1
  218. package/dist/src-BPfYOeN4.js.map +0 -1
  219. package/dist/src-CrCxd8km.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import type { BackupInfo } from "@rebasepro/types";
2
- import type { StorageController } from "../storage";
2
+ import type { StorageController } from "../storage/index.js";
3
3
  export type BackupDestination = {
4
4
  kind: "local";
5
5
  path: string;
@@ -1,7 +1,7 @@
1
1
  import { Hono } from "hono";
2
- import type { HonoEnv } from "../api/types";
3
- import type { StorageController } from "../storage";
4
- import { BackupDestination } from "./backup-common";
2
+ import type { HonoEnv } from "../api/types.js";
3
+ import type { StorageController } from "../storage/index.js";
4
+ import { BackupDestination } from "./backup-common.js";
5
5
  export interface BackupRoutesConfig {
6
6
  /**
7
7
  * Resolve the current backup destination, or `null` when backups are not
@@ -2,6 +2,6 @@
2
2
  * Storage-generic backup helpers and admin routes for the Backups panel.
3
3
  * The `pg_dump`/`pg_restore` machinery lives in `@rebasepro/server-postgres`.
4
4
  */
5
- export * from "./backup-common";
6
- export { createBackupRoutes } from "./backup-routes";
7
- export type { BackupRoutesConfig } from "./backup-routes";
5
+ export * from "./backup-common.js";
6
+ export { createBackupRoutes } from "./backup-routes.js";
7
+ export type { BackupRoutesConfig } from "./backup-routes.js";
@@ -1,8 +1,9 @@
1
- import { createRequire as __createRequire } from "module";
2
- import "process";
3
- __createRequire(import.meta.url);
4
- import { n as __exportAll } from "./rolldown-runtime-DSJWtz9O.js";
5
- import { n as errorHandler, t as ApiError } from "./errors-EBYiaJ2E.js";
1
+ import { createRequire as __rebaseCreateRequire } from "module";
2
+ import __rebaseProcess from "process";
3
+ globalThis.process ??= __rebaseProcess;
4
+ __rebaseCreateRequire(import.meta.url);
5
+ import { n as __exportAll } from "./rolldown-runtime-dW7B1o5h.js";
6
+ import { n as errorHandler, t as ApiError } from "./errors-DBwpj9N8.js";
6
7
  import fs from "fs";
7
8
  import path from "path";
8
9
  import { Hono } from "hono";
@@ -160,4 +161,4 @@ var backup_exports = /* @__PURE__ */ __exportAll({
160
161
  //#endregion
161
162
  export { parseBackupTimestamp as a, parseBackupDestination as i, createBackupRoutes as n, readBackupBytes as o, listBackupObjects as r, backup_exports as t };
162
163
 
163
- //# sourceMappingURL=backup-C6ljYVTp.js.map
164
+ //# sourceMappingURL=backup-CRdZkA6c.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"backup-C6ljYVTp.js","names":[],"sources":["../src/backup/backup-common.ts","../src/backup/backup-routes.ts","../src/backup/index.ts"],"sourcesContent":["/**\n * Storage-generic backup helpers used by the admin backup routes.\n *\n * These live in server (which owns {@link StorageController}) so the\n * admin API can list backups without depending on the Postgres driver —\n * `server` must not import from `server-postgres`. The `pg_dump`-side\n * copies of the tiny pure parsers live in `@rebasepro/server-postgres`;\n * keep the two in sync if the naming scheme ever changes.\n */\nimport fs from \"fs\";\nimport path from \"path\";\nimport type { BackupInfo, BackupDestinationKind } from \"@rebasepro/types\";\nimport type { StorageController } from \"../storage\";\n\nexport type BackupDestination =\n | { kind: \"local\"; path: string }\n | { kind: \"s3\"; bucket: string; prefix: string }\n | { kind: \"gcs\"; bucket: string; prefix: string };\n\n/** Parse a destination string (`s3://…`, `gs://…`, or a local path). */\nexport function parseBackupDestination(out: string): BackupDestination {\n const s3 = out.match(/^s3:\\/\\/([^/]+)\\/?(.*)$/);\n if (s3) return { kind: \"s3\", bucket: s3[1], prefix: s3[2].replace(/\\/+$/, \"\") };\n const gcs = out.match(/^gs:\\/\\/([^/]+)\\/?(.*)$/);\n if (gcs) return { kind: \"gcs\", bucket: gcs[1], prefix: gcs[2].replace(/\\/+$/, \"\") };\n return { kind: \"local\", path: out };\n}\n\n/**\n * Recover the UTC creation time encoded in a `rebase-<db>-<ts>.dump` name.\n * Returns `null` for names that don't match, so foreign objects are ignored.\n */\nexport function parseBackupTimestamp(fileName: string): Date | null {\n const base = fileName.split(\"/\").pop() ?? fileName;\n const match = base.match(/-(\\d{8})T(\\d{6})Z\\.dump$/);\n if (!match) return null;\n const [, ymd, hms] = match;\n const iso =\n `${ymd.slice(0, 4)}-${ymd.slice(4, 6)}-${ymd.slice(6, 8)}` +\n `T${hms.slice(0, 2)}:${hms.slice(2, 4)}:${hms.slice(4, 6)}Z`;\n const date = new Date(iso);\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\n/**\n * List the backups at a destination as {@link BackupInfo}, newest first.\n * Only `.dump` files are considered.\n */\nexport async function listBackupObjects(\n dest: BackupDestination,\n storage?: StorageController\n): Promise<BackupInfo[]> {\n if (dest.kind === \"local\") {\n if (!fs.existsSync(dest.path)) return [];\n const stat = fs.statSync(dest.path);\n const dir = stat.isDirectory() ? dest.path : path.dirname(dest.path);\n if (!fs.existsSync(dir)) return [];\n return fs\n .readdirSync(dir)\n .filter((f) => f.endsWith(\".dump\"))\n .map((f): BackupInfo => {\n const full = path.join(dir, f);\n const st = fs.statSync(full);\n const createdAt = parseBackupTimestamp(f) ?? st.mtime;\n return {\n key: full,\n name: f,\n sizeBytes: st.size,\n createdAt: createdAt.toISOString(),\n destinationKind: \"local\"\n };\n })\n .sort(byNewest);\n }\n\n if (!storage) return [];\n const result = await storage.listObjects(dest.prefix ? `${dest.prefix}/` : \"\", {\n bucket: dest.bucket,\n maxResults: 1000\n });\n return result.items\n .map((item) => item.fullPath)\n .filter((key) => key.endsWith(\".dump\"))\n .map((key): BackupInfo => {\n const createdAt = parseBackupTimestamp(key);\n return {\n key,\n name: key.split(\"/\").pop() || key,\n createdAt: createdAt ? createdAt.toISOString() : undefined,\n destinationKind: dest.kind as BackupDestinationKind\n };\n })\n .sort(byNewest);\n}\n\nfunction byNewest(a: BackupInfo, b: BackupInfo): number {\n const ta = a.createdAt ? Date.parse(a.createdAt) : 0;\n const tb = b.createdAt ? Date.parse(b.createdAt) : 0;\n return tb - ta;\n}\n\n/** Read a single backup's bytes. Guards against path traversal for local. */\nexport async function readBackupBytes(\n dest: BackupDestination,\n key: string,\n storage?: StorageController\n): Promise<{ bytes: Uint8Array<ArrayBuffer>; name: string } | null> {\n if (dest.kind === \"local\") {\n const stat = fs.existsSync(dest.path) ? fs.statSync(dest.path) : null;\n const dir = stat?.isDirectory() ? dest.path : path.dirname(dest.path);\n const resolvedDir = path.resolve(dir);\n const resolved = path.resolve(key);\n // Only allow reads inside the backup directory, and only .dump files.\n if (!resolved.startsWith(resolvedDir + path.sep) || !resolved.endsWith(\".dump\")) {\n return null;\n }\n if (!fs.existsSync(resolved)) return null;\n return { bytes: new Uint8Array(fs.readFileSync(resolved)), name: path.basename(resolved) };\n }\n\n if (!storage) return null;\n if (!key.endsWith(\".dump\")) return null;\n const file = await storage.getObject(key, dest.bucket);\n if (!file) return null;\n return { bytes: new Uint8Array(await file.arrayBuffer()), name: key.split(\"/\").pop() || key };\n}\n","import { Hono } from \"hono\";\nimport type { HonoEnv } from \"../api/types\";\nimport { ApiError, errorHandler } from \"../api/errors\";\nimport type { StorageController } from \"../storage\";\nimport { BackupDestination, listBackupObjects, readBackupBytes } from \"./backup-common\";\n\nexport interface BackupRoutesConfig {\n /**\n * Resolve the current backup destination, or `null` when backups are not\n * configured (`BACKUP_DESTINATION` unset). Read lazily so a restart isn't\n * required to pick up config.\n */\n getDestination: () => BackupDestination | null;\n /** Storage controller for object-storage destinations. */\n storage?: StorageController;\n}\n\n/**\n * Admin REST routes for the Backups panel.\n *\n * Routes (mounted under `/admin/backups`, admin-guarded by the caller):\n * GET / → list available backups\n * GET /download → download a backup's bytes (?key=…)\n */\nexport function createBackupRoutes(config: BackupRoutesConfig): Hono<HonoEnv> {\n const router = new Hono<HonoEnv>();\n router.onError(errorHandler);\n\n router.get(\"/\", async (c) => {\n const dest = config.getDestination();\n if (!dest) {\n return c.json({ backups: [], destinationKind: \"local\" as const, configured: false });\n }\n const backups = await listBackupObjects(dest, config.storage);\n return c.json({ backups, destinationKind: dest.kind, configured: true });\n });\n\n router.get(\"/download\", async (c) => {\n const dest = config.getDestination();\n if (!dest) {\n throw ApiError.badRequest(\"Backups are not configured (set BACKUP_DESTINATION).\");\n }\n const key = c.req.query(\"key\");\n if (!key) {\n throw ApiError.badRequest(\"Missing 'key' query parameter.\");\n }\n const result = await readBackupBytes(dest, key, config.storage);\n if (!result) {\n throw ApiError.notFound(`Backup not found: ${key}`);\n }\n c.header(\"Content-Type\", \"application/octet-stream\");\n c.header(\"Content-Disposition\", `attachment; filename=\"${result.name}\"`);\n return c.body(result.bytes);\n });\n\n return router;\n}\n","/**\n * Storage-generic backup helpers and admin routes for the Backups panel.\n * The `pg_dump`/`pg_restore` machinery lives in `@rebasepro/server-postgres`.\n */\nexport * from \"./backup-common\";\nexport { createBackupRoutes } from \"./backup-routes\";\nexport type { BackupRoutesConfig } from \"./backup-routes\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"backup-CRdZkA6c.js","names":[],"sources":["../src/backup/backup-common.ts","../src/backup/backup-routes.ts","../src/backup/index.ts"],"sourcesContent":["/**\n * Storage-generic backup helpers used by the admin backup routes.\n *\n * These live in server (which owns {@link StorageController}) so the\n * admin API can list backups without depending on the Postgres driver —\n * `server` must not import from `server-postgres`. The `pg_dump`-side\n * copies of the tiny pure parsers live in `@rebasepro/server-postgres`;\n * keep the two in sync if the naming scheme ever changes.\n */\nimport fs from \"fs\";\nimport path from \"path\";\nimport type { BackupInfo, BackupDestinationKind } from \"@rebasepro/types\";\nimport type { StorageController } from \"../storage\";\n\nexport type BackupDestination =\n | { kind: \"local\"; path: string }\n | { kind: \"s3\"; bucket: string; prefix: string }\n | { kind: \"gcs\"; bucket: string; prefix: string };\n\n/** Parse a destination string (`s3://…`, `gs://…`, or a local path). */\nexport function parseBackupDestination(out: string): BackupDestination {\n const s3 = out.match(/^s3:\\/\\/([^/]+)\\/?(.*)$/);\n if (s3) return { kind: \"s3\", bucket: s3[1], prefix: s3[2].replace(/\\/+$/, \"\") };\n const gcs = out.match(/^gs:\\/\\/([^/]+)\\/?(.*)$/);\n if (gcs) return { kind: \"gcs\", bucket: gcs[1], prefix: gcs[2].replace(/\\/+$/, \"\") };\n return { kind: \"local\", path: out };\n}\n\n/**\n * Recover the UTC creation time encoded in a `rebase-<db>-<ts>.dump` name.\n * Returns `null` for names that don't match, so foreign objects are ignored.\n */\nexport function parseBackupTimestamp(fileName: string): Date | null {\n const base = fileName.split(\"/\").pop() ?? fileName;\n const match = base.match(/-(\\d{8})T(\\d{6})Z\\.dump$/);\n if (!match) return null;\n const [, ymd, hms] = match;\n const iso =\n `${ymd.slice(0, 4)}-${ymd.slice(4, 6)}-${ymd.slice(6, 8)}` +\n `T${hms.slice(0, 2)}:${hms.slice(2, 4)}:${hms.slice(4, 6)}Z`;\n const date = new Date(iso);\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\n/**\n * List the backups at a destination as {@link BackupInfo}, newest first.\n * Only `.dump` files are considered.\n */\nexport async function listBackupObjects(\n dest: BackupDestination,\n storage?: StorageController\n): Promise<BackupInfo[]> {\n if (dest.kind === \"local\") {\n if (!fs.existsSync(dest.path)) return [];\n const stat = fs.statSync(dest.path);\n const dir = stat.isDirectory() ? dest.path : path.dirname(dest.path);\n if (!fs.existsSync(dir)) return [];\n return fs\n .readdirSync(dir)\n .filter((f) => f.endsWith(\".dump\"))\n .map((f): BackupInfo => {\n const full = path.join(dir, f);\n const st = fs.statSync(full);\n const createdAt = parseBackupTimestamp(f) ?? st.mtime;\n return {\n key: full,\n name: f,\n sizeBytes: st.size,\n createdAt: createdAt.toISOString(),\n destinationKind: \"local\"\n };\n })\n .sort(byNewest);\n }\n\n if (!storage) return [];\n const result = await storage.listObjects(dest.prefix ? `${dest.prefix}/` : \"\", {\n bucket: dest.bucket,\n maxResults: 1000\n });\n return result.items\n .map((item) => item.fullPath)\n .filter((key) => key.endsWith(\".dump\"))\n .map((key): BackupInfo => {\n const createdAt = parseBackupTimestamp(key);\n return {\n key,\n name: key.split(\"/\").pop() || key,\n createdAt: createdAt ? createdAt.toISOString() : undefined,\n destinationKind: dest.kind as BackupDestinationKind\n };\n })\n .sort(byNewest);\n}\n\nfunction byNewest(a: BackupInfo, b: BackupInfo): number {\n const ta = a.createdAt ? Date.parse(a.createdAt) : 0;\n const tb = b.createdAt ? Date.parse(b.createdAt) : 0;\n return tb - ta;\n}\n\n/** Read a single backup's bytes. Guards against path traversal for local. */\nexport async function readBackupBytes(\n dest: BackupDestination,\n key: string,\n storage?: StorageController\n): Promise<{ bytes: Uint8Array<ArrayBuffer>; name: string } | null> {\n if (dest.kind === \"local\") {\n const stat = fs.existsSync(dest.path) ? fs.statSync(dest.path) : null;\n const dir = stat?.isDirectory() ? dest.path : path.dirname(dest.path);\n const resolvedDir = path.resolve(dir);\n const resolved = path.resolve(key);\n // Only allow reads inside the backup directory, and only .dump files.\n if (!resolved.startsWith(resolvedDir + path.sep) || !resolved.endsWith(\".dump\")) {\n return null;\n }\n if (!fs.existsSync(resolved)) return null;\n return { bytes: new Uint8Array(fs.readFileSync(resolved)), name: path.basename(resolved) };\n }\n\n if (!storage) return null;\n if (!key.endsWith(\".dump\")) return null;\n const file = await storage.getObject(key, dest.bucket);\n if (!file) return null;\n return { bytes: new Uint8Array(await file.arrayBuffer()), name: key.split(\"/\").pop() || key };\n}\n","import { Hono } from \"hono\";\nimport type { HonoEnv } from \"../api/types\";\nimport { ApiError, errorHandler } from \"../api/errors\";\nimport type { StorageController } from \"../storage\";\nimport { BackupDestination, listBackupObjects, readBackupBytes } from \"./backup-common\";\n\nexport interface BackupRoutesConfig {\n /**\n * Resolve the current backup destination, or `null` when backups are not\n * configured (`BACKUP_DESTINATION` unset). Read lazily so a restart isn't\n * required to pick up config.\n */\n getDestination: () => BackupDestination | null;\n /** Storage controller for object-storage destinations. */\n storage?: StorageController;\n}\n\n/**\n * Admin REST routes for the Backups panel.\n *\n * Routes (mounted under `/admin/backups`, admin-guarded by the caller):\n * GET / → list available backups\n * GET /download → download a backup's bytes (?key=…)\n */\nexport function createBackupRoutes(config: BackupRoutesConfig): Hono<HonoEnv> {\n const router = new Hono<HonoEnv>();\n router.onError(errorHandler);\n\n router.get(\"/\", async (c) => {\n const dest = config.getDestination();\n if (!dest) {\n return c.json({ backups: [], destinationKind: \"local\" as const, configured: false });\n }\n const backups = await listBackupObjects(dest, config.storage);\n return c.json({ backups, destinationKind: dest.kind, configured: true });\n });\n\n router.get(\"/download\", async (c) => {\n const dest = config.getDestination();\n if (!dest) {\n throw ApiError.badRequest(\"Backups are not configured (set BACKUP_DESTINATION).\");\n }\n const key = c.req.query(\"key\");\n if (!key) {\n throw ApiError.badRequest(\"Missing 'key' query parameter.\");\n }\n const result = await readBackupBytes(dest, key, config.storage);\n if (!result) {\n throw ApiError.notFound(`Backup not found: ${key}`);\n }\n c.header(\"Content-Type\", \"application/octet-stream\");\n c.header(\"Content-Disposition\", `attachment; filename=\"${result.name}\"`);\n return c.body(result.bytes);\n });\n\n return router;\n}\n","/**\n * Storage-generic backup helpers and admin routes for the Backups panel.\n * The `pg_dump`/`pg_restore` machinery lives in `@rebasepro/server-postgres`.\n */\nexport * from \"./backup-common\";\nexport { createBackupRoutes } from \"./backup-routes\";\nexport type { BackupRoutesConfig } from \"./backup-routes\";\n"],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  import { type Server } from "http";
2
2
  import { Hono } from "hono";
3
- import { type RebaseBackendInstance } from "../init";
4
- import type { HonoEnv } from "../api/types";
5
- import { type RebaseBootEnv } from "./env";
6
- import { type LoadedBundle } from "./bundle";
7
- import { type InitializedDataSource } from "./driver";
3
+ import { type RebaseBackendInstance } from "../init.js";
4
+ import type { HonoEnv } from "../api/types.js";
5
+ import { type RebaseBootEnv } from "./env.js";
6
+ import { type LoadedBundle } from "./bundle.js";
7
+ import { type InitializedDataSource } from "./driver.js";
8
8
  /** A running runtime, and the handle to stop it. */
9
9
  export interface BootedRuntime {
10
10
  app: Hono<HonoEnv>;
@@ -1,5 +1,5 @@
1
1
  import { type CollectionConfig, type CollectionCallbacks, type DataSourceDefinition, type RebaseBundleManifest, type StorageSourceDefinition } from "@rebasepro/types";
2
- import type { StorageAuthorize } from "../storage/types";
2
+ import type { StorageAuthorize } from "../storage/types.js";
3
3
  /** Thrown when a bundle cannot be read, or claims a contract this runtime cannot honour. */
4
4
  export declare class BundleError extends Error {
5
5
  readonly hint?: string | undefined;
@@ -31,6 +31,15 @@ export interface LoadedStaticApp {
31
31
  /** Serve `index.html` for unmatched paths under `path`. */
32
32
  spa: boolean;
33
33
  }
34
+ /**
35
+ * The file that makes a directory a bundle.
36
+ *
37
+ * Exported because `fetch-bundle.ts` has to recognise the same thing after
38
+ * unpacking, and when it had its own idea of the name — `rebase-bundle.json`,
39
+ * which nothing has ever written — every download was rejected as "not a Rebase
40
+ * bundle". A marker with two spellings is a marker with none.
41
+ */
42
+ export declare const MANIFEST_FILENAME = "manifest.json";
34
43
  /**
35
44
  * Read and validate a bundle's manifest.
36
45
  *
@@ -1,5 +1,5 @@
1
1
  import type { BackendBootstrapper, DatabaseAdapter } from "@rebasepro/types";
2
- import type { ResolvedDataSourceConfig } from "./sources";
2
+ import type { ResolvedDataSourceConfig } from "./sources.js";
3
3
  /**
4
4
  * The connection handle a driver hands back at boot: the client object, the
5
5
  * pool to close on shutdown, and how to probe it.
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { type RebaseEnv } from "../env";
2
+ import { type RebaseEnv } from "../env.js";
3
3
  /**
4
4
  * The environment a bundle-booted runtime understands.
5
5
  *
@@ -52,6 +52,11 @@ declare const bootEnvExtension: z.ZodObject<{
52
52
  true: "true";
53
53
  false: "false";
54
54
  }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
55
+ STORAGE_RENDITION_CACHE: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
56
+ "": "";
57
+ true: "true";
58
+ false: "false";
59
+ }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
55
60
  STORAGE_ALLOW_ANY_AUTHENTICATED: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
56
61
  "": "";
57
62
  true: "true";
@@ -67,6 +72,23 @@ declare const bootEnvExtension: z.ZodObject<{
67
72
  true: "true";
68
73
  false: "false";
69
74
  }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
75
+ AUTH_MAGIC_LINK: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
76
+ "": "";
77
+ true: "true";
78
+ false: "false";
79
+ }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
80
+ AUTH_EMAIL_OTP: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
81
+ "": "";
82
+ true: "true";
83
+ false: "false";
84
+ }>>, z.ZodTransform<boolean, "" | "true" | "false">>;
85
+ CAPTCHA_PROVIDER: z.ZodOptional<z.ZodEnum<{
86
+ "": "";
87
+ turnstile: "turnstile";
88
+ hcaptcha: "hcaptcha";
89
+ }>>;
90
+ CAPTCHA_SECRET: z.ZodOptional<z.ZodString>;
91
+ CAPTCHA_ROUTES: z.ZodOptional<z.ZodString>;
70
92
  AUTH_COOKIE_SAME_SITE: z.ZodOptional<z.ZodEnum<{
71
93
  "": "";
72
94
  Strict: "Strict";
@@ -113,6 +135,11 @@ declare const bootEnvExtension: z.ZodObject<{
113
135
  true: "true";
114
136
  false: "false";
115
137
  }>>, z.ZodTransform<boolean | undefined, "" | "true" | "false" | undefined>>;
138
+ REBASE_RLS_AUDIT: z.ZodPipe<z.ZodOptional<z.ZodEnum<{
139
+ "": "";
140
+ true: "true";
141
+ false: "false";
142
+ }>>, z.ZodTransform<boolean | undefined, "" | "true" | "false" | undefined>>;
116
143
  REBASE_FUNCTIONS_ONLY: z.ZodOptional<z.ZodString>;
117
144
  REBASE_FUNCTIONS_EXCLUDE: z.ZodOptional<z.ZodString>;
118
145
  REBASE_FUNCTIONS_UPSTREAM: z.ZodOptional<z.ZodString>;
@@ -2,6 +2,22 @@
2
2
  export declare const BUNDLE_URL_ENV = "REBASE_BUNDLE_URL";
3
3
  /** Bearer token for that fetch. Does not expire — see the module note. */
4
4
  export declare const BUNDLE_TOKEN_ENV = "REBASE_BUNDLE_TOKEN";
5
+ /**
6
+ * Where a fetched bundle is unpacked. Defaults to a fresh temp directory.
7
+ *
8
+ * A platform sets this to a volume it sized on purpose, because the unpack and
9
+ * the dependency install are the two things in a pod's life that need real
10
+ * disk. Left unset the bundle lands under the OS temp directory, which on a
11
+ * container is the writable layer and on Cloud Run is a tmpfs — fine for a
12
+ * small bundle, and the thing to change first when one is not.
13
+ *
14
+ * It is deliberately a *fixed* directory when set, not a fresh one per boot: a
15
+ * container that restarts inside a live pod finds the tree it already unpacked
16
+ * and installed, so a restart costs a manifest check rather than a download and
17
+ * an `npm ci`. `REBASE_BUNDLE` is still the one that means "a bundle is already
18
+ * here, do not fetch at all" — this only says where to put one.
19
+ */
20
+ export declare const BUNDLE_FETCH_DIR_ENV = "REBASE_BUNDLE_FETCH_DIR";
5
21
  export interface FetchBundleOptions {
6
22
  url: string;
7
23
  token?: string;
@@ -11,8 +27,29 @@ export interface FetchBundleOptions {
11
27
  fetchImpl?: typeof fetch;
12
28
  /** Injected for tests. */
13
29
  extract?: (tarball: string, destination: string) => Promise<void>;
14
- /** How long the download may take before it is abandoned. */
30
+ /** How long a single download attempt may take before it is abandoned. */
15
31
  timeoutMs?: number;
32
+ /**
33
+ * How many times to try the download.
34
+ *
35
+ * A pod starting during a control-plane rollout, or racing its own DNS, gets
36
+ * one transient failure and would otherwise CrashLoop on it — and a
37
+ * CrashLoop re-runs the whole boot, so the retry is cheaper than the restart
38
+ * it replaces.
39
+ */
40
+ attempts?: number;
41
+ /** Delay between attempts. */
42
+ retryDelayMs?: number;
43
+ /**
44
+ * Install the bundle's declared dependencies after unpacking.
45
+ *
46
+ * On by default: a bundle that declares dependencies and has none installed
47
+ * cannot boot, and this is the only step between the two. Turned off for a
48
+ * bundle that was vendored at build time, and by tests.
49
+ */
50
+ installDependencies?: boolean;
51
+ /** Injected for tests. */
52
+ installImpl?: (bundleRoot: string) => Promise<void>;
16
53
  }
17
54
  /**
18
55
  * Whether this process should fetch its bundle rather than read one from disk.
@@ -31,6 +68,112 @@ export declare function shouldFetchBundle(env?: NodeJS.ProcessEnv): boolean;
31
68
  * refuse. Writing the whole tarball first means a truncated download is caught
32
69
  * by `tar` as a corrupt archive, which is an error.
33
70
  */
71
+ /**
72
+ * Install the bundle's declared dependencies, in place.
73
+ *
74
+ * `npm ci` when a lockfile is present and `npm install` otherwise — a bundle
75
+ * that shipped a lockfile gets a reproducible install, one that did not still
76
+ * boots.
77
+ *
78
+ * `--ignore-scripts` is not optional. The runtime image's entrypoint refuses to
79
+ * run lifecycle scripts, and an install that ran them here would void that
80
+ * guarantee at every pod start, executing arbitrary code from the dependency
81
+ * tree before the process this is meant to be booting exists.
82
+ *
83
+ * The npm cache is dropped afterwards because it is, at that point, a
84
+ * byte-for-byte duplicate of the tree beside it and nothing reads it again —
85
+ * the runtime never installs twice in one process. Keeping it doubles the
86
+ * high-water mark on a disk that is usually the binding constraint.
87
+ */
88
+ export declare function installBundleDependencies(bundleRoot: string, exec?: (cmd: string, args: string[], opts: object) => Promise<unknown>): Promise<void>;
89
+ /**
90
+ * Packages the runtime image provides and a bundle must not carry its own copy of.
91
+ *
92
+ * Exactly one, deliberately. `@rebasepro/server` holds the framework singleton,
93
+ * and a second copy is not merely wasteful — it is a total, silent breakage of
94
+ * custom functions. Every function imports `defineFunction` from
95
+ * `@rebasepro/server`, so it resolves the BUNDLE's copy, which is a different
96
+ * module instance from the one `runFromBundle` booted. The singleton
97
+ * initialised by the boot is invisible to it, so `rebase.data`,
98
+ * `rebase.dataAsAdmin` and `rebase.storage` throw "server not initialized yet"
99
+ * on every request, in a process that is otherwise healthy and reports itself
100
+ * ready. Seen in production as every custom-function route 500ing while
101
+ * `/api/data/*` served fine.
102
+ *
103
+ * It arrives transitively: `@rebasepro/admin` and `@rebasepro/server-postgres`
104
+ * both depend on it, and nearly every project declares one of them.
105
+ *
106
+ * NOT every package the image ships. The image installs the narrow set of
107
+ * dependencies the runtime itself needs, while the bundle's install resolved
108
+ * each package's FULL tree — so redirecting a package at the image's copy can
109
+ * point it at a tree missing something. `@rebasepro/server-postgres` is the
110
+ * proof: the image's copy has no `chokidar`, and redirecting it took the
111
+ * database driver down and crash-looped the pod. `@rebasepro/server` is the one
112
+ * package where the redirect is both necessary (it holds the singleton) and
113
+ * provably safe (the process is already running from the image's copy).
114
+ */
115
+ /**
116
+ * Where the runtime image keeps its own `node_modules`, when there is an image.
117
+ *
118
+ * An environment variable, set by the image, rather than something derived from
119
+ * this module's own location. Deriving it is the obvious approach and it does
120
+ * not survive the build: `__filename` is undefined in the ESM bundle vite emits,
121
+ * and `import.meta.url` is a syntax error under the CJS transform the jest
122
+ * suites use — so any version of this that reads its own path works in exactly
123
+ * one of the two places it has to.
124
+ *
125
+ * Found by booting the built image (`tooling/scripts/check-runtime-image-boots.mjs`),
126
+ * which is the only thing that runs the artifact this ships as. The unit tests
127
+ * were green.
128
+ *
129
+ * Absent outside a container, where there is no second copy to collapse and
130
+ * nothing to do.
131
+ */
132
+ export declare const RUNTIME_MODULES_ENV = "REBASE_RUNTIME_MODULES";
133
+ /**
134
+ * The packages the runtime image supplies to a fetched bundle.
135
+ *
136
+ * Must match `RUNTIME_PROVIDED` in `packages/cli/src/bundle.ts` and in
137
+ * `infra/docker/entrypoint.mjs`; `tooling/scripts/test/runtime-provided.test.mjs` fails if any
138
+ * of the three drift. The bundler STRIPS these from a bundle's declared
139
+ * dependencies on the promise that the image supplies them, so a shorter list
140
+ * here means the builder removed a dependency that nothing then provides, and
141
+ * every function and cron importing it fails to load with `Cannot find package`
142
+ * behind a container that reports itself healthy.
143
+ *
144
+ * This list carried only `@rebasepro/server` while the bundler stripped five —
145
+ * the same four-package gap that broke the non-fetch path, reproduced on the
146
+ * fetch path because this list was written before that fix and no gate watched
147
+ * this file.
148
+ */
149
+ export declare const RUNTIME_PROVIDED_PACKAGES: readonly ["@rebasepro/server", "@rebasepro/types", "@rebasepro/client", "@rebasepro/common", "@rebasepro/utils"];
150
+ /**
151
+ * Collapse a duplicate framework copy in the bundle onto the image's.
152
+ *
153
+ * Node resolves a module's identity by its real path, so replacing the
154
+ * duplicate with a symlink makes the two one instance again. It is also the
155
+ * honest version of what was already true: the image's copy is the one that
156
+ * booted and owns the process, so a bundle pinning a different version was
157
+ * never running that version — it just carried a second, dead one alongside it.
158
+ *
159
+ * Non-fatal by design. A project with no custom functions is unaffected by the
160
+ * duplicate, and refusing to boot over it would turn a degraded start into no
161
+ * start at all.
162
+ *
163
+ * @param imageModules the runtime image's own `node_modules`. Absent, there is
164
+ * nothing to dedupe against and this is a no-op — which is the case in every
165
+ * context except a container built from the runtime image.
166
+ */
167
+ export declare function dedupeRuntimePackages(bundleRoot: string, imageModules: string | undefined): string[];
168
+ /**
169
+ * Download, unpack and prepare a bundle, returning the directory it landed in.
170
+ *
171
+ * Downloads to a file rather than streaming into `tar`, deliberately. A stream
172
+ * that dies mid-transfer leaves `tar` having successfully extracted a prefix of
173
+ * the archive and exiting 0 — the half-unpacked bundle this module exists to
174
+ * refuse. Writing the whole tarball first means a truncated download is caught
175
+ * by `tar` as a corrupt archive, which is an error.
176
+ */
34
177
  export declare function fetchBundle(options: FetchBundleOptions): Promise<string>;
35
178
  /**
36
179
  * Find the bundle root inside an unpacked directory.
@@ -1,14 +1,38 @@
1
1
  import type { CollectionConfig } from "@rebasepro/types";
2
- import type { RebaseAuthConfig } from "../init";
3
- import type { EmailConfig } from "../email";
4
- import type { RebaseBootEnv } from "./env";
2
+ import type { RebaseAuthConfig } from "../init.js";
3
+ import type { EmailConfig } from "../email/index.js";
4
+ import type { CaptchaConfig } from "../auth/captcha.js";
5
+ import type { RebaseBootEnv } from "./env.js";
5
6
  /**
6
- * Build the email configuration, or `undefined` when no SMTP host is set.
7
+ * Build the email configuration.
7
8
  *
8
- * Without it the auth adapter still works; password-reset and verification mail
9
- * simply has nowhere to go, which the auth routes report for themselves.
9
+ * With `SMTP_HOST`, that is a real SMTP transport. Without it, outside
10
+ * production, it is the development sink: mail is captured and its links are
11
+ * printed, so `POST /auth/magic-link` and `POST /auth/forgot-password` complete
12
+ * on a fresh project instead of answering `503 EMAIL_NOT_CONFIGURED`. The token
13
+ * was always minted and valid; only delivery was missing.
14
+ *
15
+ * Three conditions, all required, none configurable:
16
+ *
17
+ * - no `SMTP_HOST` — a configured mail server always wins;
18
+ * - `NODE_ENV` is not `production` — a captured reset mail carries a working
19
+ * token, so this must not be reachable there (see `dev-sink.ts`);
20
+ * - an absolute `FRONTEND_URL`, or the emailed link has no base and is dead on
21
+ * arrival — which is the condition `assertEmailLinkBases` fails the boot on.
22
+ *
23
+ * When any of those does not hold this returns `undefined`, exactly as before,
24
+ * and the auth routes report the missing service for themselves.
10
25
  */
11
26
  export declare function resolveEmailOptions(env: RebaseBootEnv): EmailConfig | undefined;
27
+ /**
28
+ * Bot protection from the environment, or `undefined` when it is not configured.
29
+ *
30
+ * Both halves are required together. A provider with no secret cannot verify
31
+ * anything, so it is left off here and `resolveCaptchaVerifier` refuses the boot
32
+ * if something else turns it on — the one failure this feature must not have is
33
+ * being silently absent while the config says otherwise.
34
+ */
35
+ export declare function resolveCaptchaOptions(env: RebaseBootEnv): CaptchaConfig | undefined;
12
36
  /**
13
37
  * Build the auth configuration from the environment and the bundle's users
14
38
  * collection.
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The graph, expressed as the shapes the existing subsystems already take.
3
+ *
4
+ * The data layer consumes `DataSourceDefinition[]` and the storage layer
5
+ * consumes `StorageSourceDefinition[]`, and both work. Nothing about the
6
+ * resource graph requires rewriting them: the graph is a better *declaration*,
7
+ * not a different runtime. So it is translated at the boundary, once, and
8
+ * everything downstream is untouched.
9
+ *
10
+ * Doing it the other way round — teaching each subsystem to read the graph —
11
+ * would have meant touching the pool manager, the storage registry and the
12
+ * collection resolver to land a config change, which is how a config change
13
+ * becomes a rewrite and then does not ship.
14
+ */
15
+ import { type DataSourceDefinition, type ResourceGraph, type StorageSourceDefinition } from "@rebasepro/types";
16
+ /** Databases in the graph, as the data layer's definitions. */
17
+ export declare function graphToDataSources(graph: ResourceGraph): DataSourceDefinition[];
18
+ /** Buckets in the graph, as the storage layer's definitions. */
19
+ export declare function graphToStorageSources(graph: ResourceGraph): StorageSourceDefinition[];
20
+ /** Topics in the graph, for the runtime to publish through and the worker to wire. */
21
+ export declare function graphTopics(graph: ResourceGraph): ResourceGraph["resources"];
22
+ /**
23
+ * Refuse a config still carrying a replaced key.
24
+ *
25
+ * Throws on the first one rather than collecting: unlike a manifest, where a
26
+ * reader wants every problem at once, this is a single edit per key and the
27
+ * message is long enough that three of them would bury each other.
28
+ */
29
+ export declare function assertNoReplacedResourceConfig(config: Record<string, unknown>): void;
30
+ /** The keys this refuses, for a doctor check and for the tests that pin them. */
31
+ export declare function replacedResourceConfigKeys(): string[];
@@ -0,0 +1,10 @@
1
+ import { type ResourceGraph } from "@rebasepro/types";
2
+ import { type LoadedBundle } from "./bundle.js";
3
+ /**
4
+ * Evaluate a bundle's resource declarations and return the graph.
5
+ *
6
+ * A project with no `resources.ts` is normal and returns whatever the config
7
+ * index already registered — which for most projects is nothing, and a single
8
+ * default database is then synthesised downstream exactly as before.
9
+ */
10
+ export declare function loadBundleResourceGraph(bundle: LoadedBundle): Promise<ResourceGraph>;
@@ -13,8 +13,8 @@
13
13
  * a role that quietly runs no scheduler, or two roles that both provision the
14
14
  * schema, are failures nothing in a boot log makes obvious.
15
15
  */
16
- import type { RuntimeOwnershipOptions, RuntimeSurfaceOptions } from "../init/surfaces";
17
- import type { FunctionSelection } from "../functions/selection";
16
+ import type { RuntimeOwnershipOptions, RuntimeSurfaceOptions } from "../init/surfaces.js";
17
+ import type { FunctionSelection } from "../functions/selection.js";
18
18
  /** The four shapes a runtime process can boot in. */
19
19
  export type RebaseRuntimeRole = "all" | "api" | "functions" | "worker";
20
20
  /** Everything a role decides, resolved. */
@@ -34,6 +34,7 @@ export interface RoleEnv {
34
34
  REBASE_ROLE?: RebaseRuntimeRole;
35
35
  REBASE_CRON_SCHEDULER?: boolean;
36
36
  REBASE_JOB_WORKERS?: boolean;
37
+ REBASE_RLS_AUDIT?: boolean;
37
38
  REBASE_MIGRATE_ON_BOOT?: "none" | "ensure" | "push" | "";
38
39
  REBASE_FUNCTIONS_ONLY?: string;
39
40
  REBASE_FUNCTIONS_EXCLUDE?: string;
@@ -1,5 +1,5 @@
1
1
  import { type DataSourceDefinition, type StorageSourceDefinition } from "@rebasepro/types";
2
- import type { BackendStorageConfig } from "../storage/types";
2
+ import type { BackendStorageConfig } from "../storage/types.js";
3
3
  /**
4
4
  * Resolving *named* data and storage sources from the environment.
5
5
  *
@@ -79,7 +79,13 @@ export declare function resolveDataSources(env: EnvBag, definitions: DataSourceD
79
79
  * once, in `initializeStorage`, which logs precisely why storage is disabled.
80
80
  * Duplicating it would mean two places to keep in agreement.
81
81
  */
82
- export declare function resolveStorageBackend(env: EnvBag, key: string, engineHint: string | undefined, defaultBasePath: string): BackendStorageConfig | undefined;
82
+ export declare function resolveStorageBackend(env: EnvBag, key: string, engineHint: string | undefined, defaultBasePath: string,
83
+ /**
84
+ * The credential set this source shares, from its declaration. Only the
85
+ * account-scoped bindings — the ones describing the provider rather than the
86
+ * bucket — consult it. See `StorageSourceDefinition.account`.
87
+ */
88
+ accountHint?: string): BackendStorageConfig | undefined;
83
89
  /**
84
90
  * Resolve every server-transport storage source into a controller config map.
85
91
  *
@@ -87,7 +87,7 @@ export declare function readPackageVersion(packageDir: string): string | undefin
87
87
  * The version of `@rebasepro/server` this deployment is actually running.
88
88
  *
89
89
  * Resolved from the same roots the drivers are, and that is the point rather
90
- * than a convenience. In a managed container `docker/entrypoint.mjs` replaces
90
+ * than a convenience. In a managed container `infra/docker/entrypoint.mjs` replaces
91
91
  * `/bundle/node_modules/@rebasepro/server` with a link to the image's copy, so
92
92
  * reading the manifest *through the bundle* reports the version that will
93
93
  * really execute — which is exactly the number the driver has to be compared
@@ -1,5 +1,5 @@
1
1
  import { CollectionRegistry } from "@rebasepro/common";
2
- import { CollectionRegistryInterface } from "../db/interfaces";
2
+ import { CollectionRegistryInterface } from "../db/interfaces.js";
3
3
  /**
4
4
  * Backend-agnostic collection registry.
5
5
  * Satisfies CollectionRegistryInterface through inheritance from CollectionRegistry.
@@ -1,5 +1,5 @@
1
1
  import { CollectionConfig, SecurityRule } from "@rebasepro/types";
2
- import { type ValidateCollectionConfigOptions } from "./validate-config";
2
+ import { type ValidateCollectionConfigOptions } from "./validate-config.js";
3
3
  /**
4
4
  * The one definition of "the collections".
5
5
  *
@@ -33,6 +33,19 @@
33
33
  export type UnknownKeyPolicy = "warn" | "error" | "off";
34
34
  export interface ConfigProblem {
35
35
  severity: "error" | "warning";
36
+ /**
37
+ * What kind of wrong this is, because the two read very differently and the
38
+ * remedies differ.
39
+ *
40
+ * - `"key"` — a key this version does not read, whether renamed, removed or
41
+ * simply unrecognised. The feature it configures is absent; the config is
42
+ * otherwise coherent. `REBASE_STRICT_COLLECTION_CONFIG` governs how loud
43
+ * the unrecognised half of this is.
44
+ * - `"incoherent"` — every key is recognised and the *combination* cannot do
45
+ * what it says. That policy has no bearing on these, and saying it did
46
+ * sent people to an environment variable that would not have helped.
47
+ */
48
+ kind: "key" | "incoherent";
36
49
  /** Dotted path into the config, e.g. `posts.properties.author`. */
37
50
  path: string;
38
51
  message: string;
@@ -1,9 +1,10 @@
1
- import { createRequire as __createRequire } from "module";
2
- import "process";
3
- __createRequire(import.meta.url);
4
- import { n as __exportAll } from "./rolldown-runtime-DSJWtz9O.js";
5
- import "./src-CrCxd8km.js";
6
- import { t as logger } from "./logger-DfvF_8r-.js";
1
+ import { createRequire as __rebaseCreateRequire } from "module";
2
+ import __rebaseProcess from "process";
3
+ globalThis.process ??= __rebaseProcess;
4
+ __rebaseCreateRequire(import.meta.url);
5
+ import { n as __exportAll } from "./rolldown-runtime-dW7B1o5h.js";
6
+ import "./src-Cdsw7DqV.js";
7
+ import { t as logger } from "./logger-DS03e908.js";
7
8
  import { Hono } from "hono";
8
9
  //#region ../types/src/types/project_manifest.ts
9
10
  /** Header carrying the schema version an SDK was generated from. */
@@ -261,4 +262,4 @@ function createContractRoutes(config) {
261
262
  //#endregion
262
263
  export { createContractRoutes as n, computeSchemaVersion as r, contract_routes_exports as t };
263
264
 
264
- //# sourceMappingURL=contract-routes-DZ-LBpSL.js.map
265
+ //# sourceMappingURL=contract-routes-D8TvxPLo.js.map