@rebasepro/cli 0.12.1-canary.gf5f1d39 → 0.13.1-canary.g06dbe5b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/bin/rebase.js +27 -1
  2. package/dist/bundle.d.ts +40 -3
  3. package/dist/commands/api-keys.d.ts +51 -0
  4. package/dist/commands/auth.d.ts +62 -0
  5. package/dist/commands/cloud/context.d.ts +134 -7
  6. package/dist/commands/cloud/databases.d.ts +39 -0
  7. package/dist/commands/cloud/debug.d.ts +1 -0
  8. package/dist/commands/cloud/deploy.d.ts +64 -0
  9. package/dist/commands/cloud/deployments.d.ts +22 -0
  10. package/dist/commands/cloud/domains.d.ts +10 -0
  11. package/dist/commands/cloud/env.d.ts +51 -0
  12. package/dist/commands/cloud/extensions.d.ts +21 -0
  13. package/dist/commands/cloud/index.d.ts +23 -0
  14. package/dist/commands/cloud/orgs.d.ts +1 -0
  15. package/dist/commands/cloud/projects.d.ts +61 -1
  16. package/dist/commands/cloud/resources.d.ts +14 -0
  17. package/dist/commands/cloud/settings.d.ts +1 -0
  18. package/dist/commands/dev.d.ts +27 -0
  19. package/dist/commands/eject.d.ts +42 -0
  20. package/dist/commands/init.d.ts +67 -0
  21. package/dist/commands/skills.d.ts +81 -0
  22. package/dist/commands/telemetry.d.ts +9 -0
  23. package/dist/fold-static.d.ts +47 -0
  24. package/dist/index.es.js +2411 -481
  25. package/dist/index.es.js.map +1 -1
  26. package/dist/manifest.d.ts +16 -1
  27. package/dist/telemetry/consent.d.ts +38 -0
  28. package/dist/telemetry/identity.d.ts +69 -0
  29. package/dist/telemetry/index.d.ts +72 -0
  30. package/dist/telemetry/payload.d.ts +78 -0
  31. package/dist/telemetry/project.d.ts +34 -0
  32. package/dist/utils/args.d.ts +76 -0
  33. package/dist/utils/collection-drift.d.ts +27 -0
  34. package/dist/utils/project.d.ts +20 -0
  35. package/package.json +11 -11
  36. package/templates/eject/Dockerfile +29 -4
  37. package/templates/eject/backend/src/index.ts +49 -5
  38. package/templates/eject/docker-compose.custom.yml +13 -5
  39. package/templates/overlays/baas/backend/package.json +2 -2
  40. package/templates/overlays/baas/backend/tsconfig.json +6 -1
  41. package/templates/overlays/baas/package.json +1 -2
  42. package/templates/template/.env.example +13 -4
  43. package/templates/template/backend/functions/hello.ts +8 -4
  44. package/templates/template/backend/package.json +2 -2
  45. package/templates/template/backend/tsconfig.json +6 -1
  46. package/templates/template/config/collections/index.ts +9 -1
  47. package/templates/template/config/package.json +1 -0
  48. package/templates/template/docker-compose.yml +4 -4
  49. package/templates/template/frontend/package.json +3 -3
  50. package/templates/template/frontend/src/App.tsx +2 -1
  51. package/templates/template/frontend/src/main.tsx +2 -1
  52. package/templates/template/frontend/vite.config.ts +0 -1
  53. package/templates/template/package.json +1 -2
