@rebasepro/cli 0.25.0-canary.ge06257e → 0.25.1

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 (142) hide show
  1. package/bin/rebase.js +9 -5
  2. package/dist/{agent-setup-C83DXnlx.js → agent-setup-BYb2Tbdz.js} +2 -2
  3. package/dist/{agent-setup-C83DXnlx.js.map → agent-setup-BYb2Tbdz.js.map} +1 -1
  4. package/dist/{api-keys-Bc4FJKYp.js → api-keys-CSMbsmAn.js} +28 -22
  5. package/dist/api-keys-CSMbsmAn.js.map +1 -0
  6. package/dist/{apps-wG-ZTryA.js → apps-iBXNZhVN.js} +6 -7
  7. package/dist/{apps-wG-ZTryA.js.map → apps-iBXNZhVN.js.map} +1 -1
  8. package/dist/{atlas-dev-database-DeK3Sa4h.js → atlas-dev-database-BusbHP6n.js} +4 -4
  9. package/dist/{atlas-dev-database-DeK3Sa4h.js.map → atlas-dev-database-BusbHP6n.js.map} +1 -1
  10. package/dist/{auth-BL7bNQVu.js → auth-DRsTWPky.js} +77 -11
  11. package/dist/auth-DRsTWPky.js.map +1 -0
  12. package/dist/{branch-pointer-DTQNLFtb.js → branch-pointer-Bn_FjNld.js} +1 -1
  13. package/dist/{build-h_7Re-67.js → build-et7Rccxi.js} +6 -7
  14. package/dist/{build-h_7Re-67.js.map → build-et7Rccxi.js.map} +1 -1
  15. package/dist/{bundle-CqURVN-K.js → bundle-DlqkDYSe.js} +6 -21
  16. package/dist/bundle-DlqkDYSe.js.map +1 -0
  17. package/dist/{cloud-DVV_5GPG.js → cloud-B-ZIjHrA.js} +10 -11
  18. package/dist/{cloud-DVV_5GPG.js.map → cloud-B-ZIjHrA.js.map} +1 -1
  19. package/dist/commands/api-keys.d.ts +4 -1
  20. package/dist/commands/auth.d.ts +3 -2
  21. package/dist/commands/dev.d.ts +12 -0
  22. package/dist/commands/generate_sdk.d.ts +4 -2
  23. package/dist/commands/init.d.ts +20 -0
  24. package/dist/commands/start.d.ts +10 -0
  25. package/dist/commands/upgrade.d.ts +12 -0
  26. package/dist/connection-banner-DbLJzWf4.js +128 -0
  27. package/dist/connection-banner-DbLJzWf4.js.map +1 -0
  28. package/dist/{consent-ClRHmcxf.js → consent-BaB-eQKG.js} +2 -2
  29. package/dist/{consent-ClRHmcxf.js.map → consent-BaB-eQKG.js.map} +1 -1
  30. package/dist/{console-Dw3HLdUs.js → console-BlD9kjFW.js} +4 -4
  31. package/dist/{console-Dw3HLdUs.js.map → console-BlD9kjFW.js.map} +1 -1
  32. package/dist/{context-BM-oOMNX.js → context-DHiiiJ5C.js} +3 -4
  33. package/dist/context-DHiiiJ5C.js.map +1 -0
  34. package/dist/{daemon-CknkDjd6.js → daemon-DDMRbz4T.js} +160 -5
  35. package/dist/daemon-DDMRbz4T.js.map +1 -0
  36. package/dist/{daemon-entry-C6pxdily.js → daemon-entry-zOC1revO.js} +204 -5
  37. package/dist/daemon-entry-zOC1revO.js.map +1 -0
  38. package/dist/{db-Dkn9XhT-.js → db-9P6MnmdC.js} +237 -86
  39. package/dist/db-9P6MnmdC.js.map +1 -0
  40. package/dist/{derive-Dl0z2OWi.js → derive-MTdClnkc.js} +29 -14
  41. package/dist/{derive-Dl0z2OWi.js.map → derive-MTdClnkc.js.map} +1 -1
  42. package/dist/{dev-DAcZR4Pp.js → dev-BDN_OKXA.js} +183 -23
  43. package/dist/dev-BDN_OKXA.js.map +1 -0
  44. package/dist/dev-db/connection-banner.d.ts +47 -0
  45. package/dist/dev-db/daemon.d.ts +41 -0
  46. package/dist/dev-db/notification-proxy.d.ts +82 -1
  47. package/dist/dev-db/pull.d.ts +33 -5
  48. package/dist/dev-db/state.d.ts +9 -0
  49. package/dist/{dev-preflight-CorMg7Ub.js → dev-preflight-FT9GbJVj.js} +73 -4
  50. package/dist/dev-preflight-FT9GbJVj.js.map +1 -0
  51. package/dist/{dev-server-B1UYifZJ.js → dev-server-CIZwAfZa.js} +14 -3
  52. package/dist/dev-server-CIZwAfZa.js.map +1 -0
  53. package/dist/{doctor-Ds_lzc9p.js → doctor-D8YXz7df.js} +6 -6
  54. package/dist/doctor-D8YXz7df.js.map +1 -0
  55. package/dist/{eject-CJHkfnat.js → eject-izG2KjMo.js} +3 -4
  56. package/dist/{eject-CJHkfnat.js.map → eject-izG2KjMo.js.map} +1 -1
  57. package/dist/{fold-static-BC9CYicw.js → fold-static-CybSay_W.js} +3 -3
  58. package/dist/{fold-static-BC9CYicw.js.map → fold-static-CybSay_W.js.map} +1 -1
  59. package/dist/{generate_sdk-kfkZmG-d.js → generate_sdk-B4R65oUV.js} +22 -12
  60. package/dist/generate_sdk-B4R65oUV.js.map +1 -0
  61. package/dist/index.es.js +36 -37
  62. package/dist/index.es.js.map +1 -1
  63. package/dist/{init-CjoJoThg.js → init-DYaeppEN.js} +52 -63
  64. package/dist/init-DYaeppEN.js.map +1 -0
  65. package/dist/invoked-command-CG_rIa_o.js +55 -0
  66. package/dist/invoked-command-CG_rIa_o.js.map +1 -0
  67. package/dist/last-dev-database-B_75fxZC.js +2 -0
  68. package/dist/{manifest-DRp0UVTj.js → manifest-nvPdLlJY.js} +2 -2
  69. package/dist/{manifest-DRp0UVTj.js.map → manifest-nvPdLlJY.js.map} +1 -1
  70. package/dist/{normalize-imports-BHxL2d05.js → normalize-imports-BYw8ad87.js} +3 -3
  71. package/dist/{normalize-imports-BHxL2d05.js.map → normalize-imports-BYw8ad87.js.map} +1 -1
  72. package/dist/precompress.d.ts +0 -7
  73. package/dist/{prepare-C1iaiTC4.js → prepare-1rVNd2PF.js} +7 -6
  74. package/dist/prepare-1rVNd2PF.js.map +1 -0
  75. package/dist/project-g4K6kV1t.js +701 -0
  76. package/dist/project-g4K6kV1t.js.map +1 -0
  77. package/dist/{pull-COpNJFzY.js → pull-DDMpsZ5r.js} +143 -63
  78. package/dist/pull-DDMpsZ5r.js.map +1 -0
  79. package/dist/refusal-ReeeGP8a.js +26 -0
  80. package/dist/refusal-ReeeGP8a.js.map +1 -0
  81. package/dist/resolve-BQUAC3Wi.js +2 -0
  82. package/dist/resources/derive.d.ts +9 -0
  83. package/dist/{resources-CLm6g0br.js → resources-CovP8AZ-.js} +4 -5
  84. package/dist/{resources-CLm6g0br.js.map → resources-CovP8AZ-.js.map} +1 -1
  85. package/dist/{schema-BKdh6UoE.js → schema-nuxvvc50.js} +5 -6
  86. package/dist/{schema-BKdh6UoE.js.map → schema-nuxvvc50.js.map} +1 -1
  87. package/dist/{skills-DEhYiPeO.js → skills-DeUIsZcT.js} +3 -4
  88. package/dist/{skills-DEhYiPeO.js.map → skills-DeUIsZcT.js.map} +1 -1
  89. package/dist/{start-BsPJedPQ.js → start-RzZqDroW.js} +20 -7
  90. package/dist/start-RzZqDroW.js.map +1 -0
  91. package/dist/{state-CCB-FAQ9.js → state-CYdBvnwA.js} +3 -2
  92. package/dist/state-CYdBvnwA.js.map +1 -0
  93. package/dist/{status-D_B3tlDy.js → status-D9Zm88NZ.js} +11 -12
  94. package/dist/{status-D_B3tlDy.js.map → status-D9Zm88NZ.js.map} +1 -1
  95. package/dist/{storage-CtB8polS.js → storage-BB3umRfw.js} +3 -4
  96. package/dist/{storage-CtB8polS.js.map → storage-BB3umRfw.js.map} +1 -1
  97. package/dist/{telemetry-EMFRVRQi.js → telemetry-HfU5uAh1.js} +2 -2
  98. package/dist/{telemetry-EMFRVRQi.js.map → telemetry-HfU5uAh1.js.map} +1 -1
  99. package/dist/{telemetry-BYmPU-Ji.js → telemetry-TseNLk6X.js} +4 -4
  100. package/dist/{telemetry-BYmPU-Ji.js.map → telemetry-TseNLk6X.js.map} +1 -1
  101. package/dist/{upgrade-DbuKX9lv.js → upgrade-apiPKKE_.js} +29 -6
  102. package/dist/{upgrade-DbuKX9lv.js.map → upgrade-apiPKKE_.js.map} +1 -1
  103. package/dist/utils/args.d.ts +45 -3
  104. package/dist/utils/boot-retry.d.ts +41 -0
  105. package/dist/utils/dev-preflight.d.ts +34 -1
  106. package/dist/utils/dev-server.d.ts +11 -0
  107. package/dist/utils/project.d.ts +5 -1
  108. package/dist/utils/redact.d.ts +10 -0
  109. package/dist/utils/refusal.d.ts +18 -0
  110. package/dist/utils/unknown-command.d.ts +4 -0
  111. package/package.json +7 -7
  112. package/templates/overlays/baas/README.md +2 -1
  113. package/templates/resource-graphs/blank.json +25 -0
  114. package/templates/resource-graphs/blog.json +28 -0
  115. package/templates/resource-graphs/ecommerce.json +28 -0
  116. package/templates/resource-graphs/headless.json +22 -0
  117. package/templates/template/.env.example +11 -4
  118. package/templates/template/frontend/src/App.tsx +10 -9
  119. package/templates/template/frontend/vite.config.ts +7 -73
  120. package/dist/api-keys-Bc4FJKYp.js.map +0 -1
  121. package/dist/args-CcBphFdj.js +0 -237
  122. package/dist/args-CcBphFdj.js.map +0 -1
  123. package/dist/auth-BL7bNQVu.js.map +0 -1
  124. package/dist/bundle-CqURVN-K.js.map +0 -1
  125. package/dist/context-BM-oOMNX.js.map +0 -1
  126. package/dist/daemon-CknkDjd6.js.map +0 -1
  127. package/dist/daemon-entry-C6pxdily.js.map +0 -1
  128. package/dist/db-Dkn9XhT-.js.map +0 -1
  129. package/dist/dev-DAcZR4Pp.js.map +0 -1
  130. package/dist/dev-preflight-CorMg7Ub.js.map +0 -1
  131. package/dist/dev-server-B1UYifZJ.js.map +0 -1
  132. package/dist/doctor-Ds_lzc9p.js.map +0 -1
  133. package/dist/generate_sdk-kfkZmG-d.js.map +0 -1
  134. package/dist/init-CjoJoThg.js.map +0 -1
  135. package/dist/last-dev-database-BEBPfAMY.js +0 -2
  136. package/dist/prepare-C1iaiTC4.js.map +0 -1
  137. package/dist/project-Wp2zoyeN.js +0 -349
  138. package/dist/project-Wp2zoyeN.js.map +0 -1
  139. package/dist/pull-COpNJFzY.js.map +0 -1
  140. package/dist/resolve-b_p9bmdH.js +0 -2
  141. package/dist/start-BsPJedPQ.js.map +0 -1
  142. package/dist/state-CCB-FAQ9.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"bundle-CqURVN-K.js","names":[],"sources":["../src/utils/tool-stdio.ts","../src/precompress.ts","../src/bundle.ts"],"sourcesContent":["/**\n * The stdio a build tool the CLI runs in the foreground gets: a static app's\n * build command, `tsc`, `tar`.\n *\n * Inherited, so its output streams as it happens. With `quietStdout` its stdout\n * goes to stderr instead, for a command whose own stdout carries a result:\n * `rebase cloud deploy` in JSON mode — every piped run — owes stdout exactly one\n * JSON value, and a `vite v6 building…` line in front of it is a result no\n * parser can read. The tool's output still reaches the person watching.\n */\nexport function toolStdio(quietStdout: boolean | undefined): \"inherit\" | [\"ignore\", 2, \"inherit\"] {\n return quietStdout ? [\"ignore\", 2, \"inherit\"] : \"inherit\";\n}\n","/**\n * `.br` and `.gz` beside a static build's content-hashed assets, written when\n * the build is folded into a bundle.\n *\n * The runtime serves a sibling when the browser accepts its encoding\n * (`serveSPA` turns `precompressed` on at mount when the build holds any), so a\n * hashed chunk costs no compression CPU at all, on any request — including the\n * first one after a deploy, which otherwise gzips every chunk once per process\n * — and the browsers that accept brotli get it. Without siblings the runtime\n * only ever sends gzip.\n *\n * Which files: the ones the runtime caches as `immutable` — a content hash in\n * the name, by the same rule as the server's `isContentHashed` — of a type worth\n * compressing, and 1 KB or more (the runtime's own compression threshold). An\n * unhashed file (`index.html`) is left to on-the-fly compression, where a\n * rewrite of it can never be served stale from a sibling. A sibling is written\n * only when it is smaller, and never over one the build already emitted.\n *\n * Brotli at quality 9, not 11. On the example app's 5.6 MB of JavaScript,\n * quality 11 is 1.30 MB and took 20 s (8.7 s across the thread pool); quality\n * 9 is 1.41 MB in 0.9 s. gzip at level 9 is 1.57 MB in 0.3 s. A deploy runs\n * this every time, and a CI runner has fewer cores than a laptop.\n */\nimport fs from \"fs\";\nimport path from \"path\";\nimport zlib from \"zlib\";\n\n/** Below this a compressed response saves less than its headers cost — the runtime's threshold. */\nconst MIN_BYTES = 1024;\n\n/**\n * Extensions whose content type the runtime compresses (`COMPRESSIBLE_CONTENT_TYPE_REGEX`).\n * All of them, because a build with any sibling switches the runtime's cache of\n * gzipped hashed files off: a hashed type left out here would be compressed on\n * every request instead of once.\n */\nconst COMPRESSIBLE = new Set([\n \"js\", \"mjs\", \"cjs\", \"css\", \"html\", \"htm\", \"txt\", \"csv\", \"md\", \"xml\", \"json\", \"webmanifest\",\n \"svg\", \"wasm\", \"ttf\", \"otf\", \"eot\", \"ico\", \"bmp\"\n]);\n\n/**\n * A content hash in the name, by the runtime's rule (`isContentHashed` in the\n * server's `serve-spa.ts`): 8+ base64url characters after the last `-` with a\n * digit or a capital in them. `index-vgugiqRO.js` is; `vendor-analytics.js` is\n * not.\n */\nexport function isContentHashedName(fileName: string): boolean {\n const dot = fileName.lastIndexOf(\".\");\n if (dot <= 0) return false;\n const stem = fileName.slice(0, dot);\n const dash = stem.lastIndexOf(\"-\");\n if (dash < 0) return false;\n const suffix = stem.slice(dash + 1);\n return suffix.length >= 8 && /^[A-Za-z0-9_-]+$/.test(suffix) && /[0-9A-Z]/.test(suffix);\n}\n\nexport interface PrecompressOutcome {\n /** Files that got at least one sibling. */\n files: number;\n /** Their total size, and their siblings'. */\n bytes: number;\n brotliBytes: number;\n gzipBytes: number;\n}\n\n/** Write `.br` and `.gz` siblings for every hashed, compressible asset under `dir`. */\nexport function precompressStaticAssets(dir: string): PrecompressOutcome {\n const outcome: PrecompressOutcome = { files: 0, bytes: 0, brotliBytes: 0, gzipBytes: 0 };\n const pending = [dir];\n while (pending.length > 0) {\n const current = pending.pop() as string;\n for (const entry of fs.readdirSync(current, { withFileTypes: true })) {\n // Not build output, as the runtime's own scan has it.\n if (entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue;\n const file = path.join(current, entry.name);\n if (entry.isDirectory()) {\n pending.push(file);\n continue;\n }\n if (!entry.isFile() || !worthCompressing(entry.name)) continue;\n const source = fs.readFileSync(file);\n if (source.byteLength < MIN_BYTES) continue;\n\n const brotli = writeSibling(`${file}.br`, source, () => zlib.brotliCompressSync(source, {\n params: {\n [zlib.constants.BROTLI_PARAM_QUALITY]: 9,\n [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT,\n [zlib.constants.BROTLI_PARAM_SIZE_HINT]: source.byteLength\n }\n }));\n const gzip = writeSibling(`${file}.gz`, source, () => zlib.gzipSync(source, { level: 9 }));\n if (brotli === 0 && gzip === 0) continue;\n outcome.files++;\n outcome.bytes += source.byteLength;\n outcome.brotliBytes += brotli;\n outcome.gzipBytes += gzip;\n }\n }\n return outcome;\n}\n\nfunction worthCompressing(fileName: string): boolean {\n const extension = fileName.slice(fileName.lastIndexOf(\".\") + 1).toLowerCase();\n return COMPRESSIBLE.has(extension) && isContentHashedName(fileName);\n}\n\n/** The sibling's size, or 0 when there already was one or it would not be smaller. */\nfunction writeSibling(target: string, source: Buffer, compress: () => Buffer): number {\n if (fs.existsSync(target)) return 0;\n const compressed = compress();\n if (compressed.byteLength >= source.byteLength) return 0;\n fs.writeFileSync(target, compressed);\n return compressed.byteLength;\n}\n","/**\n * Building a project bundle.\n *\n * A bundle is the deployable form of a project: compiled collections, functions,\n * crons and schema, plus a generated manifest describing exactly what it needs\n * to run. It contains no Dockerfile and no repository — the runtime is supplied\n * separately, which is what allows a project to be moved onto a patched runtime\n * without being rebuilt.\n *\n * Compilation runs through a generated tsconfig rooted at the project directory,\n * so the output mirrors the source layout (`config/…`, `backend/functions/…`)\n * and every path in the manifest is predictable. Letting each workspace package\n * emit into its own `dist/` would have meant guessing at three different\n * layouts, since `rootDir` differs between the template flavours.\n */\nimport fs from \"fs\";\nimport path from \"path\";\nimport { createRequire } from \"module\";\nimport { spawnSync } from \"child_process\";\nimport chalk from \"chalk\";\nimport {\n BUNDLE_FORMAT_VERSION,\n RUNTIME_CONTRACT_VERSION,\n computeSchemaVersion,\n findStorageSuffixCollision,\n parseEnvBoolean,\n type CollectionConfig,\n type ResourceGraph,\n type NativeDependency,\n type RebaseBundleManifest,\n type RebaseBundleFunction,\n type RebaseBackendAppConfig\n} from \"@rebasepro/types\";\nimport { compareMountOrder, resolveBackendPaths } from \"./manifest\";\nimport { cliVersion } from \"./utils/version\";\nimport { toolStdio } from \"./utils/tool-stdio\";\nimport { analyseFunctionsDirectory, summarisePortability } from \"./function-portability\";\nimport { precompressStaticAssets } from \"./precompress\";\nimport {\n getActiveBackendPlugin,\n resolveLocalBin,\n resolvePluginCliScript,\n resolveTsx\n} from \"./utils/project\";\n\nexport const DEFAULT_BUNDLE_DIR = \"dist-bundle\";\n\nexport interface BuildBundleOptions {\n projectRoot: string;\n appName: string;\n app: RebaseBackendAppConfig;\n /** Output directory, absolute or relative to the project root. */\n outDir?: string;\n /** Runtime range from the manifest, recorded for compatibility checks. */\n runtimeRange: string;\n /**\n * The `storage` block of `rebase.json` — which buckets this project uses.\n *\n * Passed in rather than re-read here so `rebase.json` is parsed and validated\n * once, by the command that owns it.\n */\n /**\n * The project's resource graph, derived from its config.\n *\n * Recorded in the bundle manifest so a host can read what the project needs\n * without running it — which is what lets a console show \"wants a `media`\n * bucket, has none\" before a first deploy has produced anything.\n */\n resources?: ResourceGraph;\n /**\n * Install the declared dependencies into the bundle at build time.\n *\n * Omitted means \"when it is safe to\" — which is every bundle whose closure\n * has no native code. `false` is the escape hatch for a build that must not\n * shell out to npm at all (an air-gapped CI, a offline reproducibility\n * check); the bundle still works, it simply installs at boot as before.\n */\n vendor?: boolean;\n /** Skip type checking. Faster, and strictly worse — for iteration only. */\n skipTypeCheck?: boolean;\n /** Skip regenerating the Drizzle schema from the collections. */\n skipSchema?: boolean;\n /** Emit progress. */\n log?: (message: string) => void;\n /**\n * Keep stdout for the caller's result: the compiler's output, and every\n * warning the build prints, go to stderr. See `toolStdio`.\n */\n quietStdout?: boolean;\n}\n\nexport interface BuildBundleResult {\n outDir: string;\n manifest: RebaseBundleManifest;\n collectionCount: number;\n /**\n * Whether the dependency tree was installed into the bundle, and why not\n * when it was not. Reported rather than silent: \"your pods will take a\n * minute to start\" is a consequence a developer should hear at build time,\n * not discover during an incident.\n */\n vendor: VendorResult;\n}\n\n/** Packages whose presence means the bundle cannot run on a stock runtime image. */\nconst KNOWN_NATIVE_PACKAGES = new Set([\n \"sharp\",\n \"canvas\",\n \"bcrypt\",\n \"argon2\",\n \"node-sass\",\n \"sqlite3\",\n \"better-sqlite3\",\n \"grpc\",\n \"@grpc/grpc-js-native\",\n \"re2\",\n \"sodium-native\",\n \"libpq\",\n \"pg-native\"\n]);\n\n/** Dependencies supplied by the runtime image itself, not by the bundle. */\nconst RUNTIME_PROVIDED = new Set([\n \"@rebasepro/server\",\n \"@rebasepro/types\",\n \"@rebasepro/client\",\n \"@rebasepro/common\",\n \"@rebasepro/utils\",\n \"hono\",\n \"@hono/node-server\",\n \"typescript\",\n \"tsx\",\n // See entrypoint.mjs: a second zod makes `loadEnv({ extend })` reject every\n // value carrying a `.default()`, and the deploy reports success with no\n // crons running.\n \"zod\"\n]);\n\nfunction log(options: BuildBundleOptions, message: string): void {\n (options.log ?? ((m: string) => console.log(m)))(message);\n}\n\n/**\n * A line the build says to the person running it — a warning, or what it left\n * out — which progress callbacks may drop and this does not: stdout, or stderr\n * when stdout carries the caller's result.\n */\nfunction say(options: BuildBundleOptions, line: string): void {\n if (options.quietStdout) console.error(line);\n else console.log(line);\n}\n\n/**\n * Every `node_modules/@types` directory the project can see.\n *\n * Type roots normally resolve by walking up from the tsconfig's own directory,\n * which breaks here for two reasons: the generated config lives in `.rebase/`,\n * and a pnpm workspace puts `@types/node` inside the *package* that depends on\n * it (`config/node_modules/@types`) rather than at the project root. Listing them\n * explicitly, as absolute paths, sidesteps both.\n */\nfunction discoverTypeRoots(projectRoot: string): string[] {\n const candidates: string[] = [];\n\n for (const relative of [\".\", \"config\", \"backend\", \"frontend\"]) {\n candidates.push(path.join(projectRoot, relative, \"node_modules\", \"@types\"));\n }\n\n // Walk up as well, for a project nested inside a larger workspace.\n let dir = projectRoot;\n for (let i = 0; i < 4; i++) {\n const parent = path.dirname(dir);\n if (parent === dir) break;\n candidates.push(path.join(parent, \"node_modules\", \"@types\"));\n dir = parent;\n }\n\n return candidates.filter(candidate => fs.existsSync(candidate));\n}\n\n/**\n * Read a tsconfig's own `compilerOptions`.\n *\n * Parsed with the project's own TypeScript, because a tsconfig is not JSON: it\n * permits comments and trailing commas. Hand-rolled comment stripping gets this\n * wrong in a way that is easy to miss — a `paths` entry like\n * `\"@acme/types/*\": [\"src/*\"]` contains the character sequence that opens a\n * block comment, so a regex happily eats the rest of the file and the result\n * parses as *something*, just not the config the developer wrote.\n *\n * One level only, and only `paths` is used from it.\n */\nasync function readCompilerOptions(\n projectRoot: string,\n file: string\n): Promise<Record<string, unknown> | undefined> {\n if (!fs.existsSync(file)) return undefined;\n\n const text = fs.readFileSync(file, \"utf8\");\n\n try {\n const require = createRequire(path.join(projectRoot, \"package.json\"));\n const ts = require(\"typescript\") as {\n parseConfigFileTextToJson(fileName: string, text: string): {\n config?: { compilerOptions?: Record<string, unknown> };\n error?: unknown;\n };\n };\n const { config } = ts.parseConfigFileTextToJson(file, text);\n return config?.compilerOptions;\n } catch {\n // TypeScript is not resolvable from the project root. Fall back to\n // stripping whole-line comments only — never block comments, for the\n // reason above — and give up quietly if that still is not valid JSON.\n try {\n const parsed = JSON.parse(text.replace(/^\\s*\\/\\/.*$/gm, \"\")) as {\n compilerOptions?: Record<string, unknown>;\n };\n return parsed.compilerOptions;\n } catch {\n return undefined;\n }\n }\n}\n\n/**\n * Drop path aliases that resolve outside the project.\n *\n * A monorepo commonly aliases its workspace packages to their **source**\n * (`\"@acme/types\": [\"packages/types/src/index.ts\"]`) so editors jump to real\n * files. That is right for developing the monorepo and wrong for building a\n * bundle: it drags foreign `.ts` files into the program, none of which are under\n * the project's `rootDir`, and the compile fails on files the developer never\n * asked to build.\n *\n * A bundle is built against *installed packages*. Aliases pointing inside the\n * project are kept, because those are the project's own code.\n */\nfunction filterProjectPaths(\n baseDir: string,\n projectRoot: string,\n paths: Record<string, string[]>,\n baseUrl: string\n): { kept: Record<string, string[]>; dropped: string[] } {\n const kept: Record<string, string[]> = {};\n const dropped: string[] = [];\n\n for (const [alias, targets] of Object.entries(paths)) {\n if (!Array.isArray(targets)) continue;\n const resolved = targets.map(target => path.resolve(baseUrl, target));\n const allInside = resolved.every(target => {\n const relative = path.relative(projectRoot, target);\n return relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n });\n if (allInside) {\n kept[alias] = resolved.map(target => {\n const relative = path.relative(baseDir, target);\n return relative.split(path.sep).join(\"/\");\n });\n } else {\n dropped.push(alias);\n }\n }\n\n return { kept,\ndropped };\n}\n\n/**\n * Compose the tsconfig used to compile the bundle.\n *\n * Extends the config package's own tsconfig when there is one, so the project's\n * choices about target, JSX and strictness are respected. It has to be `extends`\n * rather than a copy of `compilerOptions`: TypeScript resolves relative paths\n * against the file they were written in, so copying a value like\n * `baseUrl: \"../../\"` into a config in a different directory silently repoints\n * it at the wrong place.\n */\nasync function writeBundleTsconfig(\n projectRoot: string,\n outDir: string,\n includes: string[],\n options: BuildBundleOptions\n): Promise<string> {\n const skipTypeCheck = options.skipTypeCheck === true;\n // Paths written *here* resolve against this file's directory. Posix\n // separators, because tsconfig wants them on every platform.\n const tsconfigDir = path.join(projectRoot, \".rebase\");\n const fromTsconfig = (target: string): string => {\n const relative = path.relative(tsconfigDir, path.resolve(projectRoot, target));\n return relative.split(path.sep).join(\"/\");\n };\n\n const configTsconfigPath = path.join(projectRoot, \"config\", \"tsconfig.json\");\n const extendsFrom = fs.existsSync(configTsconfigPath)\n ? fromTsconfig(path.join(\"config\", \"tsconfig.json\"))\n : undefined;\n\n // Neutralize aliases that escape the project (see `filterProjectPaths`).\n let pathOverrides: Record<string, unknown> = {};\n const baseOptions = await readCompilerOptions(projectRoot, configTsconfigPath);\n if (baseOptions?.paths && typeof baseOptions.paths === \"object\") {\n const baseDir = path.dirname(configTsconfigPath);\n const baseUrl = path.resolve(\n baseDir,\n typeof baseOptions.baseUrl === \"string\" ? baseOptions.baseUrl : \".\"\n );\n const { kept, dropped } = filterProjectPaths(\n tsconfigDir,\n projectRoot,\n baseOptions.paths as Record<string, string[]>,\n baseUrl\n );\n pathOverrides = { baseUrl: fromTsconfig(\".\"),\npaths: kept };\n if (dropped.length > 0) {\n say(options, chalk.dim(\n ` ignoring ${dropped.length} path alias(es) pointing outside the project ` +\n `(${dropped.join(\", \")}) — resolving those from node_modules instead`\n ));\n }\n }\n\n const compilerOptions: Record<string, unknown> = {\n // Defaults, used when there is no project tsconfig to extend. When there\n // is one, its values win over these and are overridden only by the block\n // below.\n target: \"ES2022\",\n module: \"ESNext\",\n moduleResolution: \"bundler\",\n lib: [\"ES2022\"],\n jsx: \"react-jsx\",\n allowSyntheticDefaultImports: true,\n esModuleInterop: true,\n resolveJsonModule: true,\n forceConsistentCasingInFileNames: true,\n\n // Everything below is the bundle's contract and is not negotiable.\n rootDir: fromTsconfig(\".\"),\n outDir: fromTsconfig(path.relative(projectRoot, outDir) || \".\"),\n typeRoots: discoverTypeRoots(projectRoot),\n ...pathOverrides,\n declaration: false,\n declarationMap: false,\n sourceMap: true,\n noEmit: false,\n skipLibCheck: true,\n // The runtime imports the emitted files directly with Node's ESM loader,\n // so they stay ES modules regardless of what the project targets for its\n // own builds.\n allowJs: true,\n ...(skipTypeCheck ? { noCheck: true } : {})\n };\n\n const tsconfig = {\n ...(extendsFrom ? { extends: extendsFrom } : {}),\n compilerOptions,\n include: includes.map(fromTsconfig),\n exclude: [\n \"node_modules\",\n \"**/*.test.ts\",\n \"**/*.spec.ts\",\n \"**/dist/**\",\n DEFAULT_BUNDLE_DIR\n ].map(pattern => (pattern.startsWith(\"**\") ? pattern : fromTsconfig(pattern)))\n };\n\n fs.mkdirSync(tsconfigDir, { recursive: true });\n const tsconfigPath = path.join(tsconfigDir, \"tsconfig.bundle.json\");\n fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2), \"utf8\");\n return tsconfigPath;\n}\n\n/**\n * Whether the compiled config package exports a `storageAuthorize` hook.\n *\n * Recorded in the manifest so a host can refuse a deploy that would enable file\n * storage with no access model, rather than let the runtime's boot guard turn it\n * into a crash loop the developer cannot read.\n *\n * Read from the *compiled* index, deliberately: that is the exact module the\n * runtime imports and reads the export off, so this cannot disagree with what\n * actually happens at boot. It is a textual check rather than an import because\n * a freshly built bundle cannot resolve its own dependencies until it is\n * deployed — the same reason schema hashing reads source.\n *\n * Errs toward `false`: a missed detection costs a deploy rejection whose message\n * says exactly how to proceed, while a false positive would hand back the crash\n * loop this exists to prevent.\n */\nexport function detectStorageAuthorize(compiledConfigDir: string, depth = 0): boolean {\n const indexPath = [\".js\", \".mjs\", \".ts\"]\n .map(ext => path.join(compiledConfigDir, `index${ext}`))\n .find(candidate => fs.existsSync(candidate));\n if (!indexPath) return false;\n return moduleExportsStorageAuthorize(indexPath, depth);\n}\n\n/**\n * Whether one compiled module re-exports or defines `storageAuthorize`.\n *\n * Split out from {@link detectStorageAuthorize} so a wildcard re-export can be\n * followed. `export * from \"./storage.js\"` is an ordinary way to write a config\n * barrel, and treating it as \"no hook\" rejected deploys that were correct — with\n * a message telling the developer to add a hook they had already written.\n */\nfunction moduleExportsStorageAuthorize(modulePath: string, depth: number): boolean {\n let source: string;\n try {\n source = fs.readFileSync(modulePath, \"utf8\");\n } catch {\n return false;\n }\n\n // `export const/let/var/function/async function storageAuthorize`\n if (/\\bexport\\s+(?:async\\s+)?(?:const|let|var|function)\\s+storageAuthorize\\b/.test(source)) {\n return true;\n }\n // `export { storageAuthorize }` / `export { x as storageAuthorize }`,\n // including re-export forms (`export { storageAuthorize } from \"./storage\"`).\n for (const clause of source.matchAll(/\\bexport\\s*\\{([^}]*)\\}/g)) {\n const names = clause[1].split(\",\").map(entry => {\n const parts = entry.split(/\\bas\\b/);\n return parts[parts.length - 1].trim();\n });\n if (names.includes(\"storageAuthorize\")) return true;\n }\n\n // `export * from \"./storage.js\"` — follow it. Bounded to a few levels: a\n // barrel of barrels is realistic, an infinite chain is not, and the cost of\n // giving up is a rejection message rather than a wrong answer.\n if (depth < 3) {\n for (const clause of source.matchAll(/\\bexport\\s*\\*\\s*from\\s*[\"']([^\"']+)[\"']/g)) {\n const specifier = clause[1];\n if (!specifier.startsWith(\".\")) continue;\n const resolved = resolveRelativeModule(path.dirname(modulePath), specifier);\n if (resolved && moduleExportsStorageAuthorize(resolved, depth + 1)) return true;\n }\n }\n return false;\n}\n\n/**\n * Resolve a relative ESM specifier to a file on disk.\n *\n * Compiled output carries explicit `.js` extensions, but the same function reads\n * TypeScript sources during a source boot, where the specifier may be\n * extensionless or point at a directory index.\n */\nfunction resolveRelativeModule(fromDir: string, specifier: string): string | null {\n const base = path.resolve(fromDir, specifier);\n const candidates = [\n base,\n `${base}.js`,\n `${base}.mjs`,\n `${base}.ts`,\n path.join(base, \"index.js\"),\n path.join(base, \"index.mjs\"),\n path.join(base, \"index.ts\")\n ];\n for (const candidate of candidates) {\n try {\n if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) return candidate;\n } catch {\n continue;\n }\n }\n // A `.js` specifier that only exists as `.ts` — the shape every compiled-from-\n // TypeScript barrel has when this runs against sources rather than output.\n if (/\\.js$/.test(base)) {\n const asTs = base.replace(/\\.js$/, \".ts\");\n try {\n if (fs.existsSync(asTs) && fs.statSync(asTs).isFile()) return asTs;\n } catch {\n return null;\n }\n }\n return null;\n}\n\n/**\n * Detect native code in the dependency closure.\n *\n * Walks declared runtime dependencies breadth-first through `node_modules`,\n * flagging anything with a `binding.gyp`, a prebuilt `.node` binary, or an\n * install script that builds one. The managed runtime cannot run these: a\n * binary compiled for one image will not load in another, and finding that out\n * at deploy time is far better than in a crash loop.\n *\n * The walk is bounded. A dependency graph can be enormous, and this is a\n * heuristic gate whose false negatives are caught at deploy time anyway.\n */\nexport function detectNativeDependencies(\n projectRoot: string,\n declared: Record<string, string>,\n limit = 2000\n): NativeDependency[] {\n const found: NativeDependency[] = [];\n const seen = new Set<string>();\n const queue = Object.keys(declared);\n let visited = 0;\n\n const searchRoots = [\n path.join(projectRoot, \"node_modules\"),\n path.join(projectRoot, \"backend\", \"node_modules\"),\n path.join(projectRoot, \"config\", \"node_modules\")\n ].filter(dir => fs.existsSync(dir));\n\n while (queue.length > 0 && visited < limit) {\n const name = queue.shift()!;\n if (seen.has(name)) continue;\n seen.add(name);\n visited++;\n\n if (KNOWN_NATIVE_PACKAGES.has(name)) {\n found.push({ name,\nreason: \"known native module\" });\n continue;\n }\n\n const packageDir = searchRoots\n .map(root => path.join(root, ...name.split(\"/\")))\n .find(dir => fs.existsSync(path.join(dir, \"package.json\")));\n\n if (!packageDir) continue;\n\n let pkg: {\n dependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n gypfile?: boolean;\n };\n try {\n pkg = JSON.parse(fs.readFileSync(path.join(packageDir, \"package.json\"), \"utf8\"));\n } catch {\n continue;\n }\n\n if (pkg.gypfile || fs.existsSync(path.join(packageDir, \"binding.gyp\"))) {\n found.push({ name,\nreason: \"builds a native addon (binding.gyp)\" });\n continue;\n }\n\n const install = `${pkg.scripts?.install ?? \"\"} ${pkg.scripts?.preinstall ?? \"\"} ${pkg.scripts?.postinstall ?? \"\"}`;\n if (/node-gyp|prebuild|node-pre-gyp|cmake-js/.test(install)) {\n found.push({ name,\nreason: \"install script compiles native code\" });\n continue;\n }\n\n if (hasNodeBinary(packageDir)) {\n found.push({ name,\nreason: \"ships a prebuilt .node binary\" });\n continue;\n }\n\n for (const dep of Object.keys(pkg.dependencies ?? {})) {\n if (!seen.has(dep)) queue.push(dep);\n }\n }\n\n return found;\n}\n\n/** Shallow scan for `.node` binaries — deep enough for the usual `build/Release`. */\nfunction hasNodeBinary(dir: string, depth = 0): boolean {\n if (depth > 3) return false;\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return false;\n }\n for (const entry of entries) {\n if (entry.isFile() && entry.name.endsWith(\".node\")) return true;\n if (entry.isDirectory() && entry.name !== \"node_modules\" && entry.name !== \".bin\") {\n if (hasNodeBinary(path.join(dir, entry.name), depth + 1)) return true;\n }\n }\n return false;\n}\n\n/**\n * Whether a dependency name resolves to a package *inside this repository* — a\n * workspace package rather than a registry one.\n *\n * The bundle's declared deps are installed with `npm install` from the public\n * registry beside the bundle at boot. A workspace package is not there, so\n * declaring it guarantees a boot-time install failure. The most common case is\n * the standard `config` package: the backend depends on it by name, but it is\n * *carried in the bundle* (as `entry.config`), so it must never also be an npm\n * dependency. Projects often express this as a `workspace:` range — caught\n * separately — but a plain `\"*\"` against a workspace symlink is just as common\n * and looks like a registry range, so the symlink is what actually settles it.\n *\n * Detection: the installed `node_modules/<name>` is a symlink whose real path is\n * inside the project and not within a pnpm virtual store (`.pnpm`). That is\n * exactly a workspace link and nothing else.\n */\nfunction resolvesToWorkspacePackage(projectRoot: string, name: string): boolean {\n // Resolve the root's own symlinks too: on macOS a temp/checkout path under\n // `/var/...` realpaths to `/private/var/...`, so comparing a realpath'd link\n // target against a non-realpath'd root would never match.\n let realRoot: string;\n try {\n realRoot = fs.realpathSync(projectRoot);\n } catch {\n realRoot = projectRoot;\n }\n\n for (const base of [projectRoot, path.join(projectRoot, \"backend\"), path.join(projectRoot, \"config\")]) {\n const link = path.join(base, \"node_modules\", name);\n try {\n // A workspace link is a *symlink*; a normal (non-pnpm) registry\n // install is a real directory inside node_modules, which would also\n // sit \"inside the repo\" — so the symlink is what separates the two.\n if (!fs.lstatSync(link).isSymbolicLink()) continue;\n const real = fs.realpathSync(link);\n const insideRepo = real.startsWith(realRoot + path.sep);\n // pnpm links registry packages into its virtual store; those live\n // under node_modules/.pnpm and are not workspace packages.\n const inStore = real.includes(`${path.sep}.pnpm${path.sep}`)\n || real.includes(`${path.sep}node_modules${path.sep}`);\n if (insideRepo && !inStore) return true;\n } catch {\n // No such entry, broken link, or race: let it be declared.\n }\n }\n return false;\n}\n\n/**\n * The manifests a bundle's declared dependencies come from, least specific first.\n *\n * Order is the whole point. `collectDeclaredDependencies` lets a later manifest\n * win, and the app — `backend/` — is the one whose code was written and\n * typechecked against the range it names. The project root is a workspace root:\n * it exists to hold scripts and the tooling every workspace shares, and its\n * ranges were never exercised by the code that ends up in the bundle. It used to\n * be read last, so a scaffold declaring `dotenv ^16` at the root and `^17.4.2`\n * in the backend shipped a manifest telling the managed runtime to install 16.\n */\nconst BUNDLE_DEP_MANIFESTS = [\"package.json\", \"config/package.json\", \"backend/package.json\"];\n\n/**\n * Specifiers the registry the managed runtime installs from cannot resolve.\n *\n * `workspace:` is handled separately (it is normal and expected inside this\n * repo's own projects); everything here is a specifier that works on the\n * developer's disk and nowhere else. The runtime installs `deps.declared` from\n * npm with no access to the machine the bundle was built on, so a `file:` or a\n * `git+` range is a deploy-time install failure — the worst place to find out.\n */\nconst NON_REGISTRY_PROTOCOLS = [\"file:\", \"link:\", \"portal:\", \"git+\", \"git:\", \"github:\"];\n\n/** Whether a range names something npm could not install from the registry. */\nfunction nonRegistrySpecifier(version: string): string | null {\n const trimmed = version.trim();\n for (const protocol of NON_REGISTRY_PROTOCOLS) {\n if (trimmed.startsWith(protocol)) return protocol;\n }\n // A bare path — `../shared`, `./vendor/lib`, `/opt/lib` — which npm accepts\n // as a local directory and the registry has never heard of.\n if (/^\\.{0,2}\\//.test(trimmed)) return \"a filesystem path\";\n return null;\n}\n\n/**\n * Collect the runtime dependencies a bundle needs installed beside it.\n *\n * Packages the runtime image already provides are excluded — reinstalling a\n * second copy of the server next to the one running the process is at best\n * wasted space and at worst a version conflict. Workspace packages are excluded\n * too: they are not on the registry the runtime installs from, and the project's\n * own config package already travels inside the bundle.\n *\n * Throws when a declared range is not something the registry can resolve, or\n * when two manifests declare a name at ranges nothing satisfies. The\n * alternative is a bundle that builds green and fails at the deploy's install\n * step, minutes later and on a machine the developer cannot see. `rebase build`\n * reports both in its own words first; this is the backstop for every other\n * caller, `rebase cloud deploy` included.\n */\nexport function collectDeclaredDependencies(projectRoot: string): Record<string, string> {\n const declared: Record<string, string> = {};\n\n const conflicts = detectDeclaredDepConflicts(projectRoot);\n if (conflicts.length > 0) {\n const described = conflicts\n .map(c => {\n const [a, b] = c.declarations;\n return `${c.name}: ${a.range} (${a.file}) vs ${b.range} (${b.file})`;\n })\n .join(\"; \");\n throw new Error(\n `No single version satisfies every range this project declares — ${described}. `\n + \"The bundle installs one of them and the rest of the project was built against \"\n + \"the other. Declare one range, in the app that uses it.\"\n );\n }\n\n for (const relative of BUNDLE_DEP_MANIFESTS) {\n const file = path.join(projectRoot, relative);\n if (!fs.existsSync(file)) continue;\n let pkg: { dependencies?: Record<string, string> };\n try {\n pkg = JSON.parse(fs.readFileSync(file, \"utf8\")) as typeof pkg;\n } catch {\n // Unparseable package.json: nothing to declare from it.\n continue;\n }\n for (const [name, version] of Object.entries(pkg.dependencies ?? {})) {\n if (RUNTIME_PROVIDED.has(name)) continue;\n // A workspace protocol means nothing outside this repository.\n if (typeof version === \"string\" && version.startsWith(\"workspace:\")) continue;\n // A plain range that nonetheless resolves to an in-repo workspace\n // package (e.g. `\"config\": \"*\"` symlinked to `../../config`) —\n // the runtime cannot install it from the registry.\n if (resolvesToWorkspacePackage(projectRoot, name)) continue;\n const protocol = typeof version === \"string\" ? nonRegistrySpecifier(version) : null;\n // The registry-install e2e stands packed tarballs in for versions\n // that were never published, as `file:` ranges the scaffold and its\n // Dockerfile both carry, and then builds and boots the result. The\n // flag is the same one `init` reads to skip its release probe; it\n // is set by that harness and by nothing a user runs.\n if (protocol && parseEnvBoolean(process.env.REBASE_E2E) === true && protocol === \"file:\") {\n declared[name] = version;\n continue;\n }\n if (protocol) {\n throw new Error(\n `${relative} declares \"${name}\": \"${version}\", which the managed runtime `\n + `cannot install — ${protocol} resolves only on this machine. Publish the `\n + \"package to a registry and depend on it by version, or vendor its source \"\n + \"into the backend.\"\n );\n }\n declared[name] = version;\n }\n }\n\n return declared;\n}\n\n/** One dependency as some package.json in the project declares it. */\nexport interface DeclaredFrameworkDep {\n name: string;\n range: string;\n /** Project-relative package.json it was declared in. */\n file: string;\n}\n\n/** One name two of the bundle's manifests declare at ranges nothing satisfies. */\nexport interface DeclaredDepConflict {\n name: string;\n /** The two declarations, in manifest order. */\n declarations: [DeclaredFrameworkDep, DeclaredFrameworkDep];\n}\n\nexport interface FrameworkDepDrift {\n /** Declared at a version that can never reach the CLI's own. */\n behind: DeclaredFrameworkDep[];\n /**\n * The distinct lower bounds found across all declared `@rebasepro/*`, when\n * there is more than one — the project is pinning mixed-era framework\n * packages against each other.\n */\n disagreeing: string[];\n /**\n * Third-party names two bundle manifests declare at ranges no single version\n * satisfies. One of the two wins in `deps.declared` and the loser's code was\n * typechecked against a version the runtime will never install.\n */\n conflicting: DeclaredDepConflict[];\n}\n\n/**\n * Lowest version a range could resolve to, or null if it is not a range.\n *\n * Kept deliberately tiny and local. The published range grammar here is a caret,\n * a tilde, an exact version or a `>=` floor, and the alternative — a semver\n * dependency in the CLI — buys breadth this does not need.\n */\nfunction lowerBoundOf(range: string): [number, number, number] | null {\n const raw = range.trim().replace(/^[\\^~]/, \"\").replace(/^>=\\s*/, \"\").replace(/^v/, \"\");\n if (!/^\\d+(\\.\\d+){0,2}$/.test(raw)) return null;\n const [major, minor = 0, patch = 0] = raw.split(\".\").map(Number);\n return [major, minor, patch];\n}\n\n/** Highest version a range could resolve to (exclusive), or null. */\nfunction upperBoundOf(range: string): [number, number, number] | null {\n const trimmed = range.trim();\n const min = lowerBoundOf(trimmed);\n if (!min) return null;\n if (trimmed.startsWith(\">=\")) return null; // open — reaches anything\n const [major, minor, patch] = min;\n if (trimmed.startsWith(\"^\")) {\n if (major > 0) return [major + 1, 0, 0];\n if (minor > 0) return [0, minor + 1, 0];\n return [0, 0, patch + 1];\n }\n if (trimmed.startsWith(\"~\")) {\n return trimmed.replace(/^~v?/, \"\").split(\".\").length >= 2\n ? [major, minor + 1, 0]\n : [major + 1, 0, 0];\n }\n const parts = trimmed.replace(/^v/, \"\").split(\".\").length;\n if (parts === 1) return [major + 1, 0, 0];\n if (parts === 2) return [major, minor + 1, 0];\n return [major, minor, patch + 1];\n}\n\nfunction compareTriples(a: [number, number, number], b: [number, number, number]): number {\n for (let i = 0; i < 3; i++) if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1;\n return 0;\n}\n\n/**\n * Whether a declared range could EVER resolve at or above `target`.\n *\n * The same question the control plane asks at intake, asked here first. Only a\n * range whose entire span sits below the target is reported — `^0.10.0` can\n * never cross to 0.12 whatever npm publishes — because a false alarm on a build\n * that would have worked trains people to ignore the warning that matters.\n */\nfunction canReach(range: string, target: string): boolean | null {\n const ceiling = upperBoundOf(range);\n const floor = lowerBoundOf(target);\n if (!floor || !lowerBoundOf(range)) return null;\n if (!ceiling) return true;\n return compareTriples(ceiling, floor) > 0;\n}\n\n/**\n * Whether no single published version can satisfy both ranges.\n *\n * Only a provable disagreement counts. Anything this tiny grammar cannot read —\n * a tag, an `||`, a `*` — returns false, because a build refused over a range\n * the CLI merely failed to parse is worse than the drift it was looking for.\n */\nfunction rangesDisjoint(a: string, b: string): boolean {\n const loA = lowerBoundOf(a);\n const loB = lowerBoundOf(b);\n if (!loA || !loB) return false;\n const hiA = upperBoundOf(a);\n const hiB = upperBoundOf(b);\n if (hiA && compareTriples(hiA, loB) <= 0) return true;\n if (hiB && compareTriples(hiB, loA) <= 0) return true;\n return false;\n}\n\n/**\n * Names two of the bundle's manifests declare at ranges nothing satisfies.\n *\n * `collectDeclaredDependencies` has to pick one — the app's — and the loser is\n * silent: the bundle tells the managed runtime to install a version the other\n * half of the project was never compiled against. The stock scaffold shipped\n * exactly that (`dotenv ^16` at the root, `^17.4.2` in `backend/`), so every\n * bundle built from a default project asked for dotenv 16.\n *\n * Scoped to the three manifests that feed `deps.declared`, and to their\n * `dependencies`: a `frontend/` that wants a different major of a build tool is\n * not this problem, and `devDependencies` never reach the bundle.\n */\nexport function detectDeclaredDepConflicts(projectRoot: string): DeclaredDepConflict[] {\n const seen = new Map<string, DeclaredFrameworkDep>();\n const conflicts: DeclaredDepConflict[] = [];\n\n for (const relative of BUNDLE_DEP_MANIFESTS) {\n const file = path.join(projectRoot, relative);\n if (!fs.existsSync(file)) continue;\n let pkg: { dependencies?: Record<string, string> };\n try {\n pkg = JSON.parse(fs.readFileSync(file, \"utf8\")) as typeof pkg;\n } catch {\n continue;\n }\n for (const [name, range] of Object.entries(pkg.dependencies ?? {})) {\n if (typeof range !== \"string\") continue;\n // The image supplies these; a disagreement about them never reaches\n // the manifest, and `disagreeing` already reports the framework ones.\n if (RUNTIME_PROVIDED.has(name)) continue;\n if (range.startsWith(\"workspace:\")) continue;\n const first = seen.get(name);\n if (!first) {\n seen.set(name, { name,\nrange,\nfile: relative });\n continue;\n }\n if (first.range === range) continue;\n if (!rangesDisjoint(first.range, range)) continue;\n conflicts.push({ name,\ndeclarations: [first, { name,\nrange,\nfile: relative }] });\n }\n }\n\n return conflicts;\n}\n\n/**\n * Find `@rebasepro/*` dependencies pinned to a version older than this CLI.\n *\n * This is the only place a developer can be told. In development, every\n * `@rebasepro/*` resolves through pnpm's `link:`/`workspace:` overrides to the\n * checkout, so the version STRINGS in package.json are never exercised — the\n * project runs fine locally on whatever is on disk, and the declared numbers are\n * first honoured when the runtime npm-installs them from a bundle in the cloud.\n * A project scaffolded at 0.10.0 therefore keeps working on a developer's\n * machine indefinitely while being, in the cloud, a 0.10.0 driver.\n *\n * That matters because the image supplies only `@rebasepro/server`; the database\n * driver comes from these declarations and a newer runtime never updates it.\n * Every package.json is scanned, `dependencies` and `devDependencies` both,\n * because they have to be bumped together and the one that gets forgotten is the\n * one nobody looks at.\n */\nexport function detectFrameworkDepDrift(projectRoot: string, cliVersion: string): FrameworkDepDrift {\n const found: DeclaredFrameworkDep[] = [];\n\n for (const relative of [\n \"package.json\",\n \"backend/package.json\",\n \"config/package.json\",\n \"frontend/package.json\"\n ]) {\n const file = path.join(projectRoot, relative);\n if (!fs.existsSync(file)) continue;\n try {\n const pkg = JSON.parse(fs.readFileSync(file, \"utf8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n for (const block of [pkg.dependencies, pkg.devDependencies]) {\n for (const [name, range] of Object.entries(block ?? {})) {\n if (!name.startsWith(\"@rebasepro/\")) continue;\n if (typeof range !== \"string\") continue;\n found.push({ name,\nrange,\nfile: relative });\n }\n }\n } catch {\n // Unparseable package.json: nothing to judge from it.\n }\n }\n\n const behind = found.filter(d => canReach(d.range, cliVersion) === false);\n\n // Mixed-era pins. Compared by lower bound rather than by string so `^0.12.0`\n // and `0.12.0` are not reported as a disagreement — they are not one.\n const bounds = new Set(\n found\n .map(d => lowerBoundOf(d.range))\n .filter((b): b is [number, number, number] => b != null)\n .map(b => b.join(\".\"))\n );\n\n return { behind,\ndisagreeing: bounds.size > 1 ? [...bounds].sort() : [],\nconflicting: detectDeclaredDepConflicts(projectRoot) };\n}\n\n/**\n * The `[start, end)` ranges of `//` and block comments in JavaScript source.\n *\n * `normalizeEsmSpecifiers` scans emitted output with a regular expression, and a\n * regular expression cannot tell a specifier from a specifier somebody wrote\n * about. The stock template ships one: `config/resources.ts` documents\n * `import { media } from \"../resources\";` inside a docblock, tsc preserves the\n * comment, and every `rebase build` of an untouched scaffold printed\n * `⚠ 1 import(s) could not be resolved`. A warning that is wrong on the default\n * project teaches people to ignore the warning that predicts a boot failure.\n *\n * Strings are tracked only so a `//` inside one — every `http://` in the tree —\n * does not open a comment that swallows the rest of the line. A `'` or `\"` span\n * ends at the newline as well as at its closing quote: a JavaScript string\n * cannot contain a raw newline, so a quote that reaches one was never a string\n * (a regex literal's, most likely) and the mistake must not run on.\n */\nexport function commentSpans(source: string): Array<[number, number]> {\n const spans: Array<[number, number]> = [];\n let quote: string | null = null;\n let i = 0;\n\n while (i < source.length) {\n const c = source[i];\n\n if (quote) {\n if (c === \"\\\\\") { i += 2; continue; }\n if (c === quote || (c === \"\\n\" && quote !== \"`\")) quote = null;\n i++;\n continue;\n }\n if (c === \"\\\"\" || c === \"'\" || c === \"`\") { quote = c; i++; continue; }\n\n if (c === \"/\" && source[i + 1] === \"/\") {\n const newline = source.indexOf(\"\\n\", i);\n const end = newline === -1 ? source.length : newline;\n spans.push([i, end]);\n i = end;\n continue;\n }\n if (c === \"/\" && source[i + 1] === \"*\") {\n const close = source.indexOf(\"*/\", i + 2);\n const end = close === -1 ? source.length : close + 2;\n spans.push([i, end]);\n i = end;\n continue;\n }\n i++;\n }\n return spans;\n}\n\n/**\n * Rewrite relative import specifiers in emitted JavaScript so Node can resolve them.\n *\n * TypeScript deliberately does not touch specifiers: `moduleResolution: \"bundler\"`\n * lets a project write `from \"./posts\"` or `from \"./collections\"`, and TypeScript\n * emits them unchanged on the assumption that a bundler will finish the job.\n * Nothing bundles a Rebase bundle — the runtime imports these files directly with\n * Node's ESM loader, which requires a full path with an extension and refuses\n * directory imports outright.\n *\n * Without this, adopting the bundle would mean asking every project written in\n * the (extremely common) extensionless style to rewrite all of its imports. The\n * rewrite is mechanical and verifiable: only relative specifiers are touched, and\n * only when the target file actually exists on disk.\n *\n * `write: false` computes the same answer and leaves every file as it was —\n * `rebase normalize-imports --check`, which reports and must not repair.\n */\nexport function normalizeEsmSpecifiers(\n outDir: string,\n options: { write?: boolean } = {}\n): { rewritten: number; unresolved: string[] } {\n const write = options.write !== false;\n const unresolved: string[] = [];\n let rewritten = 0;\n\n // The specifier of a static import/export, a bare side-effect import, or a\n // dynamic import. Emitted output is not minified, so these forms are stable.\n const SPECIFIER = /(\\bfrom\\s*|\\bimport\\s*\\(\\s*|\\bimport\\s+)([\"'])(\\.[^\"']*)\\2/g;\n\n const walk = (dir: string): void => {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n if (entry.name === \"node_modules\") continue;\n walk(full);\n } else if (entry.isFile() && entry.name.endsWith(\".js\")) {\n rewriteFile(full);\n }\n }\n };\n\n const rewriteFile = (file: string): void => {\n const original = fs.readFileSync(file, \"utf8\");\n const dir = path.dirname(file);\n const comments = commentSpans(original);\n const inComment = (at: number) => comments.some(([start, end]) => at >= start && at < end);\n\n const updated = original.replace(SPECIFIER, (match, prefix, quote, specifier, offset: number) => {\n // Prose, not code. Neither rewritten nor reported — see commentSpans.\n if (inComment(offset)) return match;\n\n // Already resolvable: has a real extension.\n if (/\\.(js|mjs|cjs|json|node)$/.test(specifier)) return match;\n\n const target = path.resolve(dir, specifier);\n\n if (fs.existsSync(`${target}.js`)) {\n rewritten++;\n return `${prefix}${quote}${specifier}.js${quote}`;\n }\n if (fs.existsSync(path.join(target, \"index.js\"))) {\n rewritten++;\n const suffix = specifier.endsWith(\"/\") ? \"index.js\" : \"/index.js\";\n return `${prefix}${quote}${specifier}${suffix}${quote}`;\n }\n\n // A `.ts` extension written explicitly in source becomes `.js` on disk.\n if (specifier.endsWith(\".ts\") && fs.existsSync(`${target.slice(0, -3)}.js`)) {\n rewritten++;\n return `${prefix}${quote}${specifier.slice(0, -3)}.js${quote}`;\n }\n\n unresolved.push(`${path.basename(file)} → ${specifier}`);\n return match;\n });\n\n if (write && updated !== original) {\n fs.writeFileSync(file, updated, \"utf8\");\n }\n };\n\n if (fs.existsSync(outDir)) walk(outDir);\n return { rewritten,\nunresolved };\n}\n\n/**\n * Remove a previous build so stale output cannot masquerade as current.\n *\n * The containment check matters because this is a recursive force-delete of a\n * path that came from a command-line flag: `rebase build --out ../..` would\n * otherwise erase the parent of the project. The manifest's own paths are\n * checked the same way; a flag deserves no less.\n */\nfunction cleanOutDir(projectRoot: string, outDir: string): void {\n const relative = path.relative(projectRoot, outDir);\n if (relative === \"\" || relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new Error(\n `Refusing to build into \"${outDir}\": the output directory must be inside the project.`\n );\n }\n\n if (fs.existsSync(outDir)) {\n fs.rmSync(outDir, { recursive: true,\nforce: true });\n }\n fs.mkdirSync(outDir, { recursive: true });\n}\n\n/**\n * Regenerate the Drizzle schema from the collections.\n *\n * Delegated to the database driver's own CLI — the same code `rebase schema\n * generate` runs — so there is one implementation of what a schema is. When no\n * driver is resolvable the build continues with a warning rather than failing:\n * a `baas` project has no schema to generate, and a project mid-install should\n * get a clear message rather than a hard stop.\n */\nasync function regenerateSchema(\n projectRoot: string,\n configDir: string,\n options: BuildBundleOptions\n): Promise<void> {\n const backendDir = path.join(projectRoot, \"backend\");\n if (!fs.existsSync(backendDir)) return;\n\n const plugin = getActiveBackendPlugin(backendDir);\n const script = plugin ? resolvePluginCliScript(backendDir, plugin) : null;\n if (!script) {\n log(options, chalk.dim(\" (no database driver found — skipping schema generation)\"));\n return;\n }\n\n const runner = script.endsWith(\".ts\") ? resolveTsx(projectRoot) : \"node\";\n if (!runner) {\n log(options, chalk.dim(\" (tsx not installed — skipping schema generation)\"));\n return;\n }\n\n const collectionsPath = path.join(\"..\", configDir, \"collections\");\n // Imported here, not at the top: this module is part of the package's\n // entry, which every `rebase` invocation loads, and execa is ~100 modules.\n const { execa } = await import(\"execa\");\n try {\n await execa(\n runner,\n [script, \"schema\", \"generate\", \"--collections\", collectionsPath],\n { cwd: backendDir,\nstdio: \"pipe\" }\n );\n log(options, chalk.dim(\" regenerated database schema from collections\"));\n } catch (err) {\n // A schema that cannot be generated means the bundle would carry a stale\n // one, and a stale schema is how a deploy quietly writes to the wrong\n // columns. Fail rather than ship it.\n const detail = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Schema generation failed, so the bundle was not written.\\n${detail}\\n` +\n \"Run `rebase schema generate` to see the full output, or pass --skip-schema \" +\n \"if the committed schema is deliberately hand-maintained.\"\n );\n }\n}\n\n/**\n * A hand-written server entrypoint that a bundle does not use.\n *\n * `rebase dev` runs `backend/src/index.ts` whenever a project has one, so for\n * the whole of local development that file *is* the server and every route\n * written in it works. A bundle has no entrypoint of its own: the runtime boots\n * the bundle and mounts what the manifest points at — the config package,\n * functions, crons and the schema. The file is not compiled, not shipped, and\n * never imported.\n *\n * Nothing said so. A project with custom routes in its entrypoint built clean,\n * deployed green, and answered 404 on every one of them, with the file still\n * sitting in the repository looking exactly like the server.\n *\n * A project that means to own its server process runs `rebase eject`, which\n * writes an entrypoint, a Dockerfile and a compose file together and flips the\n * backend to `runtime: \"custom\"`. The warning names that route rather than\n * implying the file is a mistake — but eject writes *its* entrypoint, so the\n * warning must not read as \"eject will keep what you wrote here\".\n */\nexport function findUnusedServerEntry(projectRoot: string, functionsDir: string): string | undefined {\n // A project that relocated its functions keeps the entrypoint beside them,\n // so the second candidate is derived rather than only the default known.\n const candidates = [\n path.join(\"backend\", \"src\", \"index.ts\"),\n path.join(path.dirname(functionsDir), \"src\", \"index.ts\")\n ];\n\n const found = candidates.find(candidate => fs.existsSync(path.join(projectRoot, candidate)));\n return found ? found.split(path.sep).join(\"/\") : undefined;\n}\n\n/**\n * Compile and assemble a bundle.\n */\n/** What `composeBundleManifest` needs: every input, already resolved. */\nexport interface ComposeManifestInput {\n runtimeRange: string;\n builtAgainst: string;\n schemaVersion: string;\n appName: string;\n entry: RebaseBundleManifest[\"entry\"];\n collectionSlugs: string[];\n functions: RebaseBundleFunction[];\n nativeModules: NativeDependency[];\n declaresStorageAuthorize: boolean;\n resources: ResourceGraph | undefined;\n declaredDeps: Record<string, string>;\n build: RebaseBundleManifest[\"build\"];\n}\n\n/**\n * The bundle manifest, as a pure function of its inputs.\n *\n * Separated from `buildBundle` so the SHAPE a host reads can be pinned by a\n * test without compiling a project: `tooling/contracts/bundle-manifest.json`\n * is written from this with fixed inputs, and the control plane's own tests\n * read that file to prove they consume what the CLI emits. That contract is\n * what was missing when buckets moved from `storage.sources` into `resources`\n * and the control plane went on reading the old field for two weeks — every\n * declared bucket arriving as nothing, with both suites green.\n */\nexport function composeBundleManifest(input: ComposeManifestInput): RebaseBundleManifest {\n return {\n bundleFormat: BUNDLE_FORMAT_VERSION,\n runtime: {\n range: input.runtimeRange,\n builtAgainst: input.builtAgainst,\n contract: RUNTIME_CONTRACT_VERSION\n },\n schemaVersion: input.schemaVersion,\n app: input.appName,\n kind: \"backend\",\n entry: input.entry,\n collections: [...input.collectionSlugs].sort(),\n ...(input.functions.length > 0 ? { functions: input.functions } : {}),\n hooks: {\n native: input.nativeModules.length > 0,\n nativeModules: input.nativeModules.length > 0 ? input.nativeModules : undefined\n },\n storage: {\n // The hook, not the buckets. Those live in `resources` now, with\n // every other kind, so a host reads one list instead of one per\n // kind — which is what let databases and buckets drift apart.\n authorize: input.declaresStorageAuthorize\n },\n resources: input.resources,\n deps: { declared: input.declaredDeps },\n build: input.build\n };\n}\n\n/**\n * What a build refusing on {@link detectDeclaredDepConflicts} says: every name,\n * both ranges and where each is declared.\n */\nexport function describeDepConflicts(conflicts: DeclaredDepConflict[]): string {\n const lines = [`${conflicts.length} dependency range(s) no single version satisfies:`];\n for (const { name, declarations: [first, second] } of conflicts) {\n lines.push(` ${name}`, ` ${first.range} (${first.file})`, ` ${second.range} (${second.file})`);\n }\n lines.push(\n \" The bundle installs one range; the other half of the project was built against the other.\",\n \" Declare one range, in the app that uses it.\"\n );\n return lines.join(\"\\n\");\n}\n\nexport async function buildBundle(options: BuildBundleOptions): Promise<BuildBundleResult> {\n const { projectRoot, app, appName } = options;\n\n /* Two of this project's manifests want versions of one package that no\n single release satisfies.\n\n Fatal, and fatal before anything is built, because the bundle can only\n carry one of them: whichever manifest is read last wins, and the other\n half of the project was compiled against something the runtime will\n never install. There is no correct bundle to produce. Here rather than\n in a command, because every command that builds a bundle has to refuse\n it: `rebase cloud deploy` builds its own, and shipped what `rebase\n build` refused. */\n const conflicts = detectDeclaredDepConflicts(projectRoot);\n if (conflicts.length > 0) throw new Error(describeDepConflicts(conflicts));\n\n const paths = resolveBackendPaths(app, projectRoot);\n const outDir = path.resolve(projectRoot, options.outDir ?? DEFAULT_BUNDLE_DIR);\n\n const includes: string[] = [];\n const addIfExists = (relative: string, pattern: string): void => {\n if (fs.existsSync(path.join(projectRoot, relative))) includes.push(pattern);\n };\n\n // The whole config package, not just its collections: a headless project\n // has no `config/collections` but still ships `storageAuthorize` here.\n if (paths.hasConfig) {\n addIfExists(paths.config, `${paths.config}/**/*.ts`);\n }\n addIfExists(paths.functions, `${paths.functions}/**/*.ts`);\n addIfExists(paths.crons, `${paths.crons}/**/*.ts`);\n if (fs.existsSync(path.join(projectRoot, paths.schema))) {\n includes.push(paths.schema);\n }\n\n if (includes.length === 0) {\n throw new Error(\n `Nothing to build for app \"${appName}\". Expected a config directory at ` +\n `\"${paths.config}\" or functions at \"${paths.functions}\".`\n );\n }\n\n // Regenerate the Drizzle schema from the collections first.\n //\n // The template's backend build did this, so a project moving to the bundle\n // flow would otherwise silently ship whatever `schema.generated.ts` happened\n // to be on disk — stale by exactly the edits just made.\n if (paths.hasCollections && options.skipSchema !== true) {\n await regenerateSchema(projectRoot, paths.config, options);\n }\n\n // Say out loud what this build is NOT going to include. See\n // `findUnusedServerEntry` for why silence here was expensive.\n const unusedEntry = findUnusedServerEntry(projectRoot, paths.functions);\n if (unusedEntry) {\n const parts = [\n ...(paths.hasCollections ? [`${paths.config}/`] : []),\n `${paths.functions}/`,\n \"the schema\"\n ];\n const compiled = `${parts.slice(0, -1).join(\", \")} and ${parts[parts.length - 1]}`;\n say(options, chalk.yellow(` ⚠ ${unusedEntry} is not the bundle's entry point — it is not compiled or shipped.`));\n say(options, chalk.dim(` The runtime boots the bundle itself and mounts ${compiled}.`));\n say(options, chalk.dim(` Routes defined there will not exist once deployed: move them to ${paths.functions}/,`));\n say(options, chalk.dim(\" or run `rebase eject`, which writes an entrypoint of its own and owns\"));\n say(options, chalk.dim(\" the image — it does not adopt this file, and will not replace it\"));\n say(options, chalk.dim(\" without --force.\"));\n }\n\n log(options, chalk.dim(` compiling ${includes.length} source group(s) → ${path.relative(projectRoot, outDir)}/`));\n\n cleanOutDir(projectRoot, outDir);\n const tsconfigPath = await writeBundleTsconfig(projectRoot, outDir, includes, options);\n\n const tsc = resolveLocalBin(projectRoot, \"tsc\");\n if (!tsc) {\n throw new Error(\n \"TypeScript is not installed in this project. Run your package manager's install first.\"\n );\n }\n\n const { execa } = await import(\"execa\");\n try {\n await execa(tsc, [\"-p\", tsconfigPath], { cwd: projectRoot,\nstdio: toolStdio(options.quietStdout) });\n } catch {\n throw new Error(\"TypeScript compilation failed — the bundle was not written.\");\n }\n\n // Node resolves these files directly, so their specifiers must be complete.\n const normalized = normalizeEsmSpecifiers(outDir);\n if (normalized.rewritten > 0) {\n log(options, chalk.dim(` resolved ${normalized.rewritten} relative import(s) for Node ESM`));\n }\n if (normalized.unresolved.length > 0) {\n say(options, chalk.yellow(\n ` ⚠ ${normalized.unresolved.length} import(s) could not be resolved to a file:`\n ));\n for (const item of normalized.unresolved.slice(0, 5)) {\n say(options, chalk.dim(` ${item}`));\n }\n if (normalized.unresolved.length > 5) {\n say(options, chalk.dim(` … and ${normalized.unresolved.length - 5} more`));\n }\n }\n\n // ── Inspect what was produced ────────────────────────────────────────────\n const compiledConfigDir = path.join(outDir, paths.config);\n const compiledCollectionsDir = path.join(compiledConfigDir, \"collections\");\n\n let collections: CollectionConfig[] = [];\n if (paths.hasCollections) {\n collections = await loadSourceCollections(path.join(projectRoot, paths.config, \"collections\"));\n if (collections.length === 0) {\n throw new Error(\n \"No collections were found in \" +\n `${path.join(paths.config, \"collections\")}. ` +\n \"Define at least one collection there, or remove the directory to have the \" +\n \"runtime introspect collections from the live database instead.\"\n );\n }\n if (!fs.existsSync(compiledCollectionsDir)) {\n throw new Error(\n \"Compilation produced no collections directory at \" +\n `${path.relative(projectRoot, compiledCollectionsDir)}.`\n );\n }\n }\n\n const declared = collectDeclaredDependencies(projectRoot);\n const nativeModules = detectNativeDependencies(projectRoot, declared);\n const declaresStorageAuthorize = detectStorageAuthorize(path.join(outDir, paths.config));\n\n // Resolve the declared buckets now, and refuse the build if two of them would\n // read the same environment variables. Catching it here means a rename, not a\n // tenant that silently served one bucket's files from another's credentials.\n const resourceGraph: ResourceGraph = options.resources ?? { version: 1, resources: [] };\n const storageSources = resourceGraph.resources\n .filter(r => r.kind === \"bucket\")\n .map(r => ({\n key: r.key,\n engine: r.engine,\n transport: r.transport,\n ...(r.label !== undefined ? { label: r.label } : {})\n }));\n const collision = findStorageSuffixCollision(storageSources.map(s => s.key));\n if (collision) {\n throw new Error(\n `Buckets \"${collision.a}\" and \"${collision.b}\" both map to the environment variable ` +\n `suffix \"${collision.suffix || \"(none)\"}\", so they would read each other's ` +\n \"configuration. Rename one of them.\"\n );\n }\n\n const schemaOut = paths.schema.replace(/\\.ts$/, \".js\");\n const relative = (target: string): string | undefined =>\n fs.existsSync(path.join(outDir, target)) ? target : undefined;\n\n // What is in the functions directory, and what each one needs from its\n // host. Read from the *source*, not the compiled output, because the answer\n // is about imports and `tsc` has already resolved some of them away.\n const functionReports = analyseFunctionsDirectory(\n path.join(projectRoot, paths.functions),\n projectRoot\n );\n const bundledFunctions: RebaseBundleFunction[] = functionReports.map(report => {\n const requires = [...new Set(\n report.issues\n .filter(issue => issue.kind === \"node-builtin\" || issue.kind === \"node-only-package\")\n .map(issue => issue.message)\n )];\n return {\n name: report.name,\n // The path as it exists *in the bundle*: sources are compiled 1:1,\n // so this is the same relative path with a `.js` extension.\n file: report.file.replace(/\\.ts$/, \".js\"),\n portable: report.portable,\n ...(requires.length > 0 ? { requires } : {})\n };\n });\n\n for (const line of summarisePortability(functionReports)) {\n say(options, line.trimStart().startsWith(\"⚠\") ? chalk.yellow(line) : chalk.dim(line));\n }\n\n const manifest = composeBundleManifest({\n runtimeRange: options.runtimeRange,\n builtAgainst: resolveServerVersion(projectRoot),\n // A build with no config directory genuinely does not know the schema —\n // collections are introspected from the live database at boot. Recording\n // a version here would stamp the hash of an empty list, and the runtime\n // would then serve that as the identity of whatever it actually found.\n // Empty means \"ask the runtime\", which is the honest answer.\n schemaVersion: paths.hasCollections ? computeSchemaVersion(collections) : \"\",\n appName,\n entry: {\n config: paths.hasConfig ? relative(paths.config) : undefined,\n collections: paths.hasCollections ? relative(path.join(paths.config, \"collections\")) : undefined,\n functions: relative(paths.functions),\n crons: relative(paths.crons),\n schema: relative(schemaOut),\n usersCollection: paths.hasCollections\n ? relative(path.join(paths.config, `${paths.usersCollection}.js`))\n : undefined\n },\n collectionSlugs: collections\n .map(collection => collection.slug)\n .filter((slug): slug is string => Boolean(slug)),\n functions: bundledFunctions,\n nativeModules,\n declaresStorageAuthorize,\n resources: resourceGraph,\n declaredDeps: declared,\n build: {\n cli: cliVersion(),\n node: process.versions.node.split(\".\")[0],\n createdAt: new Date().toISOString()\n }\n });\n\n fs.writeFileSync(\n path.join(outDir, \"manifest.json\"),\n `${JSON.stringify(manifest, null, 2)}\\n`,\n \"utf8\"\n );\n\n // A package.json beside the bundle lets a deployment install exactly the\n // dependencies the project declared, with no access to the repository.\n fs.writeFileSync(\n path.join(outDir, \"package.json\"),\n `${JSON.stringify({\n name: \"rebase-bundle\",\n private: true,\n type: \"module\",\n dependencies: declared\n }, null, 2)}\\n`,\n \"utf8\"\n );\n\n const vendor = vendorDependencies({\n outDir,\n declared,\n nativeModules,\n // The driver is the one package the image does not supply, so it is the\n // one a vendored tree must actually contain.\n required: [getActiveBackendPlugin(path.join(projectRoot, \"backend\"))].filter(\n (name): name is string => Boolean(name)),\n requested: options.vendor\n });\n if (vendor.vendored) {\n manifest.deps.vendored = true;\n manifest.deps.vendorTarget = vendor.target;\n // Rewritten rather than assembled differently above: the install needs\n // the package.json this function already wrote, so the manifest cannot\n // know the answer until afterwards.\n fs.writeFileSync(\n path.join(outDir, \"manifest.json\"),\n `${JSON.stringify(manifest, null, 2)}\\n`,\n \"utf8\"\n );\n }\n\n return { outDir,\nmanifest,\ncollectionCount: collections.length,\nvendor };\n}\n\n/** Default install target: what the published runtime image runs. */\nexport const VENDOR_TARGET_OS = \"linux\";\nexport const VENDOR_TARGET_CPU = \"x64\";\n\nexport interface VendorResult {\n vendored: boolean;\n target?: { os: string; cpu: string; node: string };\n /** Why nothing was installed. Present exactly when `vendored` is false. */\n skipped?: string;\n /** Size of the installed tree on disk, when one was installed. */\n bytes?: number;\n}\n\n/**\n * Where a vendored bundle starts being too big to upload.\n *\n * The control plane refuses a bundle over 100 MB, and that ceiling is not\n * arbitrary or easily raised: its pod has a 512Mi memory limit and the upload\n * route holds the body while it writes it, so the cap protects the process that\n * also serves the console, deploys and billing. Vendoring is the one change that\n * can push a bundle near it.\n *\n * So the warning is here, at build time, where the remedy is one flag away —\n * rather than at deploy time as a 413 nobody can act on without rebuilding. The\n * threshold sits below the real cap because this measures the tree on disk and\n * the upload is compressed: crossing it means \"getting close\", not \"will fail\".\n */\nexport const VENDOR_SIZE_WARN_BYTES = 150 * 1024 * 1024;\n\n/**\n * Where vendoring stops being an optimisation and becomes a bundle nobody can\n * deploy.\n *\n * Past this, shipping the tree anyway trades a faster cold start for a 413 — and\n * the 413 arrives at deploy time, after a build nobody watches, with a remedy\n * (`--no-vendor`) that requires knowing this happened. Unvendoring here costs\n * 40–60s of cold start and produces a bundle that uploads; that is the better\n * side of the trade to be on by default.\n *\n * 200 MB assumes a **2x** floor on compression, which is pessimistic for a tree\n * of JavaScript (3–5x is typical) and deliberately so: source maps and prebuilt\n * binaries compress far worse than source, and the failure this prevents is\n * asymmetric — a bundle refused at the door versus a minute of cold start.\n * `--vendor` overrides it, for a deploy path with no upload at all (a Dockerfile\n * built from source, where the tree is copied into an image and the control\n * plane never sees it).\n */\nexport const VENDOR_SIZE_MAX_BYTES = 200 * 1024 * 1024;\n\n/** Bytes on disk under `dir`. Bounded so a pathological tree cannot hang a build. */\nfunction directorySize(dir: string, budget = 200_000): number {\n let total = 0;\n let visited = 0;\n const stack = [dir];\n while (stack.length > 0 && visited < budget) {\n const current = stack.pop()!;\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(current, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const entry of entries) {\n visited++;\n const full = path.join(current, entry.name);\n if (entry.isDirectory()) {\n stack.push(full);\n } else if (entry.isFile()) {\n try {\n total += fs.statSync(full).size;\n } catch {\n // A file that vanished between readdir and stat contributes\n // nothing; it is not worth failing a build over.\n }\n }\n }\n }\n return total;\n}\n\n/**\n * Install the bundle's declared dependencies into the bundle itself.\n *\n * ## What this buys\n *\n * A managed pod's bundle lives on an `emptyDir`, so it is re-fetched and\n * re-installed on **every** start — an eviction, a node failure, an OOM, a\n * runtime rollout. The install is 35–55 seconds of a 40–60 second cold start,\n * which makes it the price of every unplanned restart a tenant suffers. Doing it\n * once at build time instead of every time at boot takes that to roughly the\n * cost of untarring.\n *\n * The pod side needs no change to benefit: the init container already skips\n * installing when `node_modules` is present, a guard that existed for\n * pre-baked images and turns out to be exactly the hook this needs.\n *\n * ## Why it refuses to vendor native code\n *\n * A compiled binary is valid only for the platform it was built for, and a\n * developer's machine is rarely the deployment's. The managed runtime already\n * refuses bundles containing native modules for the same reason, so this refusal\n * costs nothing there — but a self-hosted project may legitimately use them, and\n * for those the honest answer is to install in the container, where the platform\n * is known.\n *\n * ## Why `--os` and `--cpu` are not optional\n *\n * The dangerous case is not native code, which is detectable. It is a pure-JS\n * package whose real work lives in a **platform-specific optional dependency** —\n * `esbuild` being the one everybody meets. Installing on an Apple Silicon Mac\n * resolves `@esbuild/darwin-arm64`, produces a tree that looks complete, and\n * fails at import inside a linux/amd64 pod. npm resolves optional dependencies\n * for the declared target rather than the host when told to, so it is told to.\n */\nexport function vendorDependencies(options: {\n outDir: string;\n declared: Record<string, string>;\n nativeModules: NativeDependency[];\n /**\n * Packages the runtime resolves *from the bundle* and cannot boot without —\n * in practice the database driver, which the image deliberately does not\n * supply. A vendored tree missing one of these is refused; see below.\n */\n required?: string[];\n /** `false` disables; `undefined` means \"when it is safe to\". */\n requested?: boolean;\n /** Injected in tests. */\n run?: (cmd: string, args: string[], cwd: string) => void;\n}): VendorResult {\n if (options.requested === false) {\n return { vendored: false, skipped: \"disabled with --no-vendor\" };\n }\n if (Object.keys(options.declared).length === 0) {\n // Not a failure and not worth a warning: a project using only what the\n // runtime already provides installs nothing at boot either way.\n return { vendored: false, skipped: \"the bundle declares no dependencies\" };\n }\n if (options.nativeModules.length > 0) {\n const names = options.nativeModules.map(m => m.name).join(\", \");\n return {\n vendored: false,\n skipped:\n `the dependency closure contains native code (${names}), which is only valid on the ` +\n \"platform it was compiled for\"\n };\n }\n\n const target = {\n os: VENDOR_TARGET_OS,\n cpu: VENDOR_TARGET_CPU,\n node: process.versions.node.split(\".\")[0]\n };\n\n const run = options.run ?? ((cmd, args, cwd) => {\n const result = spawnSync(cmd, args, { cwd, stdio: \"pipe\", encoding: \"utf8\" });\n if (result.error) throw result.error;\n if (result.status !== 0) {\n throw new Error(\n `${cmd} ${args.join(\" \")} exited ${result.status}\\n${result.stderr || result.stdout || \"\"}`.trim()\n );\n }\n });\n\n try {\n run(\n \"npm\",\n [\n \"install\",\n \"--omit=dev\",\n // Matches what the runtime image's entrypoint insists on, and\n // what the init container passes. A bundle whose dependencies\n // ran lifecycle scripts at build time would arrive at the pod\n // carrying whatever they produced.\n \"--ignore-scripts\",\n \"--no-audit\",\n \"--no-fund\",\n `--os=${target.os}`,\n `--cpu=${target.cpu}`\n ],\n options.outDir\n );\n } catch (error: unknown) {\n // Never fatal. A bundle that could not be vendored is exactly the bundle\n // every project shipped before this existed — slower to start, entirely\n // functional — and failing the build over a speed optimisation would\n // trade a working deploy for a faster one that does not happen.\n return {\n vendored: false,\n skipped: `npm install failed: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n\n const installed = path.join(options.outDir, \"node_modules\");\n if (!fs.existsSync(installed)) {\n return { vendored: false, skipped: \"npm install produced no node_modules\" };\n }\n\n // An *incomplete* vendored tree is worse than none, because of the very\n // guard that makes vendoring free: the init container skips installing when\n // `node_modules` is present. So a tree missing the database driver does not\n // start slowly — it does not start at all, with the boot dying on\n // `Cannot find package \"@rebasepro/server-postgres\"`, and the step that\n // would have installed it declining to run precisely because this directory\n // exists.\n //\n // A driver goes missing whenever the project declares it in a way the\n // registry cannot serve — `workspace:*` in a monorepo, a `link:` override —\n // since `collectDeclaredDependencies` drops exactly those. Such a project\n // could never deploy this bundle anyway; what it must not do is have a\n // *build-time* optimisation quietly remove its ability to boot from source.\n // Refusing leaves the bundle in the state every project shipped before\n // vendoring existed.\n const missing = (options.required ?? []).filter(name =>\n !fs.existsSync(path.join(installed, ...name.split(\"/\"), \"package.json\")));\n if (missing.length > 0) {\n fs.rmSync(installed, { recursive: true, force: true });\n fs.rmSync(path.join(options.outDir, \"package-lock.json\"), { force: true });\n return {\n vendored: false,\n skipped:\n `the installed tree is missing ${missing.join(\", \")}, which the runtime resolves from ` +\n \"the bundle — the bundle declares it at a version no registry can serve (a workspace \" +\n \"link), so nothing was vendored rather than shipping a tree that boots without a driver\"\n };\n }\n\n const bytes = directorySize(installed);\n if (bytes > VENDOR_SIZE_MAX_BYTES && options.requested !== true) {\n fs.rmSync(installed, { recursive: true, force: true });\n fs.rmSync(path.join(options.outDir, \"package-lock.json\"), { force: true });\n return {\n vendored: false,\n skipped:\n `the installed tree is ${Math.round(bytes / (1024 * 1024))} MB, past the point where the ` +\n \"upload can be expected to fit under the control plane's 100 MB limit — a bundle that \" +\n \"is refused at the door is worse than one that installs at boot. Pass --vendor to keep \" +\n \"it anyway (a deploy that builds from source never uploads the tree), or shrink the \" +\n \"declared dependencies\"\n };\n }\n\n return { vendored: true, target, bytes };\n}\n\n/**\n * Package a built static app (a `static` or bundled-`admin` app) into a bundle.\n *\n * A static bundle is the counterpart to a backend bundle: the same shape, the\n * same runtime image runs it, but its manifest says `mode: \"static\"` and it\n * carries only the built assets under `static/`. That is what lets a frontend or\n * admin app be its own deployable, scalable unit rather than something baked into\n * the backend container.\n *\n * `assetsDir` is the app's built output (e.g. `frontend/dist`), already produced\n * by its own build command. This copies it into the bundle and writes the\n * manifest — no compilation, no dependency closure (a static bundle installs\n * nothing at boot).\n */\n/**\n * Fold a built static app into a backend bundle, so one runtime serves both.\n *\n * ## Why this exists\n *\n * A managed tenant runs one pod, and `bootFromBundle` on the backend path already\n * knows how to serve a SPA — it looks for `entry.static` and mounts `serveSPA`\n * last, behind `REBASE_SERVE_STATIC`. What was missing was anything putting the\n * assets there.\n *\n * The consequence was not subtle. A project whose custom image served its website\n * at `/` and its API at `/api` — the shape the scaffolded template produces — lost\n * the website the moment it moved to the managed runtime: the API answered\n * perfectly and every page 404'd. Managed could not be a drop-in replacement for\n * custom while the frontend simply vanished.\n *\n * Folding restores parity with the container it replaces, which is the only\n * honest baseline. It is deliberately the FIRST implementation and not the last:\n * a static app on its own bucket behind a CDN is better for cache behaviour and\n * lets the frontend deploy independently. But that needs infrastructure that does\n * not exist yet, and \"your site is gone\" is not an acceptable state to leave a\n * project in while it gets built.\n *\n * The trade it makes, stated plainly: frontend and backend now deploy together\n * and the bundle carries the built assets. For a project that was shipping both\n * in one image already, that is exactly what it had.\n */\nexport function foldStaticIntoBundle(options: {\n /** The backend bundle directory, already written. */\n bundleDir: string;\n /** Directory of built frontend assets (the static app's `output`). */\n assetsDir: string;\n /** The app's name in `rebase.json`. Names its directory inside the bundle. */\n appName: string;\n /** Public base path this app is served under. Always a path, never a URL. */\n path: string;\n /** The one hostname this app answers on, when its manifest `path` names one. */\n host?: string;\n /** Serve `index.html` for unmatched paths under `path`. */\n spa: boolean;\n /** Where this app mounts the Rebase CMS, if it does. */\n cms?: string;\n}): { fileCount: number; dir: string } {\n const { bundleDir, assetsDir, appName, path: basePath, host, spa, cms } = options;\n const manifestPath = path.join(bundleDir, \"manifest.json\");\n if (!fs.existsSync(manifestPath)) {\n throw new Error(`No manifest at ${manifestPath} — build the backend bundle first.`);\n }\n if (!fs.existsSync(assetsDir)) {\n throw new Error(`No built assets at ${assetsDir}.`);\n }\n\n // Each app gets its own directory, and only its own is cleared. Folding used\n // to wipe `static/` wholesale and write a single `entry.static` string, so a\n // second app silently replaced the first — both in the tree and in the\n // manifest — and the bundle deployed looking complete.\n const dir = path.posix.join(\"static\", appName);\n const staticOut = path.join(bundleDir, \"static\", appName);\n fs.rmSync(staticOut, { recursive: true,\nforce: true });\n fs.mkdirSync(staticOut, { recursive: true });\n fs.cpSync(assetsDir, staticOut, { recursive: true });\n\n let fileCount = 0;\n const count = (target: string): void => {\n for (const entry of fs.readdirSync(target, { withFileTypes: true })) {\n if (entry.isDirectory()) count(path.join(target, entry.name));\n else fileCount++;\n }\n };\n count(staticOut);\n // After counting: `fileCount` is the app's files, not their siblings.\n precompressStaticAssets(staticOut);\n\n // Record it, because the runtime finds the assets through the manifest —\n // not by guessing a directory name.\n const manifest = JSON.parse(fs.readFileSync(manifestPath, \"utf8\")) as RebaseBundleManifest;\n const existing = (manifest.entry?.static ?? []).filter(entry => entry.dir !== dir);\n // Sorted into mount order rather than left in folding order, so the bundle\n // reads the way it is served whatever order its apps were folded in — a\n // refold of one app appends it after siblings it may have to outrank.\n manifest.entry = {\n ...manifest.entry,\n static: [...existing, { path: basePath,\n...(host ? { host } : {}),\ndir,\nspa,\nname: appName,\n...(cms ? { cms } : {}) }].sort(compareMountOrder)\n };\n fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\\n`, \"utf8\");\n\n return { fileCount,\ndir };\n}\n\nexport function buildStaticBundle(options: {\n projectRoot: string;\n appName: string;\n assetsDir: string;\n outDir: string;\n runtimeRange: string;\n /** Public base path. Default `/` — a standalone bundle owns its origin. Always a path. */\n path?: string;\n /** The one hostname this app answers on, when its manifest `path` names one. */\n host?: string;\n /** Serve `index.html` for unmatched paths. Default `true`. */\n spa?: boolean;\n /** Where this app mounts the Rebase CMS, if it does. */\n cms?: string;\n}): { outDir: string; manifest: RebaseBundleManifest; fileCount: number } {\n const { projectRoot, appName, assetsDir, outDir, runtimeRange } = options;\n const basePath = options.path ?? \"/\";\n\n cleanOutDir(projectRoot, outDir);\n\n const staticOut = path.join(outDir, \"static\");\n fs.mkdirSync(staticOut, { recursive: true });\n fs.cpSync(assetsDir, staticOut, { recursive: true });\n\n let fileCount = 0;\n const count = (dir: string): void => {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) count(path.join(dir, entry.name));\n else fileCount++;\n }\n };\n count(staticOut);\n precompressStaticAssets(staticOut);\n\n const manifest: RebaseBundleManifest = {\n bundleFormat: BUNDLE_FORMAT_VERSION,\n runtime: {\n range: runtimeRange,\n builtAgainst: resolveServerVersion(projectRoot),\n contract: RUNTIME_CONTRACT_VERSION\n },\n // A static app has no collections and therefore no schema contract.\n schemaVersion: \"\",\n app: appName,\n kind: \"static\",\n // Normally `/` — a standalone bundle owns its origin. It carries the\n // app's declared path rather than hardcoding one so that the bundle\n // agrees with what the assets were actually *built* for; serving a\n // `/admin`-built app at `/` is the blank-page failure in reverse. Its\n // hostname travels too: this bundle is all the control plane sees of\n // the app, and the hostname is what it registers on the project.\n entry: { static: [{ path: basePath,\n...(options.host ? { host: options.host } : {}),\ndir: \"static\",\nspa: options.spa ?? true,\nname: appName,\n...(options.cms ? { cms: options.cms } : {}) }] },\n hooks: { native: false },\n // Nothing to install beside a static bundle — it is just files.\n deps: { declared: {} },\n build: {\n cli: cliVersion(),\n node: process.versions.node.split(\".\")[0],\n createdAt: new Date().toISOString()\n }\n };\n\n fs.writeFileSync(\n path.join(outDir, \"manifest.json\"),\n `${JSON.stringify(manifest, null, 2)}\\n`,\n \"utf8\"\n );\n // An empty package.json keeps the runtime's boot-time install a clean no-op.\n fs.writeFileSync(\n path.join(outDir, \"package.json\"),\n `${JSON.stringify({ name: \"rebase-bundle\",\nprivate: true,\ntype: \"module\",\ndependencies: {} }, null, 2)}\\n`,\n \"utf8\"\n );\n\n return { outDir,\nmanifest,\nfileCount };\n}\n\n/**\n * Which files in a collections directory are collections.\n *\n * Mirrors the runtime loader's rules exactly, and must keep mirroring them: the\n * set of files counted here decides the schema version, and the runtime decides\n * what it serves the same way. A divergence would show up as a client that is\n * permanently \"out of date\" against a server that agrees with it.\n *\n * (`._*` guards macOS AppleDouble files, which look like sources and are not.)\n */\nfunction isCollectionSourceFile(name: string): boolean {\n if (name.startsWith(\".\")) return false;\n if (name.includes(\".test.\") || name.includes(\".spec.\")) return false;\n if (name.endsWith(\".d.ts\")) return false;\n if (name === \"index.ts\" || name === \"index.js\") return false;\n return name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Load collections from **source**, for hashing and for the manifest's slug list.\n *\n * Deliberately not the compiled output. A compiled bundle imports its\n * dependencies from beside itself — that is the whole point of shipping a\n * `package.json` with it — but at build time nothing has been installed there\n * yet, and under pnpm the project's own `node_modules` lives one directory per\n * package, so the emitted files genuinely cannot resolve their imports until\n * they are deployed.\n *\n * Reading source costs nothing in fidelity: compilation erases types, it does\n * not change the values a collection module exports, so the hash is the same\n * either way.\n */\nasync function loadSourceCollections(collectionsDir: string): Promise<CollectionConfig[]> {\n if (!fs.existsSync(collectionsDir)) return [];\n\n const { createJiti } = await import(\"jiti\") as {\n createJiti: (filename: string, options?: Record<string, unknown>) => {\n import: (id: string) => Promise<unknown>;\n };\n };\n const jiti = createJiti(path.join(collectionsDir, \"index.ts\"), {\n interopDefault: true,\n esmResolve: true\n });\n\n const files = fs.readdirSync(collectionsDir)\n .filter(isCollectionSourceFile)\n .sort();\n\n const collections: CollectionConfig[] = [];\n const failures: string[] = [];\n\n for (const file of files) {\n try {\n const mod = await jiti.import(path.join(collectionsDir, file)) as\n { default?: CollectionConfig } | CollectionConfig;\n const collection = (mod as { default?: CollectionConfig }).default\n ?? (mod as CollectionConfig);\n if (collection && typeof collection === \"object\" && \"slug\" in collection) {\n collections.push(collection);\n } else {\n failures.push(`${file}: no default-exported collection`);\n }\n } catch (err) {\n failures.push(`${file}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n if (failures.length > 0) {\n throw new Error(\n `Could not read ${failures.length} collection file(s):\\n` +\n failures.map(f => ` • ${f}`).join(\"\\n\")\n );\n }\n\n return collections;\n}\n\n/** The `@rebasepro/server` version the project resolves — what it was built against. */\nfunction resolveServerVersion(projectRoot: string): string {\n const candidates = [\n path.join(projectRoot, \"node_modules\", \"@rebasepro\", \"server\", \"package.json\"),\n path.join(projectRoot, \"backend\", \"node_modules\", \"@rebasepro\", \"server\", \"package.json\")\n ];\n for (const candidate of candidates) {\n if (!fs.existsSync(candidate)) continue;\n try {\n return (JSON.parse(fs.readFileSync(candidate, \"utf8\")) as { version: string }).version;\n } catch {\n // fall through\n }\n }\n return \"unknown\";\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"context-BM-oOMNX.js","names":[],"sources":["../src/commands/cloud/errors.ts","../src/commands/cloud/context.ts"],"sourcesContent":["/**\n * Turning a control-plane failure into something the caller can act on.\n *\n * The control plane talks to Kubernetes, and when Kubernetes refuses it, the\n * refusal travels back verbatim: a whole `Status` object, the request headers,\n * an `audit-id`, an `x-kubernetes-pf-flowschema-uid`. That reached the user's\n * terminal unedited. Two things are wrong with it beyond the noise.\n *\n * The first is that the one sentence that matters is buried in the middle of a\n * JSON blob, so the remedy — if there is one — is the hardest part to find.\n *\n * The second is worse, and is the reason this file exists rather than a\n * `slice(0, 200)`. A `403` naming a `system:serviceaccount:` is a statement\n * about the PLATFORM's own credentials: some role the control plane runs as is\n * missing a grant. Nothing in the user's project can change that — not the\n * collections, not `rebase.json`, not the deploy flags — and the error, printed\n * raw in the middle of `rebase cloud deploy`, reads exactly like a project\n * fault. Someone acting on that reading deletes working code looking for the\n * cause. (That is not hypothetical: three cron jobs were removed from a project\n * to test whether they caused a `cronjobs.batch` 403. They did not.)\n *\n * So this classifies before it summarises, and says whose problem it is.\n */\n\nimport { parseEnvBoolean } from \"@rebasepro/types\";\n\n/** What a Kubernetes API refusal carries, once it is found. */\nexport interface KubernetesStatus {\n message?: string;\n reason?: string;\n code?: number;\n details?: { group?: string; kind?: string; name?: string };\n}\n\nexport interface ErrorSummary {\n /** One line, safe to print. Never the raw body. */\n message: string;\n /** A remedy, when one exists — or the reason there is none. */\n hint?: string;\n /** A stable code for `--json` callers to branch on. */\n code: string;\n /**\n * Whether the failure is the platform's rather than the project's.\n *\n * The whole point of the summary: a caller that retries or mutates the\n * project on a platform-side refusal makes things worse, and an agent\n * cannot tell from the prose.\n */\n platform: boolean;\n /** The untouched original, printed only under `--debug`. */\n raw: string;\n}\n\n/**\n * The service accounts a Kubernetes 403 can name, and what each means.\n *\n * `system:serviceaccount:` is the platform's own identity — the control plane's\n * pod, or a tenant's operator. A project cannot grant it anything, because the\n * grant lives in a cluster the project does not own. `system:anonymous` is the\n * same fact with the credential missing entirely.\n */\nconst PLATFORM_PRINCIPAL_RE = /system:(?:serviceaccount:|anonymous|node:)/;\n\n/**\n * A Kubernetes `Status` object embedded anywhere in a message.\n *\n * Scanned for rather than parsed off the front: the control plane wraps it\n * (\"Failed to create the tenant namespace: …\"), the client library appends\n * headers after it, and both halves are worth keeping out of the summary.\n * Balanced-brace scanning rather than a regex, because `details.causes` nests\n * and a lazy `\\{.*?\\}` truncates the object at the first inner brace — which\n * parses to nothing and silently falls through to the raw message.\n */\nexport function extractKubernetesStatus(text: string): KubernetesStatus | undefined {\n for (let start = text.indexOf(\"{\"); start !== -1; start = text.indexOf(\"{\", start + 1)) {\n let depth = 0;\n let inString = false;\n let escaped = false;\n for (let i = start; i < text.length; i++) {\n const ch = text[i];\n if (escaped) {\n escaped = false;\n continue;\n }\n if (ch === \"\\\\\") {\n escaped = true;\n continue;\n }\n if (ch === '\"') {\n inString = !inString;\n continue;\n }\n if (inString) continue;\n if (ch === \"{\") depth++;\n else if (ch === \"}\") {\n depth--;\n if (depth !== 0) continue;\n const candidate = text.slice(start, i + 1);\n let parsed: unknown;\n try {\n parsed = JSON.parse(candidate);\n } catch {\n break; // Not JSON; try the next opening brace.\n }\n const obj = parsed as Record<string, unknown> & KubernetesStatus;\n // `kind: \"Status\"` is the marker the API server always sets on a\n // refusal. Requiring it means an ordinary JSON body in an error\n // message — a validation report, say — is left alone.\n if (obj?.kind === \"Status\" || (obj?.status === \"Failure\" && typeof obj.code === \"number\")) {\n return {\n message: typeof obj.message === \"string\" ? obj.message : undefined,\n reason: typeof obj.reason === \"string\" ? obj.reason : undefined,\n code: typeof obj.code === \"number\" ? obj.code : undefined,\n details: (obj.details as KubernetesStatus[\"details\"]) ?? undefined\n };\n }\n break;\n }\n }\n }\n return undefined;\n}\n\n/**\n * Strip the transport noise a Kubernetes client appends to its own message.\n *\n * Only ever applied to the fallback path — when no `Status` was found, the\n * message is all there is, and cutting it at the first header keeps the\n * sentence while dropping the `audit-id` and the flowschema uid nobody outside\n * the cluster can use.\n */\nfunction trimTransportNoise(message: string): string {\n const cut = message.search(\n /\\s*(?:headers:|HTTP request failed|audit-id|x-kubernetes-pf-|\\{\"kind\":\"Status\")/i\n );\n const trimmed = (cut > 0 ? message.slice(0, cut) : message).trim();\n return trimmed.replace(/[\\s:,-]+$/, \"\");\n}\n\n/** The longest a summary may be before it stops being one. */\nconst MAX_SUMMARY = 300;\n\n/**\n * One actionable line (plus a hint) from whatever the control plane returned.\n *\n * `status` is the HTTP status of the control-plane call itself, which is a\n * different number from the `code` inside an embedded Kubernetes `Status` — the\n * control plane routinely answers 500 while the cluster answered 403, and it is\n * the inner one that says what happened.\n */\nexport function summarizeError(error: unknown, context: string): ErrorSummary {\n const err = error as { status?: number; message?: string; code?: string };\n const raw = err?.message ?? String(error);\n const k8s = extractKubernetesStatus(raw);\n\n if (k8s) {\n const inner = k8s.message?.trim() ?? \"\";\n const forbidden = k8s.code === 403 || k8s.reason === \"Forbidden\";\n const platform = forbidden && PLATFORM_PRINCIPAL_RE.test(inner);\n\n if (platform) {\n return {\n // Named as the platform's before the sentence that follows, so\n // the first thing read is whose problem it is.\n message: `${context}: the platform's own cluster credentials were refused by Kubernetes.`,\n hint:\n `${truncate(inner)}\\n`\n + \" This is a platform-side permission, not something your project can grant. \"\n + \"Nothing in your code, collections or deploy flags will change it — \"\n + \"report it with the message above rather than retrying or changing the project.\",\n code: \"platform_permission_denied\",\n platform: true,\n raw\n };\n }\n\n return {\n message: `${context}: ${truncate(inner || k8s.reason || \"the cluster refused the request\")}`,\n hint: k8s.code ? `Kubernetes answered ${k8s.code}${k8s.reason ? ` (${k8s.reason})` : \"\"}.` : undefined,\n code: k8s.reason ? `k8s_${k8s.reason.toLowerCase()}` : \"k8s_error\",\n platform: false,\n raw\n };\n }\n\n // Not a Kubernetes refusal. Still worth trimming: the same transport dumps\n // its headers onto plenty of errors that carry no `Status` at all.\n const trimmed = trimTransportNoise(raw);\n return {\n message: `${context}${err?.status ? ` (${err.status})` : \"\"}: ${truncate(trimmed || raw)}`,\n code: err?.code ?? (err?.status ? `http_${err.status}` : \"request_failed\"),\n platform: false,\n raw\n };\n}\n\nfunction truncate(text: string): string {\n const flat = text.replace(/\\s+/g, \" \").trim();\n return flat.length > MAX_SUMMARY ? `${flat.slice(0, MAX_SUMMARY - 1)}…` : flat;\n}\n\n/**\n * Whether the caller asked for the untouched body.\n *\n * `--debug` is already what `bin/rebase.js` prints after every failure as the\n * thing to add, so the raw payload hangs off the flag people are told to reach\n * for rather than off one invented here.\n *\n * The one reader of `REBASE_DEBUG` in the commands, spelled as the bin spells\n * it. It used to be `=== \"1\"` here while the quote fallbacks in `resources.ts`\n * tested the raw string for truthiness, so `=true` hid the body and `=0`\n * printed the fallback.\n */\nexport function wantsRawError(argv: readonly string[] = process.argv): boolean {\n return argv.includes(\"--debug\") || parseEnvBoolean(process.env.REBASE_DEBUG) === true;\n}\n","/**\n * Shared foundation for the `rebase cloud` command family.\n *\n * Everything cloud subcommands need in common lives here:\n * - credential storage (~/.rebase/credentials.json, keyed per control-plane host)\n * - project link file (.rebase/cloud.json in the project dir)\n * - control-plane URL resolution\n * - an authenticated `@rebasepro/client` instance (createCloudClient / requireClient)\n * - small output helpers shared across subcommands\n *\n * The control plane is itself a Rebase app, so we reuse the same SDK the web\n * console uses (`@rebasepro/client`). Auth, token refresh, the data REST client\n * and function invocation all come from the SDK — the CLI only supplies a\n * file-backed AuthStorage so a login persists across invocations.\n */\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport { spawn } from \"child_process\";\nimport chalk from \"chalk\";\nimport arg from \"arg\";\nimport inquirer from \"inquirer\";\nimport { createMemoryStorage, createRebaseClient, type AuthStorage } from \"@rebasepro/client\";\nimport { findProjectRoot } from \"../../utils/project\";\nimport { parseCommandArgs } from \"../../utils/args\";\nimport { cliUserAgent } from \"../../utils/version\";\nimport { summarizeError, wantsRawError } from \"./errors\";\nimport { parseEnvBoolean } from \"@rebasepro/types\";\n\n/* ═══════════════════════════════════════════════════════════════\n Constants & paths\n ═══════════════════════════════════════════════════════════════ */\n\n/** Default hosted control plane (the Rebase Cloud console origin). */\nconst DEFAULT_CLOUD_URL = \"https://app.rebase.pro\";\n\n/** The storage key the SDK's auth module reads/writes the session under. */\nconst SDK_SESSION_KEY = \"rebase_auth\";\n\n/** ~/.rebase/credentials.json — one file, many hosts. */\nfunction credentialsPath(): string {\n return path.join(os.homedir(), \".rebase\", \"credentials.json\");\n}\n\n/** Project-local link file: <project>/.rebase/cloud.json */\n/**\n * The billing account an organization row points at, whichever key it arrived under.\n *\n * REST serves every column under its own property name, so the relation comes\n * back as `billingAccountId`. Both readers in this CLI checked\n * `billing_account_id` and `billingAccount` — neither is what arrives — so\n * `rebase cloud billing` answered \"no billing account\" for every organization,\n * and the deploy pre-check never saw an internal plan. The other two spellings\n * are still accepted: older servers and fixtures send them.\n */\nexport function billingAccountIdOf(org: unknown): string | number | undefined {\n if (typeof org !== \"object\" || org === null) return undefined;\n for (const key of [\"billingAccountId\", \"billing_account_id\", \"billingAccount\"]) {\n const value = (org as Record<string, unknown>)[key];\n if (typeof value === \"string\" || typeof value === \"number\") return value;\n }\n return undefined;\n}\n\nexport function projectLinkPath(cwd: string = process.cwd()): string {\n const root = findProjectRoot(cwd) || cwd;\n return path.join(root, \".rebase\", \"cloud.json\");\n}\n\n/* ═══════════════════════════════════════════════════════════════\n Credentials file model\n ═══════════════════════════════════════════════════════════════\n\n {\n \"current\": \"https://app.rebase.pro\",\n \"contexts\": {\n \"https://app.rebase.pro\": { \"auth\": \"<sdk session json>\", \"org\": \"42\" }\n }\n }\n*/\n\ninterface CloudContextEntry {\n /** Raw JSON blob the SDK auth module persists (the RebaseSession). */\n auth?: string;\n /** Active organization id for this host, if the user selected one. */\n org?: string;\n}\n\ninterface CredentialsFile {\n current?: string;\n contexts: Record<string, CloudContextEntry>;\n}\n\nfunction readCredentials(): CredentialsFile {\n try {\n const raw = fs.readFileSync(credentialsPath(), \"utf-8\");\n const parsed = JSON.parse(raw) as CredentialsFile;\n if (!parsed.contexts) parsed.contexts = {};\n return parsed;\n } catch {\n return { contexts: {} };\n }\n}\n\nfunction writeCredentials(data: CredentialsFile): void {\n const file = credentialsPath();\n fs.mkdirSync(path.dirname(file), { recursive: true });\n // Written with private perms — this file holds refresh tokens.\n fs.writeFileSync(file, JSON.stringify(data, null, 2), { mode: 0o600 });\n try {\n fs.chmodSync(file, 0o600);\n } catch {\n // best effort on platforms without chmod semantics\n }\n}\n\n/** Host that a bare `rebase cloud` command should target, if any. */\nfunction currentContextUrl(): string | undefined {\n return readCredentials().current;\n}\n\n/** Persist the active organization id for a host. */\nexport function setContextOrg(url: string, org: string | undefined): void {\n const creds = readCredentials();\n const entry = creds.contexts[url] || {};\n if (org) entry.org = org;\n else delete entry.org;\n creds.contexts[url] = entry;\n writeCredentials(creds);\n}\n\nexport function getContextOrg(url: string): string | undefined {\n return readCredentials().contexts[url]?.org;\n}\n\n/* ═══════════════════════════════════════════════════════════════\n File-backed AuthStorage (per host)\n ═══════════════════════════════════════════════════════════════ */\n\nfunction createFileAuthStorage(url: string): AuthStorage {\n return {\n getItem(key) {\n if (key !== SDK_SESSION_KEY) return null;\n return readCredentials().contexts[url]?.auth ?? null;\n },\n setItem(key, value) {\n if (key !== SDK_SESSION_KEY) return;\n const creds = readCredentials();\n const entry = creds.contexts[url] || {};\n entry.auth = value;\n creds.contexts[url] = entry;\n if (!creds.current) creds.current = url;\n writeCredentials(creds);\n },\n removeItem(key) {\n if (key !== SDK_SESSION_KEY) return;\n const creds = readCredentials();\n if (creds.contexts[url]) {\n delete creds.contexts[url].auth;\n delete creds.contexts[url].org;\n }\n writeCredentials(creds);\n }\n };\n}\n\n/** Mark a host as the active context (called on login). */\nexport function setCurrentContext(url: string): void {\n const creds = readCredentials();\n creds.current = url;\n if (!creds.contexts[url]) creds.contexts[url] = {};\n writeCredentials(creds);\n}\n\n/* ═══════════════════════════════════════════════════════════════\n URL resolution\n ═══════════════════════════════════════════════════════════════\n\n Priority: --url flag > REBASE_CLOUD_URL env > CLOUD link's url\n > stored current context > default hosted URL.\n\n A **direct** link is deliberately absent from that list; see below.\n*/\n\n/**\n * Where the control-plane URL came from. `link` is the one a repository chose\n * rather than the user — see {@link isKnownControlPlane}.\n */\nexport type CloudUrlSource = \"flag\" | \"env\" | \"link\" | \"context\" | \"default\";\n\nexport function resolveCloudUrl(rawArgs: string[]): string {\n return resolveCloudTarget(rawArgs).url;\n}\n\n/** The control-plane URL, and which rung of the ladder above supplied it. */\nexport function resolveCloudTarget(rawArgs: string[]): { url: string; source: CloudUrlSource } {\n const parsed = arg({ \"--url\": String }, { argv: rawArgs.slice(2),\npermissive: true });\n if (parsed[\"--url\"]) return { url: normalizeUrl(parsed[\"--url\"]),\nsource: \"flag\" };\n if (process.env.REBASE_CLOUD_URL) return { url: normalizeUrl(process.env.REBASE_CLOUD_URL),\nsource: \"env\" };\n\n const link = readLink();\n /*\n * A direct link is a tenant, not a control plane.\n *\n * `rebase cloud link <url>` points this checkout at ONE running Rebase API\n * — \"no control plane, no login\", as its own help page puts it — so its URL\n * is the customer's own backend. Returning it here made it the control\n * plane for the entire `cloud` family: `whoami` reported \"Not logged in to\n * https://api.example.com\", and following that printed remedy POSTed the\n * user's *control-plane* email and password to the tenant host.\n *\n * Commands that genuinely need a control plane refuse instead — see\n * `refuseDirectLink`, which every one of them reaches through\n * `requireClient` (and `login`, which builds its client directly).\n */\n if (link?.url && link.mode !== \"direct\") return { url: normalizeUrl(link.url),\nsource: \"link\" };\n\n const current = currentContextUrl();\n if (current) return { url: normalizeUrl(current),\nsource: \"context\" };\n\n return { url: DEFAULT_CLOUD_URL,\nsource: \"default\" };\n}\n\n/**\n * Whether a control-plane host is one the user chose: the platform's own, or a\n * host already in their credentials file because they signed in to it.\n *\n * A link file is part of the repository, and a cloned repository is not the\n * user's to trust with their password. `login` asks before sending one to a\n * linked host that is neither.\n */\nexport function isKnownControlPlane(url: string): boolean {\n return url === DEFAULT_CLOUD_URL || Object.hasOwn(readCredentials().contexts, url);\n}\n\n/**\n * Refuse to run a control-plane command in a directory linked straight at a\n * backend.\n *\n * The alternative — quietly using the default control plane — would be worse\n * than the bug it replaces: the user asked for `https://api.example.com` and\n * would get an answer about `app.rebase.pro` with nothing saying so. Naming the\n * link, and both ways out of it, is the whole message.\n *\n * `--project` and `--url` are the ways out, so a line carrying either passes\n * through: both say, explicitly, which control-plane subject the caller means.\n */\nexport function refuseDirectLink(rawArgs: string[]): void {\n const link = readLink();\n if (link?.mode !== \"direct\") return;\n\n const parsed = arg(\n { \"--project\": String,\n\"-p\": \"--project\",\n\"--url\": String },\n { argv: rawArgs.slice(2),\npermissive: true }\n );\n if (parsed[\"--project\"] || parsed[\"--url\"]) return;\n\n fail(\n `This directory is linked directly to ${chalk.cyan(link.url)} — `\n + `${chalk.bold(\"rebase cloud unlink\")} first, or pass ${chalk.bold(\"--project\")}.`,\n \"A direct link is one backend, not a control plane: it has no projects, no organizations and no session.\",\n \"direct_link\"\n );\n}\n\nfunction normalizeUrl(url: string): string {\n let u = url.trim().replace(/\\/+$/, \"\");\n if (!/^https?:\\/\\//.test(u)) u = `https://${u}`;\n return u;\n}\n\n/* ═══════════════════════════════════════════════════════════════\n Rebase client factory + auth guard\n ═══════════════════════════════════════════════════════════════ */\n\nexport type CloudClient = ReturnType<typeof createRebaseClient>;\n\n/**\n * Build an SDK client bound to a control-plane host, backed by the on-disk\n * credential store. `autoRefresh` is disabled so we never leave a dangling\n * setTimeout that keeps the CLI process alive; token refresh is done on demand\n * by `requireClient`.\n */\nexport function createCloudClient(url: string): CloudClient {\n return createRebaseClient({\n baseUrl: url,\n // No cloud subcommand needs a socket. The one that looks like it might —\n // `logs -f` — polls `deployments.findById` on a timer (see\n // `streamBuildLogs`), so nothing here ever opens a channel or an\n // `observe()`.\n //\n // This used to say `websocketUrl: \"\"` and mean the same thing. It stopped\n // meaning it when the client grew a diagnostic for the case it produces:\n // realtime is on unless you switch it off, so \"on, with no usable URL\"\n // reads as a misconfiguration and warns. The warning is right — and it\n // was firing on every single `rebase cloud` invocation, telling the user\n // to fix the CLI's own client construction, in prose they had no way to\n // act on. `realtime: false` is the escape it names: it is the difference\n // between \"no socket, because I never asked for one\" and \"no socket, and\n // I do not know why\".\n realtime: false,\n // Every control-plane request says which CLI is calling. The control\n // plane's wire format moves ahead of what is published to npm, so it\n // has to be able to answer an old client with `CLI_TOO_OLD` and the\n // minimum version — and it cannot do that for a caller that never\n // identified itself. Until this line, none of them did.\n headers: { \"User-Agent\": cliUserAgent() },\n auth: {\n storage: createFileAuthStorage(url),\n persistSession: true,\n autoRefresh: false\n }\n });\n}\n\n/**\n * The environment variable that authenticates the cloud family with a token\n * instead of a `cloud login` session — for CI and agents, which have no\n * terminal to log in at and should not hold a person's password.\n */\nexport const TOKEN_ENV = \"REBASE_TOKEN\";\n\n/** `REBASE_TOKEN`, trimmed, or undefined when it is unset or blank. */\nexport function envToken(): string | undefined {\n const value = process.env[TOKEN_ENV]?.trim();\n return value ? value : undefined;\n}\n\n/** The token each token-authenticated client was built with — see {@link freshAccessToken}. */\nconst STATIC_TOKENS = new WeakMap<object, string>();\n\n/**\n * A client that sends `token` as its bearer and nothing else.\n *\n * No session: the token is not refreshed, and the credentials file is neither\n * read nor written — a CI job's token must not become, or replace, the login\n * of whoever owns the machine. A 401 is answered by {@link explainRefusedToken}\n * rather than by the SDK's session refresh, because there is no session to\n * refresh and \"log in again\" is the wrong remedy for a token.\n */\nexport function createTokenClient(url: string, token: string): CloudClient {\n const client = createRebaseClient({\n baseUrl: url,\n realtime: false,\n headers: { \"User-Agent\": cliUserAgent() },\n token,\n auth: {\n storage: createMemoryStorage(),\n persistSession: false,\n autoRefresh: false\n }\n });\n client.setOnUnauthorized(() => explainRefusedToken(url, token));\n STATIC_TOKENS.set(client, token);\n return client;\n}\n\n/**\n * Why the control plane answered a token-authenticated request with 401, and\n * what to do about it. Never returns.\n *\n * Two different causes reach the same status. Usually the token itself was\n * refused — it expired, was revoked, or belongs to another control plane — and\n * the remedy is a new token. But a few endpoints take only a person's session\n * (`/auth/me` among them), and those refuse a perfectly good token too. One\n * request to `/api/auth/scopes`, which accepts a token, tells the two apart, so\n * neither is answered with the other's remedy.\n */\nasync function explainRefusedToken(url: string, token: string): Promise<never> {\n let tokenAccepted = false;\n try {\n const probe = await fetch(`${url}/api/auth/scopes`, {\n headers: { Authorization: `Bearer ${token}`, \"User-Agent\": cliUserAgent() }\n });\n tokenAccepted = probe.ok;\n } catch {\n // Unreachable: say what is certain — the request was refused.\n }\n if (tokenAccepted) {\n fail(\n `This command needs a signed-in session, and ${TOKEN_ENV} is an API token.`,\n `Unset ${TOKEN_ENV} and run ${chalk.bold(\"rebase cloud login\")} to run it.`,\n \"session_required\"\n );\n }\n fail(\n `${TOKEN_ENV} was rejected by ${url}: it has expired, been revoked, or was not issued by this control plane.`,\n `Create a new one with ${chalk.bold(\"rebase cloud tokens create\")} and put it in ${TOKEN_ENV}.`,\n \"token_rejected\"\n );\n}\n\n/** Two minutes of head-room before a token is treated as expired. */\nconst EXPIRY_BUFFER_MS = 120_000;\n\n/** The half of a client that holds its session — all {@link freshAccessToken} reads. */\nexport interface SessionHolder {\n auth: {\n getSession(): { accessToken: string; expiresAt: number } | null;\n refreshSession(): Promise<{ accessToken: string }>;\n };\n}\n\n/**\n * An access token with time left on it, refreshed first if it is close to\n * expiry. Rejects when there is no session, or it cannot be refreshed.\n *\n * For the requests the SDK does not make itself. Its own calls refresh and\n * retry on a 401; a raw `fetch` or a tunnel handshake presents whatever token\n * it was handed, and `createCloudClient` never refreshes in the background. A\n * token read once at the start of a command that runs for longer than it\n * lives — a deploy's build, a `db connect` left open — is refused by the time\n * it is used, so it is read here at the moment it is sent.\n *\n * A client built from `REBASE_TOKEN` has no session; its token is returned\n * as it is, since there is nothing to refresh it with.\n */\nexport async function freshAccessToken(client: SessionHolder): Promise<string> {\n const fixed = STATIC_TOKENS.get(client);\n if (fixed) return fixed;\n const session = client.auth.getSession();\n if (session?.accessToken && session.expiresAt > Date.now() + EXPIRY_BUFFER_MS) return session.accessToken;\n return (await client.auth.refreshSession()).accessToken;\n}\n\n/**\n * Return an authenticated client for the resolved host.\n *\n * With `REBASE_TOKEN` set, that token is the credential for every request and\n * the stored login is not consulted at all. Otherwise it is the `cloud login`\n * session — see {@link requireSessionClient}.\n */\nexport async function requireClient(rawArgs: string[]): Promise<{ client: CloudClient; url: string }> {\n const token = envToken();\n if (!token) return requireSessionClient(rawArgs);\n // Before anything else: everything downstream of here is a control-plane\n // call, and a direct-linked directory has no control plane to make it\n // against.\n refuseDirectLink(rawArgs);\n const url = resolveCloudUrl(rawArgs);\n return { client: createTokenClient(url, token), url };\n}\n\n/**\n * Return a client holding the `cloud login` session for the resolved host,\n * refreshing the access token if it is close to expiry, whether or not\n * `REBASE_TOKEN` is set. Exits with a helpful message when there is no usable\n * session (never logged in, or the refresh token was revoked).\n *\n * For the commands a token cannot run — minting and revoking tokens: a key that\n * could mint keys could mint its own successor, so the control plane refuses\n * every key on those routes.\n */\nexport async function requireSessionClient(rawArgs: string[]): Promise<{ client: CloudClient; url: string }> {\n // Before anything else: everything downstream of here is a control-plane\n // call, and a direct-linked directory has no control plane to make it\n // against.\n refuseDirectLink(rawArgs);\n const url = resolveCloudUrl(rawArgs);\n const client = createCloudClient(url);\n const session = client.auth.getSession();\n\n if (!session || !session.accessToken) {\n if (envToken()) {\n fail(\n `This command needs a signed-in session for ${chalk.cyan(url)}, and ${TOKEN_ENV} is an API token.`,\n `A token cannot manage tokens. Run ${chalk.bold(\"rebase cloud login\")} first.`,\n \"session_required\"\n );\n }\n fail(\n `Not logged in to ${chalk.cyan(url)}.`,\n `Run ${chalk.bold(\"rebase cloud login\")} first.`,\n \"not_logged_in\"\n );\n }\n\n if (session.expiresAt <= Date.now() + EXPIRY_BUFFER_MS) {\n try {\n await client.auth.refreshSession();\n } catch {\n fail(\n `Your session for ${chalk.cyan(url)} has expired.`,\n `Run ${chalk.bold(\"rebase cloud login\")} to sign in again.`,\n // Distinct from `not_logged_in`: a caller retrying on a stale\n // session should re-authenticate, not conclude it was never set\n // up. Same remedy, different diagnosis.\n \"session_expired\"\n );\n }\n }\n\n return { client,\nurl };\n}\n\n/* ═══════════════════════════════════════════════════════════════\n Platform configuration\n ═══════════════════════════════════════════════════════════════ */\n\n/** One place a deploy can actually land, as the control plane describes it. */\nexport interface DeployTarget {\n clusterId?: string | null;\n provider: string;\n region?: string;\n label?: string;\n baseDomain?: string;\n}\n\nexport interface PlatformConfig {\n tenantBaseDomain?: string;\n deployTargets?: DeployTarget[];\n}\n\n/**\n * The control plane's public, non-secret self-description (`platform-config`).\n *\n * None of it is knowable from the CLI side: it is per-deployment configuration —\n * production serves tenants at `rebase.website` on GKE, a dev control plane at\n * `localhost` on Docker. Guessing produced two separate lies: a congratulation\n * URL that resolved nowhere near the app, and a `provider` the project does not\n * run on (see `createProject`).\n *\n * Cached per host for the process: it is fixed for a control plane's lifetime,\n * and `projects list` formats one host per row off a single fetch.\n *\n * @returns the config, or `undefined` if the control plane doesn't serve\n * `platform-config` (an older deployment) or the request failed. A failure is\n * cached too — a short-lived CLI should not retry once per row. Note the\n * distinction callers rely on: `undefined` means \"this control plane cannot\n * tell us\", whereas `deployTargets: []` is a control plane stating that it has\n * no infrastructure configured.\n */\nconst platformConfigCache = new Map<string, Promise<PlatformConfig | undefined>>();\n\nexport function fetchPlatformConfig(client: CloudClient, url: string): Promise<PlatformConfig | undefined> {\n let pending = platformConfigCache.get(url);\n if (!pending) {\n pending = client.functions\n .invoke<PlatformConfig>(\"platform-config\", undefined, { method: \"GET\" })\n .then((cfg) => cfg ?? undefined)\n .catch(() => undefined);\n platformConfigCache.set(url, pending);\n }\n return pending;\n}\n\n/**\n * The base domain tenant projects are served at, derived from the same\n * TENANT_BASE_DOMAIN the ingress and the console read (see\n * saas/backend/src/utils/tenant-domain.ts).\n */\nexport function fetchTenantBaseDomain(client: CloudClient, url: string): Promise<string | undefined> {\n return fetchPlatformConfig(client, url).then((cfg) => cfg?.tenantBaseDomain?.trim() || undefined);\n}\n\n/**\n * The infrastructure a deploy for this control plane would ACTUALLY use, in the\n * resolver's own preference order (saas/backend/src/k8s/resolve.ts).\n *\n * @returns the targets, or `undefined` when the control plane cannot say.\n */\nexport function fetchDeployTargets(client: CloudClient, url: string): Promise<DeployTarget[] | undefined> {\n return fetchPlatformConfig(client, url).then((cfg) =>\n Array.isArray(cfg?.deployTargets) ? cfg.deployTargets : undefined\n );\n}\n\n/**\n * Public host for a project — `<subdomain>.<base>`, or the bare subdomain when\n * the base domain is unknown.\n *\n * It deliberately never falls back to a guessed domain. The user copies this\n * string into a browser, so a plausible-but-wrong hostname is worse than an\n * obviously incomplete one: `acme.rebase.pro` looks reachable and isn't, while\n * `acme` reads as \"the subdomain is acme\" and prompts no wasted debugging.\n */\nexport function formatTenantHost(\n subdomain: string | undefined,\n baseDomain: string | undefined\n): string | undefined {\n if (!subdomain) return undefined;\n return baseDomain ? `${subdomain}.${baseDomain}` : subdomain;\n}\n\n/** The fields of a project row this module needs to render a host. */\nexport interface HostableProject {\n subdomain?: string;\n /** Resolved server-side; absent on control planes older than the host hook. */\n host?: string;\n}\n\n/**\n * The host to display for a project.\n *\n * Prefers `host` off the record: the control plane resolves it through the same\n * `tenantHost()` the ingress uses, so it accounts for the project's *cluster*\n * base domain. The CLI cannot compute that itself — `clusters` is admin-only\n * under RLS, so a normal user's token cannot read `baseDomain`, and a project on\n * a second cluster is served somewhere the platform default does not name.\n *\n * `baseDomain` (from `platform-config`) remains the fallback for a control plane\n * that predates the hook — right for the single-cluster case, which is every\n * project today.\n */\nexport function projectHost(\n project: HostableProject,\n baseDomain: string | undefined\n): string | undefined {\n return project.host || formatTenantHost(project.subdomain, baseDomain);\n}\n\n/* ═══════════════════════════════════════════════════════════════\n Project link file (.rebase/cloud.json)\n ═══════════════════════════════════════════════════════════════ */\n\nexport interface ProjectLink {\n url: string;\n projectId: string;\n /** The project's subdomain — the slug users see in console URLs and type into --project. */\n slug?: string;\n projectName?: string;\n orgId?: string;\n /**\n * Base URL of the project's own API.\n *\n * For a cloud project this is a convenience derived from the subdomain. For\n * a **self-hosted** project it is the entire link: there is no control plane\n * to look anything up in, so `projectId` is empty and this is what commands\n * resolve against.\n *\n * Keeping both kinds of link in one file is deliberate. A second link file\n * for self-hosting would fork every command that reads one, and the tooling\n * would drift into being cloud-only by accident.\n */\n apiUrl?: string;\n /**\n * How this checkout is linked. Absent means `cloud` — which is every link\n * written before this field existed.\n */\n mode?: \"cloud\" | \"direct\";\n}\n\nexport function readLink(cwd: string = process.cwd()): ProjectLink | null {\n try {\n return JSON.parse(fs.readFileSync(projectLinkPath(cwd), \"utf-8\")) as ProjectLink;\n } catch {\n return null;\n }\n}\n\nexport function writeLink(link: ProjectLink, cwd: string = process.cwd()): void {\n const file = projectLinkPath(cwd);\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.writeFileSync(file, JSON.stringify(link, null, 2));\n}\n\nexport function removeLink(cwd: string = process.cwd()): boolean {\n const file = projectLinkPath(cwd);\n if (fs.existsSync(file)) {\n fs.rmSync(file);\n return true;\n }\n return false;\n}\n\n/**\n * Flags that may appear anywhere on a `rebase cloud` line, including *before*\n * the resource group.\n *\n * They have to be declared wherever positionals are resolved, because `arg`'s\n * `permissive: true` does not merely tolerate an undeclared flag — it pushes it\n * into `_` alongside the positionals, and for a flag that takes a value it\n * pushes the value in too. So `cloud --project acme storage create` parsed\n * without this spec yields `_` of `[\"--project\", \"acme\", \"storage\", \"create\"]`,\n * and the group reads as `\"acme\"`: a real project name, in the group position,\n * dispatching to nothing. Skipping tokens that start with `-` does not save you\n * there — the damage is the orphaned value, which looks exactly like a\n * positional.\n *\n * Only genuinely global flags belong here. Group-specific ones (`--bucket`,\n * `--region`, …) are declared by the handler that owns them. They can still\n * precede the action — or stand in for it, on a group with a default — so the\n * dispatcher also declares every one that takes a value: `CLOUD_VALUE_FLAGS`\n * in `index.ts`.\n *\n * `-p` is `--project` in eighteen places and `--password` in `login`. That\n * ambiguity does not matter to the one caller that reads this spec: it resolves\n * positionals and never looks at a flag's value, so all it needs to know is\n * that `-p` takes one. Anything that wants the value must keep declaring it\n * itself, with the meaning its own command gives it.\n */\nexport const GLOBAL_CLOUD_FLAGS = {\n \"--json\": Boolean,\n \"--yes\": Boolean,\n \"--help\": Boolean,\n \"--project\": String,\n /* `resolveCloudUrl` reads this off the raw line for EVERY command in the\n family — it is the first entry in the URL priority list — so a strict\n parse that did not declare it would reject a flag the CLI itself honours\n on the command being parsed. */\n \"--url\": String,\n \"-p\": \"--project\",\n \"-y\": \"--yes\",\n \"-h\": \"--help\"\n} as const;\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * The raw project reference to operate on: explicit `--project` flag wins,\n * otherwise the linked project. Exits with guidance when neither is present.\n * The value is a slug (the project's subdomain, as shown in console URLs) or,\n * for old scripts and link files, a raw project UUID.\n */\nexport function requireProjectRef(rawArgs: string[]): string {\n const parsed = arg({ \"--project\": String,\n\"-p\": \"--project\" }, { argv: rawArgs.slice(2),\npermissive: true });\n if (parsed[\"--project\"]) return parsed[\"--project\"];\n const link = readLink();\n if (link?.projectId) return link.projectId;\n fail(\n \"No project specified and this directory is not linked.\",\n `Pass ${chalk.bold(\"--project <slug>\")} or run ${chalk.bold(\"rebase cloud link\")}.`,\n \"no_project\"\n );\n}\n\n/**\n * Resolve a project reference — slug or UUID — to the internal id the API\n * takes, or undefined when no such project is visible. Slugs cost one lookup;\n * UUIDs pass through untouched so linked directories and old scripts skip the\n * round-trip.\n */\nexport async function lookupProjectId(ref: string, client: CloudClient): Promise<string | undefined> {\n if (UUID_RE.test(ref)) return ref;\n const res = await client.data.collection(\"projects\").find({\n where: { subdomain: [\"==\", ref] },\n limit: 1\n });\n const row = res.data[0] as { id?: string | number } | undefined;\n return row?.id === undefined ? undefined : String(row.id);\n}\n\n/** Like `lookupProjectId`, but exits with guidance when the ref matches nothing. */\nexport async function resolveProjectRef(ref: string, client: CloudClient): Promise<string> {\n const id = await lookupProjectId(ref, client);\n if (id === undefined) {\n fail(\n `No project with slug ${chalk.bold(ref)}.`,\n `List yours with ${chalk.bold(\"rebase cloud projects\")}.`,\n \"project_not_found\"\n );\n }\n return id;\n}\n\n/** `requireProjectRef` + `resolveProjectRef` in one step. */\nexport async function requireProject(rawArgs: string[], client: CloudClient): Promise<string> {\n return resolveProjectRef(requireProjectRef(rawArgs), client);\n}\n\n/**\n * The project reference to SHOW: the slug the user typed or the linked slug.\n * Never resolves — for human output only. Old link files predate `slug` and\n * fall back to the stored id.\n */\nexport function displayProjectRef(rawArgs: string[]): string {\n const parsed = arg({ \"--project\": String,\n\"-p\": \"--project\" }, { argv: rawArgs.slice(2),\npermissive: true });\n if (parsed[\"--project\"]) return parsed[\"--project\"];\n const link = readLink();\n return link?.slug || link?.projectId || \"\";\n}\n\n/* ═══════════════════════════════════════════════════════════════\n Machine-readable output mode\n ═══════════════════════════════════════════════════════════════\n\n Rebase is built for agents, and the CLI is their primary interface. An agent\n must never scrape a colorized table, so every cloud command can emit a single\n JSON value instead of human output.\n\n JSON mode is on when ANY of these hold:\n • `--json` was passed,\n • `REBASE_JSON=1` is set, or\n • stdout is not a TTY (piped/redirected — i.e. a program is reading it).\n\n In JSON mode a command prints exactly one JSON value to stdout and nothing\n else; errors print `{\"error\":{...}}` and exit non-zero. The mode is a\n process-global set once, at dispatch, by `initOutputMode` — every helper here\n (fail, reportError, emit) reads it so the whole family is consistent.\n\n ── The stream contract ─────────────────────────────────────────────────────\n\n The mode decides the SHAPE of the result. It does not decide which stream\n anything lands on; that rule is fixed and holds in both modes:\n\n stdout the command's result, and nothing else — one human rendering or\n one JSON value. A caller may redirect it into a parser.\n stderr everything that is not the result: progress, advice, warnings,\n errors, and the interactive prompts.\n\n Nothing is written to both. That is the whole rule, and it is worth stating\n because the family drifted off it in a way that reads as a bug in the report\n itself: a warning from the SDK went to stderr while the report went to\n stdout, so `whoami 2>&1` interleaved two unrelated voices and the header\n looked like it had been printed twice.\n\n The practical consequence for a new command: the ONLY things that may call\n `console.log` are inside an `emit` human closure. Progress and next-step\n advice go through `note`, cautions through `warn`, outcomes through\n `success` — all of which write to stderr. `keyValues` prints result rows and\n so stays on stdout, which is why it belongs inside the `emit` closure too.\n*/\n\nlet JSON_MODE = false;\n\n/**\n * Resolve and latch the output mode for this invocation. Call once at the top of\n * `cloudCommand`, before anything can print or `fail`. Returns the resolved mode\n * (handy for tests, which otherwise leave it at its `false` default).\n */\nexport function initOutputMode(rawArgs: string[]): boolean {\n const parsed = arg({ \"--json\": Boolean }, { argv: rawArgs.slice(2),\npermissive: true });\n // Most explicit wins. `REBASE_JSON=0` is the half that was missing: the\n // \"stdout is not a TTY\" rule is right for a result, and wrong for the reader\n // who ran `rebase cloud env --help | less` and got a JSON object. There was\n // no way to say so — `--json` could only turn the mode ON, and `REBASE_JSON`\n // was tested against \"1\" alone, so any other value including \"0\" fell\n // through to the TTY test and set it anyway. Any spelling of yes or no now\n // decides; only an unset or unrecognised value leaves it to the TTY.\n if (parsed[\"--json\"]) JSON_MODE = true;\n else JSON_MODE = parseEnvBoolean(process.env.REBASE_JSON) ?? process.stdout.isTTY !== true;\n return JSON_MODE;\n}\n\n/** Whether the current invocation is emitting machine-readable JSON. */\nexport function isJsonMode(): boolean {\n return JSON_MODE;\n}\n\n/** Force the mode (tests only — production latches it via `initOutputMode`). */\nexport function setJsonModeForTest(value: boolean): void {\n JSON_MODE = value;\n}\n\n/** Strip ANSI colour codes — JSON output must never carry terminal escapes. */\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\u001b\\[[0-9;]*m/g;\nfunction stripAnsi(s: string): string {\n return s.replace(ANSI_RE, \"\");\n}\n\n/**\n * Write one JSON value to stdout, followed by a newline.\n *\n * Indented, because the overwhelmingly common reader is a person or an agent\n * looking at a terminal — JSON mode is entered automatically whenever stdout is\n * not a TTY, so `rebase cloud deployments list` piped anywhere at all produced\n * a project's entire deployment history as one unwrapped line. `JSON.parse`\n * does not care about the whitespace; everything else does.\n */\nexport function printJson(value: unknown): void {\n process.stdout.write(JSON.stringify(value, null, 2) + \"\\n\");\n}\n\n/**\n * The one output primitive every new command uses: in JSON mode emit `json`\n * (and nothing else); otherwise run `human`. Keeping the two behind a single\n * call is what guarantees a command can never print a table AND a JSON blob.\n */\nexport function emit<T>(human: () => void, json: JsonArg<T>): void {\n if (JSON_MODE) printJson(json);\n else human();\n}\n\n/**\n * The JSON payload, which must be a value and not a producer of one.\n *\n * `json: unknown` accepted a function without complaint, and four call sites in\n * `resources.ts` passed `() => ({ … })` — mirroring the human argument beside\n * it, which *is* a thunk. In JSON mode `printJson` then stringified a function,\n * which is `undefined`. So `rebase cloud compute`, `compute set` and two\n * cluster commands printed the single word `undefined` on every piped or\n * `--json` run — and since this family forces JSON mode off a TTY, that is\n * every scripted use of them.\n *\n * Typed so the mistake cannot be made again: a function resolves the parameter\n * to `never`, and the call site fails to compile.\n */\nexport type JsonArg<T> = T extends (...args: never[]) => unknown ? never : T;\n\n/**\n * Print a help page — the human one, or a machine-readable description of the\n * same command in JSON mode.\n *\n * `--help` is the one place where \"stdout is not a TTY\" is a weak signal: a\n * person runs `rebase cloud db --help | less` and wants the page. But the rule\n * this family promises is that stdout carries one JSON value whenever it is not\n * a terminal, and a help page is the easiest possible thing to describe\n * structurally — so rather than carve out an exception, help answers the same\n * question in the reader's own language. For an agent, `--help` piped is then a\n * discovery call rather than 60 lines of ANSI to scrape.\n *\n * `env` shipped this shape first, alone; this generalises it so every group\n * answers the same way.\n */\nexport function emitHelp(\n command: string,\n actions: Array<string | HelpAction>,\n human: () => void,\n extra: Record<string, unknown> = {}\n): void {\n emit(human, { command,\nactions: actions.map(entry => describeAction(entry, command)),\n...extra });\n}\n\n/* ═══════════════════════════════════════════════════════════════\n Group help pages\n ═══════════════════════════════════════════════════════════════ */\n\n/**\n * One action on a group's help page.\n *\n * The page used to exist twice: a hand-formatted template literal for a\n * terminal, and a bare list of action WORDS for everything else. So the two\n * answers to `--help` were not the same answer — piped, `rebase cloud env\n * --help` said `[\"list\",\"set\",\"unset\",\"reveal\",\"pull\"]` and not one description,\n * not one flag, and not the sentence about build-time variables that is the\n * whole reason the page exists. This family forces JSON mode off a TTY, so that\n * was every scripted and every agent-driven read of it.\n *\n * One description, rendered twice.\n */\nexport interface HelpAction {\n /** The action word: `set`, `backup restore`. */\n action: string;\n /** The usage tail after the word: `KEY=VALUE`, `<domain>`, `[-y]`. */\n args?: string;\n /** One line: what it does. */\n description: string;\n /** Flags this action takes of its own, `[flag, description]`. */\n flags?: Array<[string, string]>;\n /** The heading it sits under, on a page that groups its actions. */\n section?: string;\n}\n\n/** A whole group page — `rebase cloud env --help`. */\nexport interface GroupHelp {\n /** The command words, no leading `rebase`: `cloud env`, or `cloud` itself. */\n command: string;\n /** The title's tail: \"Environment variables\". */\n title: string;\n actions: HelpAction[];\n /** Options that belong to the group rather than to one action. */\n options?: Array<[string, string]>;\n /** Closing paragraphs — the things a reader gets wrong more than once. */\n notes?: string[];\n}\n\n/**\n * Normalise an action for the JSON form. Strings stay legal — the index page\n * lists group names, which are not actions of the command being described.\n *\n * `command` is the page's own command (`cloud env`), so the usage line a caller\n * reads is a line it can run: without it the answer said `rebase cloud set\n * KEY=VALUE`, which is a command that does not exist.\n */\nfunction describeAction(entry: string | HelpAction, command: string): Record<string, unknown> {\n if (typeof entry === \"string\") return { action: entry,\ndescription: \"\",\nflags: [] };\n return {\n action: entry.action,\n usage: `rebase ${command} ${entry.action}${entry.args ? ` ${entry.args}` : \"\"}`,\n description: entry.description,\n flags: (entry.flags ?? []).map(([flag, description]) => ({ flag,\ndescription }))\n };\n}\n\n/**\n * Flags every cloud command accepts, documented once.\n *\n * Lives here rather than in `action-help.ts` because both help renderers print\n * it and `action-help` imports this module, not the other way round.\n */\nexport const GLOBAL_HELP_FLAGS: Array<[string, string]> = [\n [\"--project, -p <slug>\", \"Operate on a project without linking this directory\"],\n [\"--json\", \"Machine-readable output (also when piped, or REBASE_JSON=1)\"],\n [\"--url <origin>\", \"Target a specific control plane (or REBASE_CLOUD_URL)\"],\n [\"--yes, -y\", \"Skip confirmation prompts\"],\n [\"--debug\", \"Print the untouched error body after a failure\"]\n];\n\n/**\n * Flag names `parseCloudArgs` adds to every command in the family.\n *\n * Derived from `GLOBAL_CLOUD_FLAGS` rather than listed again — a second copy is\n * how a global gains a spelling that the collision sweep does not know about.\n * `--debug` is the one addition: `bin/rebase.js` takes it off `process.argv`\n * itself, so no cloud spec declares it and every command still accepts it.\n */\nexport const GLOBAL_SPEC_KEYS = new Set([...Object.keys(GLOBAL_CLOUD_FLAGS), \"--debug\"]);\n\n/** Column width for an action word (+ its args) before its description. */\nconst HELP_COLUMN = 28;\n\n/**\n * The gap after `text` in a `width`-wide column, never less than one space.\n *\n * `padEnd` returns the string unchanged when it is already at the width, which\n * glues the description onto the flag: `--connection-string <url>The external…`.\n */\nfunction pad(text: string, width: number): string {\n return \" \".repeat(Math.max(1, width - text.length));\n}\n\n/**\n * Print a group's page — the human one, and the same content as JSON when piped.\n */\nexport function printGroupHelp(page: GroupHelp): void {\n emitHelp(\n page.command,\n page.actions,\n () => {\n console.log(\"\");\n console.log(`${chalk.bold(`rebase ${page.command}`)} — ${page.title}`);\n console.log(\"\");\n console.log(chalk.green.bold(\"Usage\"));\n console.log(` rebase ${page.command} ${chalk.blue(\"<action>\")} [options]`);\n\n let section: string | undefined;\n for (const entry of page.actions) {\n const heading = entry.section ?? \"Commands\";\n if (heading !== section) {\n section = heading;\n console.log(\"\");\n console.log(chalk.green.bold(heading));\n }\n const word = `${entry.action}${entry.args ? ` ${entry.args}` : \"\"}`;\n console.log(\n ` ${chalk.blue.bold(entry.action)}${entry.args ? ` ${chalk.gray(entry.args)}` : \"\"}`\n + `${pad(word, HELP_COLUMN)}${entry.description}`\n );\n for (const [flag, description] of entry.flags ?? []) {\n console.log(` ${chalk.blue(flag)}${pad(flag, HELP_COLUMN - 4)}${chalk.gray(description)}`);\n }\n }\n\n if (page.options?.length) {\n console.log(\"\");\n console.log(chalk.green.bold(\"Options\"));\n for (const [flag, description] of page.options) {\n console.log(` ${chalk.blue(flag)}${pad(flag, HELP_COLUMN)}${description}`);\n }\n }\n\n console.log(\"\");\n console.log(chalk.green.bold(\"Global options\"));\n for (const [flag, description] of GLOBAL_HELP_FLAGS) {\n console.log(` ${chalk.blue(flag)}${pad(flag, HELP_COLUMN)}${chalk.gray(description)}`);\n }\n\n if (page.notes?.length) {\n console.log(\"\");\n for (const note of page.notes) console.log(chalk.gray(` ${note}`));\n }\n console.log(\"\");\n },\n {\n usage: `rebase ${page.command} <action> [options]`,\n summary: page.title,\n options: (page.options ?? []).map(([flag, description]) => ({ flag,\ndescription })),\n globalFlags: GLOBAL_HELP_FLAGS.map(([flag, description]) => ({ flag,\ndescription })),\n notes: page.notes ?? []\n }\n );\n}\n\n/* ═══════════════════════════════════════════════════════════════\n Output helpers\n ═══════════════════════════════════════════════════════════════ */\n\n/**\n * Print a warning (+ optional hint) — in every output mode, always to stderr.\n *\n * `emit` is for a command's *result*, and JSON mode legitimately replaces the\n * human rendering of one. A warning is not a result: it says the command is\n * about to do something the caller may not have meant, and that is exactly as\n * true when the output is piped. Gating one on `!isJsonMode()` deleted it\n * precisely where nobody was watching the terminal — a `--source` deploy ejected\n * a live project off the managed runtime and said so only to a TTY that wasn't\n * there.\n *\n * stdout carries the JSON value and nothing else, so warnings go to stderr:\n * a machine parser reading stdout cannot be corrupted by one. Only the\n * *formatting* may depend on the mode — colour and indentation for a terminal,\n * plain ASCII otherwise. Whether a warning is emitted at all may not.\n *\n * Anything a caller might branch on belongs in the JSON payload as well; stderr\n * is for whoever reads the transcript afterwards.\n */\nexport function warn(message: string, hint?: string): void {\n if (JSON_MODE) {\n process.stderr.write(`warning: ${stripAnsi(message)}\\n`);\n if (hint) process.stderr.write(` ${stripAnsi(hint)}\\n`);\n return;\n }\n console.error(\"\");\n console.error(chalk.yellow(` ⚠ ${message}`));\n if (hint) console.error(chalk.gray(` ${hint}`));\n}\n\n/**\n * Print an error (+ optional hint) and exit non-zero. Never returns.\n *\n * `code` is the field a caller branches on, and it defaults to `\"error\"` rather\n * than `null`. An envelope whose only machine-readable field is null is not\n * machine-readable — `{\"error\":{\"message\":\"No project specified…\",\"code\":null}}`\n * forced the very substring-matching on `message` that the envelope exists to\n * make unnecessary, and `message` is the field most likely to be reworded.\n *\n * `\"error\"` is deliberately a poor code: it says \"this refusal has not been\n * classified yet\" without ever being absent. Anything a caller might plausibly\n * want to distinguish — `usage`, `not_found`, `unauthenticated` — passes a real\n * one. Codes are part of the CLI's contract once shipped; see\n * `cloud-reporting.test.ts`, which pins the ones commands are documented to\n * return.\n */\nexport function fail(message: string, hint?: string, code?: string): never {\n if (JSON_MODE) {\n printJson({ error: { message: stripAnsi(message),\ncode: code ?? \"error\",\nhint: hint ? stripAnsi(hint) : undefined } });\n process.exit(1);\n }\n console.error(\"\");\n console.error(chalk.red(` ✗ ${message}`));\n if (hint) console.error(chalk.gray(` ${hint}`));\n console.error(\"\");\n process.exit(1);\n}\n\n/**\n * Confirm a destructive/irreversible action, respecting non-interactive use.\n *\n * With `--yes`/`-y` it proceeds silently. In JSON mode or a non-TTY it REFUSES\n * to prompt — a prompt that can hang is a known repo landmine — and fails,\n * telling the caller to pass `--yes`. Only an interactive terminal gets a real\n * confirm prompt; declining there aborts cleanly (exit 0).\n */\nexport async function confirmDestructive(opts: { yes: boolean; prompt: string }): Promise<void> {\n if (opts.yes) return;\n if (JSON_MODE || process.stdin.isTTY !== true) {\n fail(\n \"This action is destructive and needs confirmation.\",\n `Re-run with ${chalk.bold(\"--yes\")} to proceed.`,\n \"confirmation_required\"\n );\n }\n const { confirmed } = (await inquirer.prompt([\n { type: \"confirm\",\nname: \"confirmed\",\ndefault: false,\nmessage: opts.prompt }\n ] as Parameters<typeof inquirer.prompt>[0])) as { confirmed: boolean };\n if (!confirmed) {\n // stderr: declining is not a result. Unreachable in JSON mode — the\n // guard above already refused rather than prompt — so stdout stays\n // empty and the exit code carries the outcome.\n console.error(chalk.gray(\" Aborted.\"));\n process.exit(0);\n }\n}\n\n/**\n * Refuse, rather than prompt, when there is nobody to answer.\n *\n * `confirmDestructive` has always done this for yes/no confirmations. The\n * *value* prompts had no such guard: `cloud login`, `cloud link`, `cloud use`,\n * `cloud orgs create` and `cloud db create` all called `inquirer.prompt`\n * unconditionally, so piping any of them — which is how an agent runs every\n * command in this family — parked the process on a prompt reading from a stdin\n * that was never going to produce a line. A hang is the worst failure mode\n * available here: no output, no exit code, nothing to retry on.\n *\n * @param what what the prompt would have asked for, e.g. \"an email and password\"\n * @param flags the flags that supply it non-interactively\n */\nexport function requireInteractive(what: string, flags: string): void {\n if (JSON_MODE || process.stdin.isTTY !== true) {\n fail(\n `This command needs ${what}, and there is no terminal to ask on.`,\n `Pass ${chalk.bold(flags)}.`,\n \"input_required\"\n );\n }\n}\n\n/**\n * Resolve one cloud command's flags and ARGUMENTS from the full `process.argv`.\n *\n * This replaces `cloudPositionals`, which was `rawArgs.slice(3).filter(a =>\n * !a.startsWith(\"-\"))`. Dropping `-`-prefixed tokens looks like it solves the\n * permissive-parse problem and does not: a flag that takes a VALUE leaves the\n * value behind, an ordinary word in the argument position that no filter can\n * tell from a real one. `--project` is the flag every one of these commands\n * documents, so the failure was reachable from the help page:\n *\n * rebase cloud env unset -p acme → removed the variable \"acme\"\n * rebase cloud env set KEY -p acme → stored the value \"acme\"\n * rebase cloud domains add -p acme → registered the domain \"acme\"\n * rebase cloud webhooks delete -p acme 42 → deleted webhook \"acme\", not 42\n * rebase cloud cancel -p acme → cancelled deployment id \"acme\"\n *\n * The filter's other half is quieter. A flag nobody declared *is* dropped by\n * it — but only from the operands, never from the run: nothing rejects it, so\n * the command proceeds with the argument missing or defaulted. `db backup\n * --dry-run` listed backups, `domains remove --dry-run` detached the domain,\n * and `env set KEY=v --secrett` stored the value as an ordinary variable that\n * `env reveal` will hand back. The one place an undeclared flag became the\n * argument outright is `projects info|delete`, which resolved its id through\n * `positionals()` instead — that skips only LEADING `-` tokens, so `projects\n * delete --force` looked up a project named \"--force\".\n *\n * So: parse the whole line strictly, through the same `parseCommandArgs` the\n * non-cloud commands use — `arg` then consumes each declared flag *with its\n * value* wherever it appears, and rejects the undeclared, leaving `_` holding\n * the command words followed by the real arguments. `commandWords` counts from\n * `cloud` itself (`cloud env set` ⇒ 3), and is applied to the parsed\n * positionals, so a flag written before the group shifts nothing.\n *\n * Two things this adds over calling `parseCommandArgs` directly, and the reason\n * it is worth a wrapper:\n *\n * - `GLOBAL_CLOUD_FLAGS` is merged in. `--json`, `--yes` and `--project` may\n * appear anywhere on a cloud line including before the group, so a strict\n * parse that did not declare them would reject the CLI's own documented\n * usage. (`parseCommandArgs` adds `--debug`/`--help` on top of that.)\n * - A parse error is reported through `fail`, not thrown. A throw reaches\n * `bin/rebase.js`, which prints `✗ …` to stderr — which is right for every\n * other command and wrong here: `rebase cloud` is in JSON mode whenever\n * stdout is not a TTY, i.e. always for the agents this family is built for,\n * and it promises them exactly one JSON value. `fail` keeps that promise,\n * with the same `usage` code the other refusals in this family use.\n */\nexport function parseCloudArgs<S extends arg.Spec>(opts: {\n spec: S;\n rawArgs: string[];\n commandWords: number;\n /** Names the command in errors, e.g. `cloud env set` (no leading `rebase`). */\n command: string;\n maxPositionals?: number;\n}): { flags: arg.Result<S & typeof GLOBAL_CLOUD_FLAGS>; positionals: string[] } {\n const spec = { ...GLOBAL_CLOUD_FLAGS,\n...opts.spec };\n try {\n const parsed = parseCommandArgs({ ...opts,\nspec });\n return { flags: parsed.flags,\npositionals: parsed.positionals };\n } catch (err) {\n fail(err instanceof Error ? err.message : String(err), undefined, \"usage\");\n }\n}\n\n/**\n * Refuse an action word its group does not dispatch. Returns for `undefined`,\n * which is every group's default action.\n *\n * The groups that switch on their action already do this in a `default:` case.\n * The groups written as a chain of `if (action === \"x\") return …` did not: a\n * word that matched nothing fell out of the chain into the *default* action, so\n * `rebase cloud storage creat` listed the buckets and exited 0, and\n * `rebase cloud billing usage` printed the account. Reporting a typo as a\n * successful run of a different command is the failure mode this family exists\n * to not have — an agent branching on the exit code learns nothing, and a person\n * reads the output of a command they did not ask for.\n *\n * One spelling, so the code is `unknown_command` everywhere rather than the\n * default `\"error\"` half of them used, and the hint always names the group's own\n * `--help` rather than the index page.\n */\nexport function requireKnownAction(\n group: string,\n action: string | undefined,\n known: readonly string[]\n): void {\n if (action === undefined || known.includes(action)) return;\n fail(\n `Unknown ${group} command: ${action}`,\n `Run \\`rebase cloud ${group} --help\\`. Actions: ${known.join(\", \")}.`,\n \"unknown_command\"\n );\n}\n\n/**\n * `--timeout <seconds>` as milliseconds, or `fallbackMs` when it was not given.\n *\n * One function rather than one per command, because two commands take this flag\n * and a second copy is where the two would come to disagree about what\n * `--timeout 0` means.\n *\n * A value this cannot read is a refusal, not a fall back to the default. The\n * whole reason a caller passes a timeout is that it has a deadline of its own;\n * quietly substituting a different one is how a fifteen-minute wait turns up\n * inside a five-minute CI step, having been asked for `--timeout 30s`.\n */\nexport function resolveTimeoutMs(\n value: string | undefined,\n opts: { fallbackMs: number; command: string }\n): number {\n if (value === undefined) return opts.fallbackMs;\n const seconds = Number(value);\n if (!Number.isFinite(seconds) || seconds <= 0) {\n fail(\n `--timeout takes a number of seconds (got \"${value}\").`,\n `Run \\`rebase ${opts.command} --help\\`.`,\n \"usage\"\n );\n }\n return seconds * 1000;\n}\n\n/**\n * Announce an outcome — \"Logged in as …\", \"Deleted project …\".\n *\n * On **stderr**, in both modes. It reads like a result and is not one: the\n * result is the JSON value (or the table) on stdout, and every JSON payload in\n * this family already carries `success: true`. Leaving this on stdout meant a\n * successful `rebase cloud link | jq` was handed a green tick followed by an\n * object — one stream, two syntaxes, and only the second parseable.\n *\n * It stays visible in JSON mode, unlike `note`: an agent that got a `success`\n * line on a command it expected to refuse has learned something.\n */\nexport function success(message: string): void {\n if (JSON_MODE) {\n process.stderr.write(`${stripAnsi(message)}\\n`);\n return;\n }\n console.error(\"\");\n console.error(chalk.bold.green(` ✓ ${message}`));\n console.error(\"\");\n}\n\n/**\n * Narrate progress, or point at the next step — \"Signing in to …\", \"Redeploy\n * for the tenant to pick this up\".\n *\n * stderr, and **suppressed entirely in JSON mode**. This is the one helper that\n * a mode may silence, and the distinction from `warn` is worth keeping sharp:\n *\n * - A warning is a *condition*. It is as true when piped as when watched, so\n * silencing it hides something the caller would want to know. `warn` never\n * silences.\n * - A note is *hand-holding*. \"Next: run `rebase generate-sdk`\" tells a person\n * what to type; the agent reading the JSON already has the same information\n * structurally, or does not need it. Printing it anyway is transcript noise.\n *\n * When in doubt it is a warning. The cost of a needless warning is a line; the\n * cost of a swallowed one is the deploy that ejected a project off the managed\n * runtime and said so only to a terminal nobody was looking at.\n */\nexport function note(message: string, indent = \" \"): void {\n if (JSON_MODE) return;\n console.error(`${indent}${message}`);\n}\n\n/** A blank spacer line on the narration stream. No-op in JSON mode. */\nexport function noteBlank(): void {\n if (JSON_MODE) return;\n console.error(\"\");\n}\n\n/** Colorize a deployment / resource status token. */\nexport function colorStatus(status: string | undefined): string {\n switch (status) {\n case \"active\":\n case \"success\":\n case \"connected\":\n return chalk.green(status);\n case \"deploying\":\n case \"provisioning\":\n case \"pending_billing\":\n case \"untested\":\n return chalk.yellow(status ?? \"\");\n case \"failed\":\n return chalk.red(status);\n case \"stopped\":\n return chalk.gray(status);\n default:\n return chalk.gray(status ?? \"unknown\");\n }\n}\n\n/**\n * Render a two-column key/value block with aligned keys. Empty rows are skipped\n * — including `null`, which the API sends for an unset column and which used to\n * print the literal string \"null\" (e.g. `Custom domain: null`).\n */\nexport function keyValues(rows: Array<[string, string | null | undefined]>): void {\n const width = Math.max(...rows.map(([k]) => k.length));\n for (const [k, v] of rows) {\n if (v === undefined || v === null || v === \"\") continue;\n console.log(` ${chalk.gray(`${k}:`.padEnd(width + 1))} ${v}`);\n }\n}\n\n/**\n * Surface an SDK/HTTP error consistently. The SDK throws RebaseApiError with\n * a `.status` and `.message`; anything else falls back to its string form.\n *\n * The message is summarised rather than printed — see `summarizeError`. What\n * arrives here is routinely a whole Kubernetes `Status` object with the request\n * headers appended, and the one sentence worth reading is inside it. The\n * untouched body is still available, behind `--debug`, on stderr where it\n * cannot corrupt the JSON value on stdout.\n */\nexport function reportError(e: unknown, context: string): never {\n const err = e as { status?: number; message?: string; code?: string };\n const summary = summarizeError(e, context);\n\n if (wantsRawError()) {\n process.stderr.write(`\\n${summary.raw}\\n\\n`);\n }\n\n if (JSON_MODE) {\n printJson({\n error: {\n message: stripAnsi(summary.message),\n // The SDK supplies a code for errors the API classified. When it\n // does not, the HTTP status still classifies it well enough to\n // branch on — `http_401` and `http_502` want very different\n // handling, and both used to arrive as `null`. A cluster\n // refusal classifies itself, and `platform` below says whether\n // acting on it is even the caller's business.\n code: summary.code,\n status: err?.status ?? null,\n hint: summary.hint ? stripAnsi(summary.hint) : undefined,\n platform: summary.platform,\n context\n }\n });\n process.exit(1);\n }\n fail(summary.message, summary.hint, summary.code);\n}\n\n/**\n * Open a URL in the user's default browser (best effort). Always announces the\n * URL first so it stays usable over SSH or when no browser is available.\n *\n * The announcement is narration, not the result — it goes to stderr, and in\n * JSON mode it is silent. Every caller `emit`s the same URL in its payload, so\n * a machine reader gets it from the one place it is guaranteed to be parseable\n * rather than from a line that happens to end in a URL.\n */\nexport function openUrl(target: string, label = \"Opening\"): void {\n noteBlank();\n note(`${label} ${chalk.cyan(target)}`);\n noteBlank();\n const opener =\n process.platform === \"darwin\" ? \"open\" : process.platform === \"win32\" ? \"start\" : \"xdg-open\";\n try {\n const child = spawn(opener, [target], {\n stdio: \"ignore\",\n detached: true,\n shell: process.platform === \"win32\"\n });\n child.on(\"error\", () => {\n /* URL already printed for manual copy */\n });\n child.unref();\n } catch {\n /* URL already printed */\n }\n}\n\n/**\n * The one thing every control-plane row is required to have.\n *\n * The subcommands each declare their own row shape — `OrgRow`, `ProjectRow`,\n * `DatabaseRow`, `DeploymentRow` — and every one of them is an `id` plus\n * fields that are all optional, because a control plane older than a given\n * column simply does not send it. The reads are written that way too\n * (`o.name ?? \"(unnamed)\"`, `row.slug ? … : \"\"`).\n */\nexport interface CloudRow {\n id: string | number;\n}\n\n/**\n * Read the control plane's rows as a subcommand's row shape.\n *\n * `client.data.collection(...)` is typed against the *generated* schema of the\n * project the SDK is pointed at, and the control-plane collections this CLI\n * reads are not in one — so every row arrives as an open\n * `Record<string, unknown>`. A declared `interface` gets no implicit index\n * signature, so it does not overlap that, and a direct `as` is refused: which\n * is how ten call sites came to write `as unknown as XRow[]`, an assertion\n * about a wire payload with nothing checking it in either direction.\n *\n * There is exactly one invariant to check and this checks it. Everything else\n * the shapes declare is optional and already read as such, so there is nothing\n * further to verify — but a row with no usable `id` is not a row any of these\n * commands can act on, and passing it through was how a listing came to print\n * `[undefined]` and a lookup came to compare against the string `\"undefined\"`.\n */\nexport function cloudRows<T extends CloudRow>(rows: readonly Record<string, unknown>[] | undefined): T[] {\n return (rows ?? []).filter((row): row is Record<string, unknown> & T =>\n typeof row?.id === \"string\" || typeof row?.id === \"number\");\n}\n\n/** {@link cloudRows} for an endpoint that returns a single row. */\nexport function cloudRow<T extends CloudRow>(row: Record<string, unknown> | undefined): T | undefined {\n return cloudRows<T>(row ? [row] : [])[0];\n}\n\n/**\n * {@link cloudRows} for a write that must have produced a row.\n *\n * `create()` returning something with no usable `id` means the control plane\n * accepted the write and then described it in a way this CLI cannot act on.\n * The callers all go straight on to use that id — `setContextOrg(url,\n * String(created.id))` — so asserting the shape, which is what stood here,\n * turned a control-plane fault into an organization whose active id is the\n * seven-letter string `\"undefined\"`, stored in the user's config file.\n */\nexport function requireCloudRow<T extends CloudRow>(\n row: Record<string, unknown> | undefined,\n what: string\n): T {\n const parsed = cloudRow<T>(row);\n if (!parsed) throw new Error(`The control plane accepted the ${what} but returned no id for it.`);\n return parsed;\n}\n"],"mappings":"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"}