@rebasepro/cli 0.22.0 → 0.24.0

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 (80) hide show
  1. package/README.md +19 -3
  2. package/bin/rebase.js +1 -1
  3. package/dist/{branch-pointer-dBiClJ0p.js → branch-pointer-kk9F5FBO.js} +2 -2
  4. package/dist/{branch-pointer-dBiClJ0p.js.map → branch-pointer-kk9F5FBO.js.map} +1 -1
  5. package/dist/bundle.d.ts +16 -2
  6. package/dist/cli.d.ts +39 -0
  7. package/dist/commands/__test_support__/parser-specs.d.ts +13 -0
  8. package/dist/commands/agent-setup.d.ts +116 -0
  9. package/dist/commands/api-keys.d.ts +85 -22
  10. package/dist/commands/apps.d.ts +19 -0
  11. package/dist/commands/auth.d.ts +19 -0
  12. package/dist/commands/build.d.ts +13 -1
  13. package/dist/commands/cloud/auth.d.ts +4 -3
  14. package/dist/commands/cloud/bundle-deploy.d.ts +79 -5
  15. package/dist/commands/cloud/context.d.ts +87 -5
  16. package/dist/commands/cloud/cron.d.ts +53 -0
  17. package/dist/commands/cloud/db-connect.d.ts +15 -0
  18. package/dist/commands/cloud/debug.d.ts +134 -0
  19. package/dist/commands/cloud/deploy.d.ts +55 -2
  20. package/dist/commands/cloud/domains.d.ts +2 -2
  21. package/dist/commands/cloud/env.d.ts +14 -0
  22. package/dist/commands/cloud/index.d.ts +89 -12
  23. package/dist/commands/cloud/rebuild-source.d.ts +24 -2
  24. package/dist/commands/cloud/token-capabilities.d.ts +76 -0
  25. package/dist/commands/cloud/tokens.d.ts +23 -0
  26. package/dist/commands/db.d.ts +17 -1
  27. package/dist/commands/dev.d.ts +78 -7
  28. package/dist/commands/doctor.d.ts +5 -0
  29. package/dist/commands/generate_sdk.d.ts +3 -2
  30. package/dist/commands/init.d.ts +57 -14
  31. package/dist/commands/schema.d.ts +8 -0
  32. package/dist/commands/skills.d.ts +111 -5
  33. package/dist/commands/start.d.ts +29 -0
  34. package/dist/commands/telemetry.d.ts +10 -0
  35. package/dist/{daemon-DR9Tk0La.js → daemon-C8p32i-n.js} +5 -3
  36. package/dist/daemon-C8p32i-n.js.map +1 -0
  37. package/dist/dev-db/daemon.d.ts +10 -0
  38. package/dist/dev-db/prepare.d.ts +10 -0
  39. package/dist/dev-db/pull.d.ts +31 -2
  40. package/dist/dev-db/resolve.d.ts +2 -4
  41. package/dist/fold-static.d.ts +28 -3
  42. package/dist/index.es.js +13360 -9756
  43. package/dist/index.es.js.map +1 -1
  44. package/dist/manifest.d.ts +41 -1
  45. package/dist/package-manager-CXQevsE1.js +193 -0
  46. package/dist/package-manager-CXQevsE1.js.map +1 -0
  47. package/dist/{project-3WCbrrfW.js → project-DmaGLmH2.js} +4 -183
  48. package/dist/project-DmaGLmH2.js.map +1 -0
  49. package/dist/{pull-Bj0XnH5s.js → pull-Dywm5FWP.js} +41 -5
  50. package/dist/{pull-Bj0XnH5s.js.map → pull-Dywm5FWP.js.map} +1 -1
  51. package/dist/{resolve-Y56osuQH.js → resolve-BAeRUBhg.js} +2 -2
  52. package/dist/resolve-BAeRUBhg.js.map +1 -0
  53. package/dist/upgrade.d.ts +24 -3
  54. package/dist/utils/path-flags.d.ts +18 -0
  55. package/dist/utils/tool-stdio.d.ts +11 -0
  56. package/dist/version-DsgBmP22.js +58 -0
  57. package/dist/version-DsgBmP22.js.map +1 -0
  58. package/package.json +8 -8
  59. package/templates/eject/backend/src/index.ts +14 -1
  60. package/templates/overlays/baas/ai-instructions.md +1 -1
  61. package/templates/overlays/baas/config/storage.ts +5 -3
  62. package/templates/template/.cursorrules +1 -1
  63. package/templates/template/.env.example +10 -6
  64. package/templates/template/.github/copilot-instructions.md +1 -1
  65. package/templates/template/.mcp.json +2 -2
  66. package/templates/template/.windsurfrules +1 -1
  67. package/templates/template/AGENTS.md +1 -1
  68. package/templates/template/CLAUDE.md +1 -1
  69. package/templates/template/README.md +10 -11
  70. package/templates/template/ai-instructions.md +3 -3
  71. package/templates/template/backend/functions/hello.ts +8 -0
  72. package/templates/template/backend/package.json +1 -1
  73. package/templates/template/config/storage.ts +5 -3
  74. package/templates/template/docker-compose.yml +6 -6
  75. package/templates/template/gitignore +6 -1
  76. package/templates/template/package.json +4 -3
  77. package/templates/template/scripts/example.ts +4 -3
  78. package/dist/daemon-DR9Tk0La.js.map +0 -1
  79. package/dist/project-3WCbrrfW.js.map +0 -1
  80. package/dist/resolve-Y56osuQH.js.map +0 -1
package/README.md CHANGED
@@ -22,7 +22,7 @@ The CLI is also bundled with every Rebase project as a local dependency.
22
22
  | `rebase dev` | Start the development server (backend + frontend) |
23
23
  | `rebase build` | Build the apps declared in `rebase.json` into a bundle |
24
24
  | `rebase normalize-imports` | Complete compiled output's relative imports for Node ESM |
25
- | `rebase start` | Start the backend server (production) |
25
+ | `rebase start` | Run the built bundle, as a deployment does, in the `NODE_ENV` you set |
26
26
  | `rebase apps list` | Show the apps this repository declares |
27
27
  | `rebase schema generate` | Generate Drizzle schema from collection definitions |
28
28
  | `rebase schema introspect` | Introspect an existing database → Rebase collections |
@@ -36,7 +36,7 @@ The CLI is also bundled with every Rebase project as a local dependency.
36
36
  | `rebase db reset` | Delete the managed development database and start over |
37
37
  | `rebase generate-sdk` | Generate a typed TypeScript SDK from collections |
38
38
  | `rebase auth reset-password` | Reset a user's password |