package/bin/rebase.js CHANGED
@@ -88,4 +88,30 @@ if (!existsSync(distEntry)) {
88
88
 
89
89
  const { entry } = await import("../dist/index.es.js");
90
90
 
91
- entry(process.argv);
91
+ /**
92
+ * The CLI's last line of defence.
93
+ *
94
+ * `entry()` returns a promise and nothing was awaiting it, so anything a
95
+ * command threw surfaced as an unhandled rejection: Node's own stack trace,
96
+ * rooted in `dist/index.es.js`, with the CLI's bundled line numbers and no
97
+ * exit code of its own. "Collections directory not found" is a sentence a
98
+ * developer can act on; the same sentence under ten frames of bundle internals
99
+ * reads as a crash in Rebase.
100
+ *
101
+ * The message is the error's own — commands that already print something
102
+ * friendly and exit never reach here. The stack is available behind
103
+ * `--debug`/`REBASE_DEBUG`, because when the message is *not* enough that is
104
+ * the only thing that helps.
105
+ */
106
+ const wantsStack = process.argv.includes("--debug") || process.env.REBASE_DEBUG === "1";
107
+
108
+ entry(process.argv).catch((error) => {
109
+ const message = error instanceof Error ? error.message : String(error);
110
+ process.stderr.write(`\x1b[31m✗ ${message}\x1b[0m\n`);
111
+ if (wantsStack && error instanceof Error && error.stack) {
112
+ process.stderr.write(`\n${error.stack}\n`);
113
+ } else {
114
+ process.stderr.write("\x1b[90m Re-run with --debug for the stack trace.\x1b[0m\n");
115
+ }
116
+ process.exit(1);
117
+ });
package/dist/bundle.d.ts CHANGED
@@ -68,6 +68,41 @@ export declare function detectNativeDependencies(projectRoot: string, declared:
68
68
  * own config package already travels inside the bundle.
69
69
  */
70
70
  export declare function collectDeclaredDependencies(projectRoot: string): Record<string, string>;
71
+ /** One `@rebasepro/*` dependency as some package.json in the project declares it. */
72
+ export interface DeclaredFrameworkDep {
73
+ name: string;
74
+ range: string;
75
+ /** Project-relative package.json it was declared in. */
76
+ file: string;
77
+ }
78
+ export interface FrameworkDepDrift {
79
+ /** Declared at a version that can never reach the CLI's own. */
80
+ behind: DeclaredFrameworkDep[];
81
+ /**
82
+ * The distinct lower bounds found across all declared `@rebasepro/*`, when
83
+ * there is more than one — the project is pinning mixed-era framework
84
+ * packages against each other.
85
+ */
86
+ disagreeing: string[];
87
+ }
88
+ /**
89
+ * Find `@rebasepro/*` dependencies pinned to a version older than this CLI.
90
+ *
91
+ * This is the only place a developer can be told. In development, every
92
+ * `@rebasepro/*` resolves through pnpm's `link:`/`workspace:` overrides to the
93
+ * checkout, so the version STRINGS in package.json are never exercised — the
94
+ * project runs fine locally on whatever is on disk, and the declared numbers are
95
+ * first honoured when the runtime npm-installs them from a bundle in the cloud.
96
+ * A project scaffolded at 0.10.0 therefore keeps working on a developer's
97
+ * machine indefinitely while being, in the cloud, a 0.10.0 driver.
98
+ *
99
+ * That matters because the image supplies only `@rebasepro/server`; the database
100
+ * driver comes from these declarations and a newer runtime never updates it.
101
+ * Every package.json is scanned, `dependencies` and `devDependencies` both,
102
+ * because they have to be bumped together and the one that gets forgotten is the
103
+ * one nobody looks at.
104
+ */
105
+ export declare function detectFrameworkDepDrift(projectRoot: string, cliVersion: string): FrameworkDepDrift;
71
106
  /**
72
107
  * Rewrite relative import specifiers in emitted JavaScript so Node can resolve them.
73
108
  *
@@ -101,10 +136,11 @@ export declare function normalizeEsmSpecifiers(outDir: string): {
101
136
  * deployed green, and answered 404 on every one of them, with the file still
102
137
  * sitting in the repository looking exactly like the server.
103
138
  *
104
- * A project that means to keep its own entrypoint runs `rebase eject`, which
105
- * writes the entrypoint, a Dockerfile and a compose file together and flips the
139
+ * A project that means to own its server process runs `rebase eject`, which
140
+ * writes an entrypoint, a Dockerfile and a compose file together and flips the
106
141
  * backend to `runtime: "custom"`. The warning names that route rather than
107
- * implying the file is a mistake.
142
+ * implying the file is a mistake — but eject writes *its* entrypoint, so the
143
+ * warning must not read as "eject will keep what you wrote here".
108
144
  */
109
145
  export declare function findUnusedServerEntry(projectRoot: string, functionsDir: string): string | undefined;
110
146
  /**
@@ -182,3 +218,4 @@ export declare function buildStaticBundle(options: {
182
218
  manifest: RebaseBundleManifest;
183
219
  fileCount: number;
184
220
  };
221
+ export declare function resolveCliVersion(): string;
@@ -1 +1,52 @@
1
1
  export declare function apiKeysCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void>;
2
+ /** The flags `rebase api-keys create` takes. */
3
+ 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";
11
+ };
12
+ /**
13
+ * What this invocation asks to be created.
14
+ *
15
+ * The name may be given either way — `--name "My Key"` or as the single
16
+ * positional — and under the old permissive parse an undeclared flag became
17
+ * 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.
21
+ *
22
+ * Exported so its tests can drive the real parser rather than a copy of it.
23
+ */
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
+ };
36
+ /** The flags `rebase api-keys revoke` takes. */
37
+ export declare const REVOKE_KEY_FLAGS: {
38
+ readonly "--id": StringConstructor;
39
+ };
40
+ /**
41
+ * Which key this invocation names.
42
+ *
43
+ * The id is a positional, so the permissive parse handed one straight to the
44
+ * DELETE: `rebase api-keys revoke --foo` sent
45
+ * `DELETE /api/admin/api-keys/--foo`, and `rebase --debug api-keys revoke <id>`
46
+ * shifted the words along and revoked the key named `revoke`.
47
+ *
48
+ * Exported so its tests can drive the real parser rather than a copy of it.
49
+ */
50
+ export declare function resolveRevokeKeyArgs(rawArgs: string[]): {
51
+ id?: string;
52
+ };
@@ -1 +1,63 @@
1
+ /** A user as the admin API returns it, reduced to what this command needs. */
2
+ export interface ResolvedUser {
3
+ id: string;
4
+ email: string;
5
+ }
6
+ /**
7
+ * Pick the user with exactly this email out of a search response.
8
+ *
9
+ * `/api/admin/users?search=` is an `ILIKE '%…%'` over email **or display
10
+ * name**, ordered by role count descending. This used to take row `[0]` and
11
+ * reset it, then print the email it had been *given* as confirmation — so two
12
+ * ordinary situations ended in a successful-looking reset of somebody else's
13
+ * account:
14
+ *
15
+ * - a substring collision: `bob@example.com` also matches
16
+ * `robert.bob@example.com`;
17
+ * - a display name, which is user-controlled and accepted up to 255
18
+ * characters with no constraint on its content, containing an address
19
+ * belonging to someone else.
20
+ *
21
+ * The ordering makes it worse rather than better — `array_length(roles) DESC
22
+ * NULLS LAST` puts the most privileged match first, so the account most likely
23
+ * to be reset by mistake is an admin's.
24
+ *
25
+ * Returns `undefined` when nothing matched exactly, which the caller reports
26
+ * rather than falling through to a guess. The direct-database fallback below
27
+ * has always matched with `eq(usersTable.email, email)`; this is the same
28
+ * definition, so the command no longer resets different accounts depending on
29
+ * whether the backend happened to be running.
30
+ */
31
+ export declare function selectUserForEmail(payload: unknown, email: string): ResolvedUser | undefined;
1
32
  export declare function authCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void>;
33
+ /**
34
+ * The flags `rebase auth reset-password` takes.
35
+ *
36
+ * `-p` was advertised in this command's own help and never declared here, so
37
+ * `arg` — running permissively — pushed it into the positionals and the value
38
+ * *after* it shifted out of reach: anyone following the help set the account's
39
+ * password to the two-character string `-p`. Declared now, and `auth.test.ts`
40
+ * asserts that the help and this spec list the same aliases.
41
+ */
42
+ export declare const RESET_PASSWORD_FLAGS: {
43
+ readonly "--email": StringConstructor;
44
+ readonly "--password": StringConstructor;
45
+ readonly "-e": "--email";
46
+ readonly "-p": "--password";
47
+ };
48
+ /**
49
+ * Which account, and which password, this invocation names.
50
+ *
51
+ * Both may still be absent — the caller reports a missing email — but neither
52
+ * can be a flag. `parseCommandArgs` parses the whole line strictly, so an
53
+ * undeclared flag is an error rather than a positional. That is what stops
54
+ * `rebase auth reset-password bob@example.com --debug` from setting Bob's
55
+ * password to `--debug`, which is the flag the CLI itself prints after every
56
+ * failure as the thing to re-run with.
57
+ *
58
+ * Exported so its tests can drive the real parser rather than a copy of it.
59
+ */
60
+ export declare function resolveResetPasswordArgs(rawArgs: string[]): {
61
+ email?: string;
62
+ password?: string;
63
+ };
@@ -1,3 +1,4 @@
1
+ import arg from "arg";
1
2
  import { createRebaseClient } from "@rebasepro/client";
2
3
  /** Project-local link file: <project>/.rebase/cloud.json */
3
4
  export declare function projectLinkPath(cwd?: string): string;
@@ -24,7 +25,32 @@ export declare function requireClient(rawArgs: string[]): Promise<{
24
25
  client: CloudClient;
25
26
  url: string;
26
27
  }>;
28
+ /** One place a deploy can actually land, as the control plane describes it. */
29
+ export interface DeployTarget {
30
+ clusterId?: string | null;
31
+ provider: string;
32
+ region?: string;
33
+ label?: string;
34
+ baseDomain?: string;
35
+ }
36
+ export interface PlatformConfig {
37
+ tenantBaseDomain?: string;
38
+ deployTargets?: DeployTarget[];
39
+ }
40
+ export declare function fetchPlatformConfig(client: CloudClient, url: string): Promise<PlatformConfig | undefined>;
41
+ /**
42
+ * The base domain tenant projects are served at, derived from the same
43
+ * TENANT_BASE_DOMAIN the ingress and the console read (see
44
+ * saas/backend/src/utils/tenant-domain.ts).
45
+ */
27
46
  export declare function fetchTenantBaseDomain(client: CloudClient, url: string): Promise<string | undefined>;