39
- | `rebase api-keys list \| create \| revoke` | Manage scoped service API keys |
39
+ | `rebase api-keys list \| get \| create \| revoke \| scopes` | Manage service API keys and the scopes they hold |
40
40
  | `rebase doctor` | Detect schema drift between collections, Drizzle schema, and database |
41
41
  | `rebase status` | Show every resource this project declares and whether its variables are set |
42
42
  | `rebase resources` | List the databases, buckets and topics this project declares |
@@ -64,7 +64,7 @@ rebase cloud status # project status at a glance
64
64
 
65
65
  | Group | Commands |
66
66
  |-------|----------|
67
- | Auth | `login`, `logout`, `whoami` |
67
+ | Auth | `login`, `logout`, `whoami`, `tokens list \| create \| revoke` |
68
68
  | Link/context | `link`, `unlink`, `use [org]`, `open` |
69
69
  | Projects | `projects list \| create \| info \| delete` |
70
70
  | Deploy/observe | `deploy`, `logs [--runtime] [-f]`, `status`, `metrics` |
@@ -75,6 +75,22 @@ rebase cloud status # project status at a glance
75
75
  Most commands act on the linked project unless you pass `--project <id>`.
76
76
  Run `rebase cloud --help` for the full list.
77
77
 
78
+ ### Tokens for CI and agents
79
+
80
+ A token acts as your account, narrowed to what it was created for on one project.
81
+ Create it from a signed-in terminal, then hand it to CI as `REBASE_TOKEN` — every
82
+ `rebase cloud` command uses it instead of a login, and never reads or writes the
83
+ stored session:
84
+
85
+ ```bash
86
+ rebase cloud tokens create --project shop --can deploy,logs --expires-in 90
87
+ # → export REBASE_TOKEN=rk_live_… (shown once)
88
+ REBASE_TOKEN=rk_live_… rebase cloud deploy --project shop
89
+ ```
90
+
91
+ `--can` takes `deploy`, `logs`, `env`, `database` and `backups`. A token cannot
92
+ create, list or revoke tokens, and none can restore a backup.
93
+
78
94
  ## Quick Start
79
95
 