47
+ /**
48
+ * The infrastructure a deploy for this control plane would ACTUALLY use, in the
49
+ * resolver's own preference order (saas/backend/src/k8s/resolve.ts).
50
+ *
51
+ * @returns the targets, or `undefined` when the control plane cannot say.
52
+ */
53
+ export declare function fetchDeployTargets(client: CloudClient, url: string): Promise<DeployTarget[] | undefined>;
28
54
  /**
29
55
  * Public host for a project — `<subdomain>.<base>`, or the bare subdomain when
30
56
  * the base domain is unknown.
@@ -84,6 +110,39 @@ export interface ProjectLink {
84
110
  export declare function readLink(cwd?: string): ProjectLink | null;
85
111
  export declare function writeLink(link: ProjectLink, cwd?: string): void;
86
112
  export declare function removeLink(cwd?: string): boolean;
113
+ /**
114
+ * Flags that may appear anywhere on a `rebase cloud` line, including *before*
115
+ * the resource group.
116
+ *
117
+ * They have to be declared wherever positionals are resolved, because `arg`'s
118
+ * `permissive: true` does not merely tolerate an undeclared flag — it pushes it
119
+ * into `_` alongside the positionals, and for a flag that takes a value it
120
+ * pushes the value in too. So `cloud --project acme storage create` parsed
121
+ * without this spec yields `_` of `["--project", "acme", "storage", "create"]`,
122
+ * and the group reads as `"acme"`: a real project name, in the group position,
123
+ * dispatching to nothing. Skipping tokens that start with `-` does not save you
124
+ * there — the damage is the orphaned value, which looks exactly like a
125
+ * positional.
126
+ *
127
+ * Only genuinely global flags belong here. Group-specific ones (`--bucket`,
128
+ * `--region`, …) are declared by the handler that owns them and always follow
129
+ * the group, so they cannot shift the group or action.
130
+ *
131
+ * `-p` is `--project` in eighteen places and `--password` in `login`. That
132
+ * ambiguity does not matter to the one caller that reads this spec: it resolves
133
+ * positionals and never looks at a flag's value, so all it needs to know is
134
+ * that `-p` takes one. Anything that wants the value must keep declaring it
135
+ * itself, with the meaning its own command gives it.
136
+ */
137
+ export declare const GLOBAL_CLOUD_FLAGS: {
138
+ readonly "--json": BooleanConstructor;
139
+ readonly "--yes": BooleanConstructor;
140
+ readonly "--help": BooleanConstructor;
141
+ readonly "--project": StringConstructor;
142
+ readonly "-p": "--project";
143
+ readonly "-y": "--yes";
144
+ readonly "-h": "--help";
145
+ };
87
146
  /**
88
147
  * The raw project reference to operate on: explicit `--project` flag wins,
89
148
  * otherwise the linked project. Exits with guidance when neither is present.
@@ -134,6 +193,26 @@ export declare function printJson(value: unknown): void;
134
193
  * call is what guarantees a command can never print a table AND a JSON blob.
135
194
  */
136
195
  export declare function emit(human: () => void, json: unknown): void;
196
+ /**
197
+ * Print a warning (+ optional hint) — in every output mode, always to stderr.
198
+ *
199
+ * `emit` is for a command's *result*, and JSON mode legitimately replaces the
200
+ * human rendering of one. A warning is not a result: it says the command is
201
+ * about to do something the caller may not have meant, and that is exactly as
202
+ * true when the output is piped. Gating one on `!isJsonMode()` deleted it
203
+ * precisely where nobody was watching the terminal — a `--source` deploy ejected
204
+ * a live project off the managed runtime and said so only to a TTY that wasn't
205
+ * there.
206
+ *
207
+ * stdout carries the JSON value and nothing else, so warnings go to stderr:
208
+ * a machine parser reading stdout cannot be corrupted by one. Only the
209
+ * *formatting* may depend on the mode — colour and indentation for a terminal,
210
+ * plain ASCII otherwise. Whether a warning is emitted at all may not.
211
+ *
212
+ * Anything a caller might branch on belongs in the JSON payload as well; stderr
213
+ * is for whoever reads the transcript afterwards.
214
+ */
215
+ export declare function warn(message: string, hint?: string): void;
137
216
  /** Print an error (+ optional hint) and exit non-zero. Never returns. */
138
217
  export declare function fail(message: string, hint?: string, code?: string): never;
139
218
  /**
@@ -149,15 +228,63 @@ export declare function confirmDestructive(opts: {
149
228
  prompt: string;
150
229
  }): Promise<void>;
151
230
  /**
152
- * Positional tokens after `rebase cloud` — `[group, action, arg1, …]`.
231
+ * Resolve one cloud command's flags and ARGUMENTS from the full `process.argv`.
232
+ *
233
+ * This replaces `cloudPositionals`, which was `rawArgs.slice(3).filter(a =>
234
+ * !a.startsWith("-"))`. Dropping `-`-prefixed tokens looks like it solves the
235
+ * permissive-parse problem and does not: a flag that takes a VALUE leaves the
236
+ * value behind, an ordinary word in the argument position that no filter can
237
+ * tell from a real one. `--project` is the flag every one of these commands
238
+ * documents, so the failure was reachable from the help page:
239
+ *
240
+ * rebase cloud env unset -p acme → removed the variable "acme"
241
+ * rebase cloud env set KEY -p acme → stored the value "acme"
242
+ * rebase cloud domains add -p acme → registered the domain "acme"
243
+ * rebase cloud webhooks delete -p acme 42 → deleted webhook "acme", not 42
244
+ * rebase cloud cancel -p acme → cancelled deployment id "acme"
245
+ *
246
+ * The filter's other half is quieter. A flag nobody declared *is* dropped by
247
+ * it — but only from the operands, never from the run: nothing rejects it, so
248
+ * the command proceeds with the argument missing or defaulted. `db backup
249
+ * --dry-run` listed backups, `domains remove --dry-run` detached the domain,
250
+ * and `env set KEY=v --secrett` stored the value as an ordinary variable that
251
+ * `env reveal` will hand back. The one place an undeclared flag became the
252
+ * argument outright is `projects info|delete`, which resolved its id through
253
+ * `positionals()` instead — that skips only LEADING `-` tokens, so `projects
254
+ * delete --force` looked up a project named "--force".
255
+ *
256
+ * So: parse the whole line strictly, through the same `parseCommandArgs` the
257
+ * non-cloud commands use — `arg` then consumes each declared flag *with its
258
+ * value* wherever it appears, and rejects the undeclared, leaving `_` holding
259
+ * the command words followed by the real arguments. `commandWords` counts from
260
+ * `cloud` itself (`cloud env set` ⇒ 3), and is applied to the parsed
261
+ * positionals, so a flag written before the group shifts nothing.
262
+ *
263
+ * Two things this adds over calling `parseCommandArgs` directly, and the reason
264
+ * it is worth a wrapper:
153
265
  *
154
- * Deliberately NOT `arg({}, { permissive: true })._`: in permissive mode `arg`
155
- * pushes UNKNOWN FLAGS onto `_` too, so `rollback --yes --json` would report
156
- * `--yes` as the deployment id. Operand extraction must see operands only, so
157
- * anything starting with `-` is dropped — the same filter the db backup handler
158
- * has always used.
266
+ * - `GLOBAL_CLOUD_FLAGS` is merged in. `--json`, `--yes` and `--project` may
267
+ * appear anywhere on a cloud line including before the group, so a strict
268
+ * parse that did not declare them would reject the CLI's own documented
269
+ * usage. (`parseCommandArgs` adds `--debug`/`--help` on top of that.)
270
+ * - A parse error is reported through `fail`, not thrown. A throw reaches
271
+ * `bin/rebase.js`, which prints `✗ …` to stderr — which is right for every
272
+ * other command and wrong here: `rebase cloud` is in JSON mode whenever
273
+ * stdout is not a TTY, i.e. always for the agents this family is built for,
274
+ * and it promises them exactly one JSON value. `fail` keeps that promise,
275
+ * with the same `usage` code the other refusals in this family use.
159
276
  */
160
- export declare function cloudPositionals(rawArgs: string[]): string[];
277
+ export declare function parseCloudArgs<S extends arg.Spec>(opts: {
278
+ spec: S;
279
+ rawArgs: string[];
280
+ commandWords: number;
281
+ /** Names the command in errors, e.g. `cloud env set` (no leading `rebase`). */
282
+ command: string;
283
+ maxPositionals?: number;
284
+ }): {
285
+ flags: arg.Result<S & typeof GLOBAL_CLOUD_FLAGS>;
286
+ positionals: string[];
287
+ };
161
288
  export declare function success(message: string): void;
162
289
  /** Colorize a deployment / resource status token. */
163
290
  export declare function colorStatus(status: string | undefined): string;