80
96
  ```bash
package/bin/rebase.js CHANGED
@@ -133,7 +133,7 @@ function warnIfStale() {
133
133
  : seconds >= 60 ? `${Math.round(seconds / 60)}m` : `${seconds}s`;
134
134
  process.stderr.write(
135
135
  `${yellow(`⚠ rebase CLI: dist/ is ${ago} older than src/ — you are running a stale build.`)}\n` +
136
- ` Rebuild with: (cd ${join(here, "..")} && npm run build)\n`
136
+ " Rebuild with: pnpm --filter @rebasepro/cli build\n"
137
137
  );
138
138
  }
139
139
 
@@ -106,6 +106,6 @@ function databaseNameOf(connectionString) {
106
106
  }
107
107
  }
108
108
  //#endregion
109
- export { branch_pointer_exports as n, readActiveBranch as r, branchUrl as t };
109
+ export { readActiveBranch as i, branch_pointer_exports as n, databaseNameOf as r, branchUrl as t };
110
110
 
111
- //# sourceMappingURL=branch-pointer-dBiClJ0p.js.map
111
+ //# sourceMappingURL=branch-pointer-kk9F5FBO.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"branch-pointer-dBiClJ0p.js","names":[],"sources":["../src/dev-db/branch-pointer.ts"],"sourcesContent":["/**\n * Which database branch this checkout is working on.\n *\n * `rebase db branch create` made a full copy of the database in about a second\n * and then stopped one step short of being a feature: there was no `switch`, no\n * `--branch` on `rebase dev`, and nothing wrote the branch anywhere a command\n * would read it. The only way to *use* a branch was to hand-edit\n * `DATABASE_URL`, and the documentation claimed otherwise — \"the CLI updates\n * your local development configuration\" — which it did not; the `.env` was\n * byte-identical afterwards.\n *\n * This is that missing step, and the shape of it is chosen to avoid three\n * things:\n *\n * 1. **It does not touch `.env`.** That file holds secrets, comments and the\n * developer's own ordering, and a command that rewrites it in place will\n * eventually lose something that was not its business. The branch is\n * recorded beside the other per-checkout state in `.rebase/`, which is\n * already gitignored — a branch is a fact about one machine, never about\n * the project.\n *\n * 2. **It stores a name, not a connection string.** The credentials stay in\n * exactly one place; the URL is derived by swapping the database name on\n * the base one at resolution time. A stored URL would be a second copy of\n * the password, and would go stale the moment `.env` changed.\n *\n * 3. **It does not outrank an explicit instruction.** `--database-url` and a\n * `DATABASE_URL` in the shell are more immediate and more specific than a\n * switch made yesterday, so they still win. The pointer sits directly above\n * the project's `.env`: it is a deliberate, persistent choice, and `.env` is\n * the project default it is meant to override. Anything less and `switch`\n * would silently do nothing on every project that sets `DATABASE_URL` —\n * which is every project not using the managed database.\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\n\n/** Where the pointer lives, next to the rest of the per-checkout state. */\nexport function branchPointerPath(projectRoot: string): string {\n return path.join(projectRoot, \".rebase\", \"branch.json\");\n}\n\nexport interface ActiveBranch {\n /** The name the developer typed. */\n name: string;\n /** The PostgreSQL database that name refers to. */\n database: string;\n}\n\n/**\n * The prefix `BranchService` puts on every branch database.\n *\n * Duplicated from the driver rather than imported because the CLI must answer\n * \"which database\" without loading a database driver — `rebase dev` reads this\n * before it knows which plugin the project uses. It is covered by a test that\n * fails if the driver's prefix moves.\n */\nexport const BRANCH_DB_PREFIX = \"rb_\";\n\nexport function branchDatabaseName(name: string): string {\n return `${BRANCH_DB_PREFIX}${name}`;\n}\n\n/** Read the active branch, or null when the checkout is on the main database. */\nexport function readActiveBranch(projectRoot: string): ActiveBranch | null {\n try {\n const raw = fs.readFileSync(branchPointerPath(projectRoot), \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<ActiveBranch>;\n if (typeof parsed.name !== \"string\" || typeof parsed.database !== \"string\") return null;\n if (!parsed.name || !parsed.database) return null;\n\n return { name: parsed.name, database: parsed.database };\n } catch {\n // Absent is the common case and is not an error. A corrupt file is\n // treated the same way: the answer is \"no branch\", which is the state\n // the developer can always get back to with `branch switch --off`.\n return null;\n }\n}\n\nexport function writeActiveBranch(projectRoot: string, branch: ActiveBranch): void {\n const file = branchPointerPath(projectRoot);\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.writeFileSync(file, `${JSON.stringify(branch, null, 2)}\\n`, \"utf-8\");\n}\n\n/** Return to the main database. Absent is success — this is idempotent. */\nexport function clearActiveBranch(projectRoot: string): void {\n fs.rmSync(branchPointerPath(projectRoot), { force: true });\n}\n\n/**\n * The base connection string with its database swapped for the branch's.\n *\n * Everything else is carried across untouched — credentials, host, port, and\n * the query string, which is load-bearing here: `?sslmode=disable` is what a\n * local Docker Postgres needs, and dropping it turns a switch into a TLS error\n * that says nothing about branches.\n *\n * Returns null for a connection string that cannot be parsed, so the caller can\n * say so plainly rather than emitting a mangled URL that fails later.\n */\nexport function branchUrl(baseUrl: string, database: string): string | null {\n try {\n const url = new URL(baseUrl);\n // `pathname` keeps its leading slash; a URL with no database at all\n // still gets one, which is what connecting to a named branch means.\n url.pathname = `/${database}`;\n\n return url.toString();\n } catch {\n return null;\n }\n}\n\n/** The database name in a connection string, for reporting what you are on. */\nexport function databaseNameOf(connectionString: string): string | null {\n try {\n const name = new URL(connectionString).pathname.replace(/^\\//, \"\");\n\n return name || null;\n } catch {\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,kBAAkB,aAA6B;CAC3D,OAAO,KAAK,KAAK,aAAa,WAAW,aAAa;AAC1D;AAmBA,SAAgB,mBAAmB,MAAsB;CACrD,OAAO,MAAsB;AACjC;;AAGA,SAAgB,iBAAiB,aAA0C;CACvE,IAAI;EACA,MAAM,MAAM,GAAG,aAAa,kBAAkB,WAAW,GAAG,OAAO;EACnE,MAAM,SAAS,KAAK,MAAM,GAAG;EAC7B,IAAI,OAAO,OAAO,SAAS,YAAY,OAAO,OAAO,aAAa,UAAU,OAAO;EACnF,IAAI,CAAC,OAAO,QAAQ,CAAC,OAAO,UAAU,OAAO;EAE7C,OAAO;GAAE,MAAM,OAAO;GAAM,UAAU,OAAO;EAAS;CAC1D,QAAQ;EAIJ,OAAO;CACX;AACJ;AAEA,SAAgB,kBAAkB,aAAqB,QAA4B;CAC/E,MAAM,OAAO,kBAAkB,WAAW;CAC1C,GAAG,UAAU,KAAK,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;CACpD,GAAG,cAAc,MAAM,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,KAAK,OAAO;AAC1E;;AAGA,SAAgB,kBAAkB,aAA2B;CACzD,GAAG,OAAO,kBAAkB,WAAW,GAAG,EAAE,OAAO,KAAK,CAAC;AAC7D;;;;;;;;;;;;AAaA,SAAgB,UAAU,SAAiB,UAAiC;CACxE,IAAI;EACA,MAAM,MAAM,IAAI,IAAI,OAAO;EAG3B,IAAI,WAAW,IAAI;EAEnB,OAAO,IAAI,SAAS;CACxB,QAAQ;EACJ,OAAO;CACX;AACJ;;AAGA,SAAgB,eAAe,kBAAyC;CACpE,IAAI;EAGA,OAFa,IAAI,IAAI,gBAAgB,CAAC,CAAC,SAAS,QAAQ,OAAO,EAExD,KAAQ;CACnB,QAAQ;EACJ,OAAO;CACX;AACJ"}
1
+ {"version":3,"file":"branch-pointer-kk9F5FBO.js","names":[],"sources":["../src/dev-db/branch-pointer.ts"],"sourcesContent":["/**\n * Which database branch this checkout is working on.\n *\n * `rebase db branch create` made a full copy of the database in about a second\n * and then stopped one step short of being a feature: there was no `switch`, no\n * `--branch` on `rebase dev`, and nothing wrote the branch anywhere a command\n * would read it. The only way to *use* a branch was to hand-edit\n * `DATABASE_URL`, and the documentation claimed otherwise — \"the CLI updates\n * your local development configuration\" — which it did not; the `.env` was\n * byte-identical afterwards.\n *\n * This is that missing step, and the shape of it is chosen to avoid three\n * things:\n *\n * 1. **It does not touch `.env`.** That file holds secrets, comments and the\n * developer's own ordering, and a command that rewrites it in place will\n * eventually lose something that was not its business. The branch is\n * recorded beside the other per-checkout state in `.rebase/`, which is\n * already gitignored — a branch is a fact about one machine, never about\n * the project.\n *\n * 2. **It stores a name, not a connection string.** The credentials stay in\n * exactly one place; the URL is derived by swapping the database name on\n * the base one at resolution time. A stored URL would be a second copy of\n * the password, and would go stale the moment `.env` changed.\n *\n * 3. **It does not outrank an explicit instruction.** `--database-url` and a\n * `DATABASE_URL` in the shell are more immediate and more specific than a\n * switch made yesterday, so they still win. The pointer sits directly above\n * the project's `.env`: it is a deliberate, persistent choice, and `.env` is\n * the project default it is meant to override. Anything less and `switch`\n * would silently do nothing on every project that sets `DATABASE_URL` —\n * which is every project not using the managed database.\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\n\n/** Where the pointer lives, next to the rest of the per-checkout state. */\nexport function branchPointerPath(projectRoot: string): string {\n return path.join(projectRoot, \".rebase\", \"branch.json\");\n}\n\nexport interface ActiveBranch {\n /** The name the developer typed. */\n name: string;\n /** The PostgreSQL database that name refers to. */\n database: string;\n}\n\n/**\n * The prefix `BranchService` puts on every branch database.\n *\n * Duplicated from the driver rather than imported because the CLI must answer\n * \"which database\" without loading a database driver — `rebase dev` reads this\n * before it knows which plugin the project uses. It is covered by a test that\n * fails if the driver's prefix moves.\n */\nexport const BRANCH_DB_PREFIX = \"rb_\";\n\nexport function branchDatabaseName(name: string): string {\n return `${BRANCH_DB_PREFIX}${name}`;\n}\n\n/** Read the active branch, or null when the checkout is on the main database. */\nexport function readActiveBranch(projectRoot: string): ActiveBranch | null {\n try {\n const raw = fs.readFileSync(branchPointerPath(projectRoot), \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<ActiveBranch>;\n if (typeof parsed.name !== \"string\" || typeof parsed.database !== \"string\") return null;\n if (!parsed.name || !parsed.database) return null;\n\n return { name: parsed.name, database: parsed.database };\n } catch {\n // Absent is the common case and is not an error. A corrupt file is\n // treated the same way: the answer is \"no branch\", which is the state\n // the developer can always get back to with `branch switch --off`.\n return null;\n }\n}\n\nexport function writeActiveBranch(projectRoot: string, branch: ActiveBranch): void {\n const file = branchPointerPath(projectRoot);\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.writeFileSync(file, `${JSON.stringify(branch, null, 2)}\\n`, \"utf-8\");\n}\n\n/** Return to the main database. Absent is success — this is idempotent. */\nexport function clearActiveBranch(projectRoot: string): void {\n fs.rmSync(branchPointerPath(projectRoot), { force: true });\n}\n\n/**\n * The base connection string with its database swapped for the branch's.\n *\n * Everything else is carried across untouched — credentials, host, port, and\n * the query string, which is load-bearing here: `?sslmode=disable` is what a\n * local Docker Postgres needs, and dropping it turns a switch into a TLS error\n * that says nothing about branches.\n *\n * Returns null for a connection string that cannot be parsed, so the caller can\n * say so plainly rather than emitting a mangled URL that fails later.\n */\nexport function branchUrl(baseUrl: string, database: string): string | null {\n try {\n const url = new URL(baseUrl);\n // `pathname` keeps its leading slash; a URL with no database at all\n // still gets one, which is what connecting to a named branch means.\n url.pathname = `/${database}`;\n\n return url.toString();\n } catch {\n return null;\n }\n}\n\n/** The database name in a connection string, for reporting what you are on. */\nexport function databaseNameOf(connectionString: string): string | null {\n try {\n const name = new URL(connectionString).pathname.replace(/^\\//, \"\");\n\n return name || null;\n } catch {\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,kBAAkB,aAA6B;CAC3D,OAAO,KAAK,KAAK,aAAa,WAAW,aAAa;AAC1D;AAmBA,SAAgB,mBAAmB,MAAsB;CACrD,OAAO,MAAsB;AACjC;;AAGA,SAAgB,iBAAiB,aAA0C;CACvE,IAAI;EACA,MAAM,MAAM,GAAG,aAAa,kBAAkB,WAAW,GAAG,OAAO;EACnE,MAAM,SAAS,KAAK,MAAM,GAAG;EAC7B,IAAI,OAAO,OAAO,SAAS,YAAY,OAAO,OAAO,aAAa,UAAU,OAAO;EACnF,IAAI,CAAC,OAAO,QAAQ,CAAC,OAAO,UAAU,OAAO;EAE7C,OAAO;GAAE,MAAM,OAAO;GAAM,UAAU,OAAO;EAAS;CAC1D,QAAQ;EAIJ,OAAO;CACX;AACJ;AAEA,SAAgB,kBAAkB,aAAqB,QAA4B;CAC/E,MAAM,OAAO,kBAAkB,WAAW;CAC1C,GAAG,UAAU,KAAK,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;CACpD,GAAG,cAAc,MAAM,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,KAAK,OAAO;AAC1E;;AAGA,SAAgB,kBAAkB,aAA2B;CACzD,GAAG,OAAO,kBAAkB,WAAW,GAAG,EAAE,OAAO,KAAK,CAAC;AAC7D;;;;;;;;;;;;AAaA,SAAgB,UAAU,SAAiB,UAAiC;CACxE,IAAI;EACA,MAAM,MAAM,IAAI,IAAI,OAAO;EAG3B,IAAI,WAAW,IAAI;EAEnB,OAAO,IAAI,SAAS;CACxB,QAAQ;EACJ,OAAO;CACX;AACJ;;AAGA,SAAgB,eAAe,kBAAyC;CACpE,IAAI;EAGA,OAFa,IAAI,IAAI,gBAAgB,CAAC,CAAC,SAAS,QAAQ,OAAO,EAExD,KAAQ;CACnB,QAAQ;EACJ,OAAO;CACX;AACJ"}
package/dist/bundle.d.ts CHANGED
@@ -37,6 +37,11 @@ export interface BuildBundleOptions {
37
37
  skipSchema?: boolean;
38
38
  /** Emit progress. */
39
39
  log?: (message: string) => void;
40
+ /**
41
+ * Keep stdout for the caller's result: the compiler's output, and every
42
+ * warning the build prints, go to stderr. See `toolStdio`.
43
+ */
44
+ quietStdout?: boolean;
40
45
  }
41
46
  export interface BuildBundleResult {
42
47
  outDir: string;
@@ -247,6 +252,11 @@ export interface ComposeManifestInput {
247
252
  * declared bucket arriving as nothing, with both suites green.
248
253
  */
249
254
  export declare function composeBundleManifest(input: ComposeManifestInput): RebaseBundleManifest;
255
+ /**
256
+ * What a build refusing on {@link detectDeclaredDepConflicts} says: every name,
257
+ * both ranges and where each is declared.
258
+ */
259
+ export declare function describeDepConflicts(conflicts: DeclaredDepConflict[]): string;
250
260
  export declare function buildBundle(options: BuildBundleOptions): Promise<BuildBundleResult>;
251
261
  /** Default install target: what the published runtime image runs. */
252
262
  export declare const VENDOR_TARGET_OS = "linux";
@@ -394,8 +404,10 @@ export declare function foldStaticIntoBundle(options: {
394
404
  assetsDir: string;
395
405
  /** The app's name in `rebase.json`. Names its directory inside the bundle. */
396
406
  appName: string;
397
- /** Public base path this app is served under. */
407
+ /** Public base path this app is served under. Always a path, never a URL. */
398
408
  path: string;
409
+ /** The one hostname this app answers on, when its manifest `path` names one. */
410
+ host?: string;
399
411
  /** Serve `index.html` for unmatched paths under `path`. */
400
412
  spa: boolean;
401
413
  /** Where this app mounts the Rebase CMS, if it does. */
@@ -410,8 +422,10 @@ export declare function buildStaticBundle(options: {
410
422
  assetsDir: string;
411
423
  outDir: string;
412
424
  runtimeRange: string;
413
- /** Public base path. Default `/` — a standalone bundle owns its origin. */
425
+ /** Public base path. Default `/` — a standalone bundle owns its origin. Always a path. */
414
426
  path?: string;
427
+ /** The one hostname this app answers on, when its manifest `path` names one. */
428
+ host?: string;
415
429
  /** Serve `index.html` for unmatched paths. Default `true`. */
416
430
  spa?: boolean;
417
431
  /** Where this app mounts the Rebase CMS, if it does. */
package/dist/cli.d.ts CHANGED
@@ -18,6 +18,45 @@ export declare const ROOT_FLAGS: {
18
18
  readonly "-v": "--version";
19
19
  readonly "-h": "--help";
20
20
  };
21
+ /**
22
+ * The subcommand in the words after a command, read against the subcommands the
23
+ * group dispatches.
24
+ *
25
+ * The first word that is not a flag is not always the subcommand: after a flag
26
+ * that takes a value it is that value. `rebase db --collections ./c push` was
27
+ * refused as an unknown db command `./c`, `rebase api-keys --name ci create` as
28
+ * one called `ci`, and `rebase skills --agent claude install` as `claude` —
29
+ * lines every one of those commands parses happily once it is reached.
30
+ *
31
+ * Which flags take a value is not known at this level, so the vocabulary decides
32
+ * instead: a word the group dispatches is the subcommand; a word straight after
33
+ * a flag (and not glued to it with `=`) may be that flag's value and is passed
34
+ * over. When no word is a known subcommand, the first word is returned as
35
+ * before, so a typo — `rebase db psuh`, `rebase db --dry-run psuh` — still
36
+ * reaches the group and is refused by name. A command with no vocabulary keeps
37
+ * the first word.
38
+ *
39
+ * Exported for its tests.
40
+ */
41
+ export declare function resolveSubcommand(after: readonly string[], known: readonly string[]): string | undefined;
42
+ /**
43
+ * The command and subcommand words as `cli.error` may send them: each one is a
44
+ * word this CLI dispatches, `"none"` when nothing was typed, or `"other"`.
45
+ *
46
+ * The words come from what was typed, and what is typed after a command is
47
+ * only sometimes a subcommand. `rebase init acme-payroll-internal`, `rebase
48
+ * cloud --project acme-prod deploy` and `rebase db psuh` put a project name, a
49
+ * slug and a typo in the subcommand's position — the consent screen promises
50
+ * "never project names", and `sanitize` cannot tell one of those from a
51
+ * subcommand because neither has a separator in it. So the words are held
52
+ * against the vocabulary here, where it is known, and nothing else survives.
53
+ *
54
+ * Exported for `cli.test.ts`.
55
+ */
56
+ export declare function telemetryCommandWords(command: string | undefined, subcommand: string | undefined): {
57
+ command: string;
58
+ subcommand: string;
59
+ };
21
60
  export declare function entry(args: string[]): Promise<void>;
22
61
  /** The global help. Exported so its Options block can be held against {@link ROOT_FLAGS}. */
23
62
  export declare function printHelp(): void;
@@ -0,0 +1,13 @@
1
+ export interface ParsedCommandSpec {
2
+ /** The command words, as the call names them: `"build"`, `"skills install"`. */
3
+ command: string;
4
+ /** Canonical long flags: the value is a type, not another flag's name. */
5
+ flags: string[];
6
+ /** Every spelling the parser accepts, aliases and short flags included. */
7
+ accepted: string[];
8
+ file: string;
9
+ }
10
+ /** The parser calls in one file. Throws on a call it cannot read, so a new shape fails loudly. */
11
+ export declare function parsedCommands(file: string): ParsedCommandSpec[];
12
+ /** Every parser call under `src/` that the dispatch reaches: `cli.ts` and the command modules. */
13
+ export declare function allParsedCommands(commandsDir: string): ParsedCommandSpec[];
@@ -0,0 +1,116 @@
1
+ import { type AgentKey, type LoadedSkill } from "./skills.js";
2
+ import { type PackageManager } from "../utils/package-manager.js";
3
+ /** The name the server is registered under, in every config. */
4
+ export declare const MCP_SERVER_NAME = "rebase";
5
+ /** The MCP server's package: a devDependency of the project, pinned with the rest. */
6
+ export declare const MCP_PACKAGE = "@rebasepro/mcp";
7
+ /** The bin {@link MCP_PACKAGE} declares. */
8
+ export declare const MCP_BIN = "rebase-mcp";
9
+ /** The command an assistant spawns, and its arguments. */
10
+ export interface McpLaunch {
11
+ command: string;
12
+ args: string[];
13
+ }
14
+ /**
15
+ * How an assistant starts the Rebase MCP server: the project's own copy, through
16
+ * the project's package manager.
17
+ *
18
+ * Not `npx -y @rebasepro/mcp`, which fetched the newest release on every first
19
+ * start. The server drives the project's own CLI (`pnpm exec rebase …`) and calls
20
+ * the project's own backend (`/api/admin/schema/plan`, …), whose versions the
21
+ * lockfile pins — so a server from the registry ran ahead of both, at every
22
+ * start, and downloaded before it could answer. `@rebasepro/mcp` is a
23
+ * devDependency of the scaffold, pinned to the CLI's version like every other
24
+ * `@rebasepro` package, and this runs that copy.
25
+ *
26
+ * `npx --no`, not `npx`: an assistant spawns the server with no TTY, and npx
27
+ * then assumes "yes" and installs a missing package from the registry under the
28
+ * name it was given. `--no` makes a missing install an error instead.
29
+ */
30
+ export declare function mcpLaunch(pm: PackageManager): McpLaunch;
31
+ /** What writing one MCP config did. */
32
+ export type McpWriteStatus =
33
+ /** The file was created, or the server was added beside the ones in it. */
34
+ "added"
35
+ /** A `rebase` server was already there. It is left exactly as it was. */
36
+ | "present"
37
+ /** The file exists but is not something this can edit without losing data. */
38
+ | "unreadable";
39
+ export interface McpWriteResult {
40
+ /** Project-relative path of the config file. */
41
+ file: string;
42
+ status: McpWriteStatus;
43
+ }
44
+ /**
45
+ * The Codex block, as TOML. Appended rather than merged: there is no TOML
46
+ * parser here, and an append keeps every byte already in the file.
47
+ */
48
+ export declare function renderCodexServer(projectDir: string, launch: McpLaunch): string;
49
+ /**
50
+ * Register the Rebase MCP server in the agent's project-level config, started
51
+ * through the project's package manager (see {@link mcpLaunch}).
52
+ *
53
+ * Returns null for an agent with no project-level config to write.
54
+ */
55
+ export declare function writeMcpConfig(agentKey: AgentKey, projectDir: string, pm?: PackageManager): McpWriteResult | null;
56
+ /** What making sure the project depends on the MCP server did. */
57
+ export type McpDependencyStatus =
58
+ /** Added to `devDependencies`, at this CLI's version: an install is due. */
59
+ "added"
60
+ /** Already a dependency. Left at the version the project chose. */
61
+ | "present"
62
+ /** No `package.json`, or one that is not plain JSON: left alone. */
63
+ | "unreadable";
64
+ /**
65
+ * Make the project depend on {@link MCP_PACKAGE}, which the config written by
66
+ * {@link writeMcpConfig} runs from the project's own install.
67
+ *
68
+ * Pinned to this CLI's version, as `rebase init` pins every `@rebasepro`
69
+ * package; a project that already lists it keeps its own choice.
70
+ */
71
+ export declare function ensureMcpDependency(projectDir: string): McpDependencyStatus;
72
+ /**
73
+ * Point the scaffold's `.mcp.json` at the project's package manager.
74
+ *
75
+ * The template ships the pnpm spelling (`pnpm exec rebase-mcp`); an npm project
76
+ * has no pnpm to run it with. Only the entry the template wrote is rewritten.
77
+ */
78
+ export declare function retargetScaffoldMcpConfig(projectDir: string, pm: PackageManager): void;
79
+ /**
80
+ * Whether the agent's project-level config already registers the Rebase
81
+ * server: `null` for an agent that has no such config, `false` when the file
82
+ * is missing or does not name it. Reads only — for the hint `rebase skills
83
+ * install` prints when it was not asked to write one.
84
+ */
85
+ export declare function mcpServerRegistered(agentKey: AgentKey, projectDir: string): boolean | null;
86
+ /** What `configureAgents` did for one agent. */
87
+ export interface AgentSetupResult {
88
+ agent: AgentKey;
89
+ /** Skills written, or null when the bundle could not be loaded. */
90
+ skills: number | null;
91
+ /** An earlier agent in the same run that already wrote the skills directory. */
92
+ sharedWith?: AgentKey;
93
+ mcp: McpWriteResult | null;
94
+ }
95
+ /**
96
+ * Install the skills and register the MCP server for each agent.
97
+ *
98
+ * Never throws for a missing skills bundle — the scaffold it runs inside must
99
+ * not fail over its assistants — and reports it as `skills: null` instead.
100
+ */
101
+ export declare function configureAgents(agents: readonly AgentKey[], projectDir: string, load?: () => LoadedSkill[], pm?: PackageManager): {
102
+ results: AgentSetupResult[];
103
+ skillsError?: string;
104
+ mcpDependency?: McpDependencyStatus;
105
+ };
106
+ /** The line to print when {@link ensureMcpDependency} changed or could not change the manifest. */
107
+ export declare function mcpDependencyNote(status: McpDependencyStatus | undefined, pm: PackageManager): string | undefined;
108
+ /** One line per agent, for the scaffold's output. */
109
+ export declare function printAgentSetup({ results, skillsError, mcpDependency }: ReturnType<typeof configureAgents>, pm?: PackageManager): void;
110
+ /**
111
+ * Ask whether to set up AI agents, then which, pre-ticking what is installed.
112
+ *
113
+ * Interactive only; the caller has already refused a non-TTY. Returns [] when
114
+ * the developer says no or unticks everything.
115
+ */
116
+ export declare function promptForAgents(home?: string): Promise<AgentKey[]>;
@@ -1,38 +1,92 @@
1
+ import { type ApiKeyMasked, type ScopeSummary } from "@rebasepro/types";
2
+ /** Everything the switch below dispatches, for the did-you-mean. */
3
+ export declare const API_KEYS_SUBCOMMANDS: readonly ["list", "get", "create", "revoke", "scopes"];
4
+ /**
5
+ * What to print when a request fails: the server's error code and message,
6
+ * which is what says why — `SCOPE_EXCEEDS_CREATOR`, `INVALID_SCOPES`,
7
+ * `ROLE_EXCEEDS_CREATOR`, `KEY_MANAGEMENT_SCOPE` — and a hint where one helps.
8
+ *
9
+ * Exported so its tests can read the lines without a server.
10
+ */
11
+ export declare function describeFailure(action: string, error: unknown, baseUrl: string): string[];
1
12
  export declare function apiKeysCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void>;
13
+ /**
14
+ * The lines that describe one key: what it is, what it may do and whom it
15
+ * runs as.
16
+ *
17
+ * A service key runs as the RLS role `service` plus its own `roles`; a
18
+ * personal key runs as its owner's roles as they are when it is used, so it
19
+ * has none of its own to show.
20
+ *
21
+ * Exported so its tests can read the lines without a server.
22
+ */
23
+ export declare function describeKey(key: ApiKeyMasked, now?: Date): string[];
24
+ /** The flags `rebase api-keys list` takes: none of its own. */
25
+ export declare const LIST_KEYS_FLAGS: {};
26
+ /** The flags `rebase api-keys get` takes. */
27
+ export declare const GET_KEY_FLAGS: {
28
+ readonly "--id": StringConstructor;
29
+ };
30
+ /**
31
+ * Which key this invocation names, as a positional or as `--id`.
32
+ *
33
+ * Exported so its tests can drive the real parser rather than a copy of it.
34
+ */
35
+ export declare function resolveGetKeyArgs(rawArgs: string[]): {
36
+ id?: string;
37
+ };
2
38
  /** The flags `rebase api-keys create` takes. */
3
39
  export declare const CREATE_KEY_FLAGS: {
4
- readonly "--name": StringConstructor;
5
- readonly "--permissions": StringConstructor;
6
- readonly "--full-access": BooleanConstructor;
7
- readonly "--admin": BooleanConstructor;
8
- readonly "--rate-limit": NumberConstructor;
9
- readonly "--expires": StringConstructor;
10
- readonly "-n": "--name";
40
+ "--name": StringConstructor;
41
+ "--scopes": [StringConstructor];
42
+ "--full-access": BooleanConstructor;
43
+ "--roles": [StringConstructor];
44
+ "--rate-limit": NumberConstructor;
45
+ "--expires-in": StringConstructor;
46
+ "--expires-at": StringConstructor;
47
+ "-n": string;
11
48
  };
49
+ /**
50
+ * Options `create` refuses by name, each with the flag that does that job.
51
+ *
52
+ * Checked before the line is parsed: the strict parser would answer them
53
+ * "unknown option", which does not say what to type instead.
54
+ */
55
+ export declare const RETIRED_CREATE_OPTIONS: Readonly<Record<string, string>>;
56
+ /** What `rebase api-keys create` was asked to mint. */
57
+ export interface CreateKeyPlan {
58
+ name: string;
59
+ /** The scopes named with `--scopes`, or `"held"` for `--full-access`. */
60
+ scopes: string[] | "held";
61
+ /** RLS roles beside `service`. */
62
+ roles: string[];
63
+ rate_limit: number | null;
64
+ expires_at: string | null;
65
+ }
12
66
  /**
13
67
  * What this invocation asks to be created.
14
68
  *
15
69
  * The name may be given either way — `--name "My Key"` or as the single
16
70
  * positional — and under the old permissive parse an undeclared flag became
17
71
  * that positional: `rebase api-keys create --debug --full-access` created a
18
- * key called `--debug` with read/write/delete on every collection, and
19
- * `--debug` is what the CLI prints after every failure as the thing to re-run
20
- * with. Strict parsing makes the flag an error instead of a name.
72
+ * key called `--debug` with access to everything, and `--debug` is what the
73
+ * CLI prints after every failure as the thing to re-run with. Strict parsing
74
+ * makes the flag an error instead of a name.
75
+ *
76
+ * What the key may do has to be asked for by name — `--scopes` or
77
+ * `--full-access` — never defaulted: a forgotten flag must not mint a key that
78
+ * reaches everything.
21
79
  *
22
80
  * Exported so its tests can drive the real parser rather than a copy of it.
23
81
  */
24
- export declare function resolveCreateKeyArgs(rawArgs: string[]): {
25
- flags: import("arg").Result<{
26
- readonly "--name": StringConstructor;
27
- readonly "--permissions": StringConstructor;
28
- readonly "--full-access": BooleanConstructor;
29
- readonly "--admin": BooleanConstructor;
30
- readonly "--rate-limit": NumberConstructor;
31
- readonly "--expires": StringConstructor;
32
- readonly "-n": "--name";
33
- }>;
34
- name: string;
35
- };
82
+ export declare function resolveCreateKeyArgs(rawArgs: string[], now?: Date): CreateKeyPlan;
83
+ /**
84
+ * The scopes `--full-access` puts on a key: every one the caller holds, less
85
+ * key management, which no key may hold.
86
+ *
87
+ * Exported so its tests can check the subtraction without a server.
88
+ */
89
+ export declare function grantableScopes(held: readonly string[]): string[];
36
90
  /** The flags `rebase api-keys revoke` takes. */
37
91
  export declare const REVOKE_KEY_FLAGS: {
38
92
  readonly "--id": StringConstructor;
@@ -50,3 +104,12 @@ export declare const REVOKE_KEY_FLAGS: {
50
104
  export declare function resolveRevokeKeyArgs(rawArgs: string[]): {
51
105
  id?: string;
52
106
  };
107
+ /** The flags `rebase api-keys scopes` takes: none of its own. */
108
+ export declare const SCOPES_LIST_FLAGS: {};
109
+ /**
110
+ * The scope catalogue as printed lines: one section per plane, each scope with
111
+ * its label and what its target names, marked when the caller holds it.
112
+ *
113
+ * Exported so its tests can read the lines without a server.
114
+ */
115
+ export declare function describeScopes(scopes: readonly ScopeSummary[], held: readonly string[]): string[];
@@ -1 +1,20 @@
1
+ import type { RebaseAppConfig } from "@rebasepro/types";
2
+ import { loadManifest } from "../manifest.js";
3
+ /** Everything the switch below dispatches, for the did-you-mean. */
4
+ export declare const APPS_SUBCOMMANDS: readonly ["list", "init", "config"];
1
5
  export declare function appsCommand(subcommand: string | undefined, rawArgs?: string[]): Promise<void>;
6
+ /**
7
+ * One app's line in `rebase apps list`.
8
+ *
9
+ * A static app shows its full address — the https URL when its `path` gives it
10
+ * a hostname — and the CMS as the address a browser would open. `CMS at /` on
11
+ * an app that lives on `admin.example.com` reads as the project's own root,
12
+ * which is the one place that CMS is not.
13
+ */
14
+ export declare function describeApp(name: string, app: RebaseAppConfig): string;
15
+ /**
16
+ * Whether `rebase build` folds this static app into the backend bundle, which
17
+ * then serves it on the API's own origin: a managed backend, and an app with
18
+ * built output to fold. The same predicate the build folds by.
19
+ */
20
+ export declare function servedByBackend(manifest: ReturnType<typeof loadManifest>["manifest"], appName: string): boolean;
@@ -1,3 +1,5 @@
1
+ /** Everything the switch below dispatches, for the did-you-mean. */
2
+ export declare const AUTH_SUBCOMMANDS: readonly ["reset-password"];
1
3
  /** A user as the admin API returns it, reduced to what this command needs. */
2
4
  export interface ResolvedUser {
3
5
  id: string;
@@ -74,3 +76,20 @@ export declare function resolveResetPasswordArgs(rawArgs: string[]): {
74
76
  * hazard, and nothing that reads like a placeholder somebody might keep.
75
77
  */
76
78
  export declare function generatePassword(): string;
79
+ /**
80
+ * The script the direct-database fallback runs under the project's own tsx, so
81
+ * it resolves the project's `@rebasepro/server-postgres` and schema.
82
+ *
83
+ * It ends the account's sessions in the transaction that sets the password,
84
+ * as every door through the API does (`replaceUserPassword`): the refresh
85
+ * tokens and outstanding reset links go, and `tokens_valid_after` voids the
86
+ * access tokens already handed out. An operator resetting a phished account
87
+ * with the backend down is the case this exists for, and a reset that left the
88
+ * attacker's refresh token minting access tokens did not recover anything.
89
+ *
90
+ * It exits 0 only when a row was updated: a missing user and a thrown error are
91
+ * both exit 1. `echoPassword` prints the new password, for a generated one.
92
+ *
93
+ * Exported so its tests can run it.
94
+ */
95
+ export declare function resetPasswordScript(echoPassword: boolean): string;
@@ -33,5 +33,17 @@ export declare function buildCommand(rawArgs?: string[]): Promise<void>;
33
33
  * packages that output into a `static`-kind bundle — the same deployable shape as
34
34
  * a backend bundle, so a frontend or admin app deploys through the identical
35
35
  * path and runs on the identical image, just serving files instead of an API.
36
+ *
37
+ * Throws when the build fails or produces nothing usable, so the caller answers
38
+ * in its own way: `rebase build` with a red line, `rebase cloud deploy --json`
39
+ * with its JSON error.
40
+ */
41
+ export declare function buildAssetApp(projectRoot: string, name: string, app: RebaseAppConfig, runtimeRange: string, outOverride?: string,
42
+ /**
43
+ * `quietStdout`: every line, the build command's included, goes to stderr. See `toolStdio`.
44
+ * `builtApps`: the static apps already built in this run (see `FoldOptions.builtApps`).
36
45
  */
37
- export declare function buildAssetApp(projectRoot: string, name: string, app: RebaseAppConfig, runtimeRange: string, outOverride?: string): Promise<string | undefined>;
46
+ options?: {
47
+ quietStdout?: boolean;
48
+ builtApps?: Set<string>;
49
+ }): Promise<string | undefined>;
@@ -20,9 +20,10 @@ export declare const LOGIN_FLAGS: {
20
20
  * neither is something this CLI can redact after the fact — the same reasoning
21
21
  * `rls-check` states for its connection string, which carries one too.
22
22
  *
23
- * There is no machine token yet, so CI genuinely does need a human's password;
24
- * `REBASE_CLOUD_PASSWORD` is how a secret store hands it over without it
25
- * appearing on a command line.
23
+ * CI should not need a password at all: `rebase cloud tokens create` mints a
24
+ * token narrowed to one project, and `REBASE_TOKEN` hands it to every cloud
25
+ * command. Where a login is still wanted, `REBASE_CLOUD_PASSWORD` is how a
26
+ * secret store hands the password over without it appearing on a command line.
26
27
  */
27
28
  export declare const PASSWORD_ENV = "REBASE_CLOUD_PASSWORD";
28
29
  export declare const EMAIL_ENV = "REBASE_CLOUD_EMAIL";
@@ -2,15 +2,44 @@ import type { RebaseBundleManifest } from "@rebasepro/types";
2
2
  import type { RebuildSource } from "./rebuild-source.js";
3
3
  /** Read and shallow-validate a built bundle's manifest. */
4
4
  export declare function readBundleManifest(bundleDir: string): RebaseBundleManifest;
5
+ /**
6
+ * The control plane's cap on an uploaded bundle: its `MAX_BUNDLE_BYTES`, which
7
+ * it checks before reading the body.
8
+ */
9
+ export declare const MAX_BUNDLE_UPLOAD_BYTES: number;
5
10
  /**
6
11
  * Tar a built bundle into a gzipped archive.
7
12
  *
8
- * `node_modules` is excluded on purpose: the bundle ships a `package.json`, and
9
- * the managed runtime installs the declared dependencies at boot. Uploading an
10
- * installed `node_modules` would bloat the archive and could carry a
11
- * platform-specific build that will not run on the runtime image.
13
+ * `node_modules` goes in only with `withModules`: a tree the build vendored for
14
+ * the runtime's platform is the point of vendoring, while one installed into a
15
+ * prebuilt bundle by hand was installed for whatever machine ran it.
16
+ */
17
+ export declare function packBundle(bundleDir: string, outPath: string, options?: {
18
+ withModules?: boolean;
19
+ }): Promise<void>;
20
+ /**
21
+ * Pack a bundle for upload — without `node_modules`, even a vendored tree.
22
+ *
23
+ * Vendoring exists so a pod untars and boots rather than spending 35-55s of
24
+ * every start in `npm install`, and a deploy did carry the tree for one night
25
+ * (c36ea4637). It is left out again because of what the control plane does
26
+ * with the archive: `GET /bundle/:projectId/:bundleId` reads the whole object
27
+ * into memory on every pod start, and a runtime rollout restarts every tenant's
28
+ * pods at once. Bundles it was sized against are a few hundred kB; a vendored
29
+ * one is tens of MB, up to the 100 MB cap — N pods starting together would hold
30
+ * N of them. A slower cold start per pod is the status quo every deploy has
31
+ * shipped with; a control plane out of memory is every tenant's outage. The
32
+ * platform's own rebuilds build with `--no-vendor` for the same shape of
33
+ * reason. When the control plane streams bundles, this is the one switch to
34
+ * flip, and `rebase cloud deploy` builds with `vendor: false` until then.
35
+ *
36
+ * `modulesLeftOut` says a tree the build DID vendor was not uploaded — a
37
+ * prebuilt `--bundle-dir` from a plain `rebase build`, which vendors by default.
12
38
  */
13
- export declare function packBundle(bundleDir: string, outPath: string): Promise<void>;
39
+ export declare function packBundleForUpload(bundleDir: string, outPath: string, manifest: RebaseBundleManifest, maxBytes?: number): Promise<{
40
+ bytes: number;
41
+ modulesLeftOut: boolean;
42
+ }>;
14
43
  /**
15
44
  * Assemble the deploy-trigger body for a bundle deploy.
16
45
  *
@@ -97,3 +126,48 @@ export declare function declaredAppsFrom(manifest: {
97
126
  } | null | undefined): DeclaredApp[];
98
127
  /** Upload a bundle archive; returns the control-plane bundle id. */
99
128
  export declare function uploadBundle(url: string, token: string, projectId: string, tarPath: string): Promise<string>;
129
+ /** One DNS record a hostname needs, as the control plane lists it. */
130
+ export interface DeployHostRecord {
131
+ type: string;
132
+ name: string;
133
+ values: string[];
134
+ }
135
+ /**
136
+ * A hostname an app in this deploy is declared on, as the deploy found it.
137
+ *
138
+ * The control plane registers each one on the project as it deploys — an app
139
+ * whose `path` is `https://admin.example.com` needs that host on the project
140
+ * before anything can route it — and a new one starts `pending`, because it is
141
+ * served only once its DNS is published and verified. `records` is what to
142
+ * publish, present for a pending host.
143
+ */
144
+ export interface DeployHost {
145
+ host: string;
146
+ status: "verified" | "pending";
147
+ records?: DeployHostRecord[];
148
+ }
149
+ /**
150
+ * The `hosts` a deploy response carries, read defensively.
151
+ *
152
+ * `undefined` when there is no such field, which is what a control plane that
153
+ * predates host-routed apps answers: the caller then leaves `hosts` out of its
154
+ * own output rather than reporting an empty set nobody looked for. An entry
155
+ * with no hostname is dropped, and any status but `verified` is pending — the
156
+ * same rule `cloud domains` reads rows by, because an unreadable status must
157
+ * not print as live.
158
+ */
159
+ export declare function deployHostsFrom(response: unknown): DeployHost[] | undefined;
160
+ /**
161
+ * What to tell somebody whose deploy declared a hostname that is not live yet.
162
+ *
163
+ * A deploy that succeeds with an app on a hostname nobody can reach reads as a
164
+ * broken deploy, so each pending host gets its own block: that it is registered
165
+ * but waiting, the records to create, and the command that finishes the job.
166
+ * The records come from the control plane, never composed here — A or CNAME
167
+ * depends on apex-vs-subdomain and on the ingress behind the project, which
168
+ * the CLI cannot know. Plain text: the caller colours it.
169
+ */
170
+ export declare function pendingHostNotices(hosts: DeployHost[]): Array<{
171
+ headline: string;
172
+ details: string[];
173
+ }>;