@@ -1 +1,40 @@
1
+ /**
2
+ * `rebase cloud db` — database + backup management for a project.
3
+ *
4
+ * db list List databases attached to the project
5
+ * db create Attach a managed or bring-your-own database
6
+ * db test Test connectivity to the project's database
7
+ * db backup list|create|restore
8
+ */
9
+ import arg from "arg";
1
10
  export declare function dbCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void>;
11
+ /**
12
+ * `db backup [action] [filename]`, resolved in one strict parse.
13
+ *
14
+ * Both halves were reachable by the old operand filter, and both are
15
+ * destructive: `rebase cloud db backup -p acme` read `--project`'s value as the
16
+ * ACTION (falling through to a list, so the flag silently changed what ran),
17
+ * and `db backup restore -p acme` read it as the FILENAME — a restore staged
18
+ * over the live database, named after the project slug. An undeclared flag was
19
+ * dropped instead of refused, which is the same failure one step quieter: `db
20
+ * backup --dry-run` ran a list, having silently discarded the flag that was
21
+ * supposed to change what it did.
22
+ *
23
+ * Exported so its tests drive the real parser.
24
+ */
25
+ export declare function resolveBackupArgs(rawArgs: string[]): {
26
+ flags: arg.Result<{
27
+ "--yes": BooleanConstructor;
28
+ } & {
29
+ readonly "--json": BooleanConstructor;
30
+ readonly "--yes": BooleanConstructor;
31
+ readonly "--help": BooleanConstructor;
32
+ readonly "--project": StringConstructor;
33
+ readonly "-p": "--project";
34
+ readonly "-y": "--yes";
35
+ readonly "-h": "--help";
36
+ }>;
37
+ action: string;
38
+ filename: string;
39
+ };
40
+ export declare function printDbHelp(): void;
@@ -115,3 +115,4 @@ export declare function formatDuration(seconds: number): string;
115
115
  */
116
116
  export declare function parseSince(input: string | undefined): number | null;
117
117
  export declare function debugCommand(action: string | undefined, rawArgs: string[]): Promise<void>;
118
+ export declare function printDebugHelp(): void;
@@ -46,5 +46,69 @@ export declare function timeAgo(value: string | Date | undefined, now: Date): st
46
46
  export declare function isManagedProject(project: DeployProjectRow | undefined, latest: DeploySourceRow | undefined): boolean;
47
47
  /** What a `deploy` with nothing attached will build, in the words to print. */
48
48
  export declare function planBareDeploy(project: DeployProjectRow | undefined, latest: DeploySourceRow | undefined, now: Date): BareDeployPlan;
49
+ /**
50
+ * A warning attached to a deploy: printed for the human, carried in the JSON.
51
+ *
52
+ * `code` is the stable half — the message is prose and will be reworded, so it
53
+ * is the code that CI or an agent branches on.
54
+ */
55
+ export interface DeployWarning {
56
+ code: string;
57
+ message: string;
58
+ hint?: string;
59
+ }
60
+ /** `code` of the warning below, and the field name it sets in the payload. */
61
+ export declare const EJECTS_MANAGED_RUNTIME = "ejects_managed_runtime";
62
+ /** The one sentence that says a source build undoes `runtimeMode: managed`. */
63
+ export declare function ejectWarning(projectRef: string): DeployWarning;
64
+ /** How a container-image deploy was asked for — the input to both rules below. */
65
+ export interface EjectContext {
66
+ /** The project currently runs on the managed runtime. */
67
+ managed: boolean;
68
+ /** `--source` was passed: build this directory. */
69
+ source: boolean;
70
+ /** `--force` was passed: eject on purpose. */
71
+ force: boolean;
72
+ }
73
+ /**
74
+ * Why a container-image deploy of a managed project is refused — or `undefined`
75
+ * to let it through.
76
+ *
77
+ * Every path below this point builds a container image, and a successful one
78
+ * sets `runtimeMode: "custom"` server-side. So the question is never "which flag
79
+ * was used" but "did the caller ask to leave the managed runtime", and only
80
+ * `--force` answers it.
81
+ *
82
+ * `--source` used to be read as answering it too, on the theory that uploading a
83
+ * build context is self-evidently a deliberate eject. It is not: `--source`
84
+ * picks *which source* gets built — this directory, rather than the stale
85
+ * archive the control plane is holding — and the eject is a side effect of the
86
+ * answer. That is exactly how a live project got flipped to `custom` by someone
87
+ * whose actual intent was "deploy what I have here", and it is the same
88
+ * ignorance the bare form is refused for. Same ignorance, same refusal.
89
+ */
90
+ export declare function ejectRefusal(opts: EjectContext, projectRef: string): {
91
+ message: string;
92
+ hint: string;
93
+ code: string;
94
+ } | undefined;
95
+ /**
96
+ * Which warnings a container-image deploy has earned.
97
+ *
98
+ * Pure, and separate from the printing, because the printing is what went
99
+ * wrong: the eject warning used to be written inline behind `!isJsonMode()`, so
100
+ * the fact that a deploy ejects a managed project existed only as a side effect
101
+ * of a TTY being attached. Deciding here, emitting once at the call site, means
102
+ * the decision cannot be output-mode-dependent again.
103
+ *
104
+ * The condition is just `managed`: anything reaching this point is a container
105
+ * image build that `ejectRefusal` has already let through, and on a managed
106
+ * project that is an eject however it was spelled. A caller who passed `--force`
107
+ * knows — the warning is for the transcript and the payload, which is what
108
+ * anyone reviewing the deploy afterwards actually reads.
109
+ */
110
+ export declare function deployWarnings(opts: EjectContext, projectRef: string): DeployWarning[];
111
+ /** The warning half of a deploy's JSON payload — merged into whatever it emits. */
112
+ export declare function warningPayload(warnings: DeployWarning[]): Record<string, unknown>;
49
113
  export declare function deployCommand(rawArgs: string[], projectRef: string): Promise<void>;
50
114
  export declare function logsCommand(rawArgs: string[], projectRef: string): Promise<void>;
@@ -50,5 +50,27 @@ export declare const DEFAULT_DEPLOYMENTS_LIMIT = 20;
50
50
  /** `--limit N`, bounded. A garbage value is a refusal, never a silent default. */
51
51
  export declare function parseDeploymentsLimit(raw: number | undefined): number;
52
52
  export declare function deploymentsListCommand(rawArgs: string[]): Promise<void>;
53
+ /**
54
+ * The deployment id `rollback`/`cancel` was given, if any.
55
+ *
56
+ * Both take an optional id, which is what made the old operand filter so easy
57
+ * to trip: `rebase cloud rollback -p acme` — the documented way to act on an
58
+ * unlinked project — read `--project`'s value as the id and refused with
59
+ * "Deployment acme not found", and `cancel -p acme` sent "acme" to the server
60
+ * as the deployment to cancel. Strict parsing consumes the flag with its value,
61
+ * so an id given as a flag value is never mistaken for an argument.
62
+ */
63
+ export declare function resolveDeploymentIdArg(rawArgs: string[], command: string): {
64
+ flags: import("arg").Result<{
65
+ readonly "--json": BooleanConstructor;
66
+ readonly "--yes": BooleanConstructor;
67
+ readonly "--help": BooleanConstructor;
68
+ readonly "--project": StringConstructor;
69
+ readonly "-p": "--project";
70
+ readonly "-y": "--yes";
71
+ readonly "-h": "--help";
72
+ }>;
73
+ id: string;
74
+ };
53
75
  export declare function rollbackCommand(rawArgs: string[]): Promise<void>;
54
76
  export declare function cancelCommand(rawArgs: string[]): Promise<void>;
@@ -1 +1,11 @@
1
1
  export declare function domainsCommand(action: string | undefined, rawArgs: string[]): Promise<void>;
2
+ /**
3
+ * The domain `domains add` was asked to register.
4
+ *
5
+ * Exported so its tests drive the real parser. Under the old operand filter
6
+ * `rebase cloud domains add -p acme` registered a domain called "acme" — the
7
+ * project slug, read out of `--project`'s own value — and a registered domain
8
+ * is a project-record write, not a no-op.
9
+ */
10
+ export declare function resolveDomainArg(rawArgs: string[]): string | undefined;
11
+ export declare function printDomainsHelp(): void;
@@ -6,3 +6,54 @@ export declare function parseEnvAssignment(operands: string[]): {
6
6
  } | null;
7
7
  /** The prefix that makes `key` a build-time variable, or undefined. */
8
8
  export declare function buildTimeEnvPrefix(key: string): string | undefined;
9
+ /** The flags `rebase cloud env set` takes, on top of the global cloud ones. */
10
+ export declare const ENV_SET_FLAGS: {
11
+ readonly "--secret": BooleanConstructor;
12
+ readonly "--force": BooleanConstructor;
13
+ };
14
+ /**
15
+ * What `env set` was asked to store.
16
+ *
17
+ * The sharp one in this family: the old operand filter left `--project`'s value
18
+ * in the operand list, so `rebase cloud env set KEY -p acme` parsed as the
19
+ * `KEY VALUE` form and stored the project slug as KEY's value — a write that
20
+ * succeeds, reports success, and is wrong. Strict parsing consumes `-p` with
21
+ * its value, leaving `["KEY"]` and the documented empty value.
22
+ *
23
+ * A value beginning with `-` must use the `KEY=-v` form; the bare `KEY -v` form
24
+ * is refused rather than guessed at, as everywhere else strict parsing is used.
25
+ *
26
+ * Exported so its tests drive the real parser rather than a copy of it.
27
+ */
28
+ export declare function resolveEnvSetArgs(rawArgs: string[]): {
29
+ flags: import("arg").Result<{
30
+ readonly "--secret": BooleanConstructor;
31
+ readonly "--force": BooleanConstructor;
32
+ } & {
33
+ readonly "--json": BooleanConstructor;
34
+ readonly "--yes": BooleanConstructor;
35
+ readonly "--help": BooleanConstructor;
36
+ readonly "--project": StringConstructor;
37
+ readonly "-p": "--project";
38
+ readonly "-y": "--yes";
39
+ readonly "-h": "--help";
40
+ }>;
41
+ assignment: {
42
+ key: string;
43
+ value: string;
44
+ } | null;
45
+ };
46
+ /**
47
+ * The variable `env unset` / `env reveal` names.
48
+ *
49
+ * `unset` is a delete, and the operand filter aimed it at the wrong variable:
50
+ * `rebase cloud env unset -p acme` removed a variable called "acme" from the
51
+ * linked project instead of reporting a missing KEY, and `env unset -p acme
52
+ * KEY` removed "acme" instead of KEY. Both read `--project`'s value as the
53
+ * operand — a plain word in the right position that no flag filter can catch.
54
+ *
55
+ * `action` is the word the caller used (`unset`, `rm`, `delete`, `reveal`); the
56
+ * count of command words is the same for all of them.
57
+ */
58
+ export declare function resolveEnvKeyArg(rawArgs: string[], action: string): string | undefined;
59
+ export declare function printEnvHelp(): void;
@@ -1,3 +1,24 @@
1
1
  /** The identifier CREATE EXTENSION takes. `pgvector` is a common alias. */
2
2
  export declare function resolveExtensionAlias(name: string): string;
3
3
  export declare function extensionsCommand(action: string | undefined, rawArgs: string[]): Promise<void>;
4
+ /**
5
+ * The extension `enable`/`disable` names, plus the flags that gate it.
6
+ *
7
+ * Under the old operand filter `rebase cloud extensions enable -p acme` read
8
+ * `--project`'s value as the extension name and asked the server to install one
9
+ * called "acme"; `extensions disable -p acme vector` dropped "acme" rather than
10
+ * vector. Strict parsing consumes the flag with its value.
11
+ */
12
+ export declare function resolveExtensionArgs(rawArgs: string[], action: "enable" | "disable"): {
13
+ flags: import("arg").Result<{
14
+ readonly "--json": BooleanConstructor;
15
+ readonly "--yes": BooleanConstructor;
16
+ readonly "--help": BooleanConstructor;
17
+ readonly "--project": StringConstructor;
18
+ readonly "-p": "--project";
19
+ readonly "-y": "--yes";
20
+ readonly "-h": "--help";
21
+ }>;
22
+ name: string;
23
+ };
24
+ export declare function printExtensionsHelp(): void;
@@ -1 +1,24 @@
1
+ /**
2
+ * Positional tokens after `rebase cloud` (group, action, …).
3
+ *
4
+ * Two things stop a flag being mistaken for the group. `GLOBAL_CLOUD_FLAGS` is
5
+ * declared so `arg` *consumes* the flags that may precede it — critically
6
+ * together with their values, which is the half that filtering cannot do. The
7
+ * leading-`-` skip then covers a flag nobody declared, so an unrecognised
8
+ * boolean shifts nothing.
9
+ *
10
+ * Only leading tokens are skipped: past the group and action, an undeclared
11
+ * flag and its value are somebody else's positionals and none of our business.
12
+ * A flag this file has never heard of, that takes a value, placed before the
13
+ * group, is the one shape still unresolvable here — there is no way to know
14
+ * whether the token after it is its value or the group, and guessing either way
15
+ * is worse than the handler reporting an unknown group.
16
+ *
17
+ * Exported so its tests can drive the real thing. The dispatch test used to
18
+ * re-implement it locally as `slice(3).filter(a => !a.startsWith("-"))` — which
19
+ * filtered flags, while this function did not — so the test asserted the
20
+ * behaviour we wanted against a copy that had it, and stayed green for as long
21
+ * as the real dispatcher was broken.
22
+ */
23
+ export declare function positionals(rawArgs: string[]): string[];
1
24
  export declare function cloudCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void>;
@@ -1 +1,2 @@
1
1
  export declare function orgsCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void>;
2
+ export declare function printOrgsHelp(): void;