@rebasepro/cli 0.25.1 → 0.26.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 (151) hide show
  1. package/README.md +2 -1
  2. package/bin/rebase.js +143 -4
  3. package/dist/{agent-setup-BYb2Tbdz.js → agent-setup-D9mHRZ5R.js} +125 -3
  4. package/dist/agent-setup-D9mHRZ5R.js.map +1 -0
  5. package/dist/{api-keys-CSMbsmAn.js → api-keys-CyJ26KEJ.js} +41 -9
  6. package/dist/api-keys-CyJ26KEJ.js.map +1 -0
  7. package/dist/{apps-iBXNZhVN.js → apps-CnLDV5b6.js} +6 -6
  8. package/dist/{apps-iBXNZhVN.js.map → apps-CnLDV5b6.js.map} +1 -1
  9. package/dist/{atlas-dev-database-BusbHP6n.js → atlas-dev-database-BODqdCWt.js} +2 -2
  10. package/dist/{atlas-dev-database-BusbHP6n.js.map → atlas-dev-database-BODqdCWt.js.map} +1 -1
  11. package/dist/{auth-DRsTWPky.js → auth-dII2jCO1.js} +10 -7
  12. package/dist/auth-dII2jCO1.js.map +1 -0
  13. package/dist/{branch-pointer-Bn_FjNld.js → branch-pointer-BQUF6lYa.js} +1 -1
  14. package/dist/{build-et7Rccxi.js → build-Cza7ZQrp.js} +6 -6
  15. package/dist/{build-et7Rccxi.js.map → build-Cza7ZQrp.js.map} +1 -1
  16. package/dist/{bundle-DlqkDYSe.js → bundle-C6yEtMJ-.js} +53 -5
  17. package/dist/bundle-C6yEtMJ-.js.map +1 -0
  18. package/dist/bundle.d.ts +14 -0
  19. package/dist/{cloud-B-ZIjHrA.js → cloud-BdnmqQaZ.js} +8527 -4340
  20. package/dist/cloud-BdnmqQaZ.js.map +1 -0
  21. package/dist/collections-dir-DlvDhime.js +69 -0
  22. package/dist/collections-dir-DlvDhime.js.map +1 -0
  23. package/dist/commands/agent-setup.d.ts +58 -0
  24. package/dist/commands/api-keys.d.ts +13 -0
  25. package/dist/commands/cloud/activity.d.ts +25 -0
  26. package/dist/commands/cloud/app-key.d.ts +18 -0
  27. package/dist/commands/cloud/auth.d.ts +1 -0
  28. package/dist/commands/cloud/billing-invoices.d.ts +39 -0
  29. package/dist/commands/cloud/claim.d.ts +7 -0
  30. package/dist/commands/cloud/context.d.ts +115 -6
  31. package/dist/commands/cloud/deploy-summary.d.ts +162 -0
  32. package/dist/commands/cloud/deploy.d.ts +64 -0
  33. package/dist/commands/cloud/env.d.ts +24 -0
  34. package/dist/commands/cloud/index.d.ts +13 -1
  35. package/dist/commands/cloud/init.d.ts +143 -0
  36. package/dist/commands/cloud/login-flow.d.ts +51 -0
  37. package/dist/commands/cloud/notifications.d.ts +28 -0
  38. package/dist/commands/cloud/orgs.d.ts +13 -0
  39. package/dist/commands/cloud/previews.d.ts +123 -0
  40. package/dist/commands/cloud/resources.d.ts +68 -14
  41. package/dist/commands/cloud/runtime-logs.d.ts +176 -0
  42. package/dist/commands/cloud/service-key.d.ts +15 -0
  43. package/dist/commands/cloud/token-capabilities.d.ts +61 -8
  44. package/dist/commands/cloud/tokens.d.ts +18 -3
  45. package/dist/commands/cloud/usage.d.ts +63 -0
  46. package/dist/commands/dev.d.ts +10 -0
  47. package/dist/commands/doctor.d.ts +1 -1
  48. package/dist/commands/generate-view.d.ts +94 -0
  49. package/dist/commands/generate_sdk.d.ts +15 -0
  50. package/dist/commands/skills.d.ts +4 -3
  51. package/dist/commands/storage.d.ts +4 -0
  52. package/dist/commands/verify.d.ts +96 -0
  53. package/dist/{consent-BaB-eQKG.js → consent-BD7F29T3.js} +2 -2
  54. package/dist/{consent-BaB-eQKG.js.map → consent-BD7F29T3.js.map} +1 -1
  55. package/dist/{console-BlD9kjFW.js → console-BXB6-8GT.js} +12 -6
  56. package/dist/console-BXB6-8GT.js.map +1 -0
  57. package/dist/{context-DHiiiJ5C.js → context-GUxkZm-S.js} +481 -24
  58. package/dist/context-GUxkZm-S.js.map +1 -0
  59. package/dist/{daemon-DDMRbz4T.js → daemon-Cp7oNXth.js} +2 -2
  60. package/dist/{daemon-DDMRbz4T.js.map → daemon-Cp7oNXth.js.map} +1 -1
  61. package/dist/{db-9P6MnmdC.js → db-KzlqddGD.js} +37 -30
  62. package/dist/db-KzlqddGD.js.map +1 -0
  63. package/dist/{derive-MTdClnkc.js → derive-ae9UOoOB.js} +2 -2
  64. package/dist/{derive-MTdClnkc.js.map → derive-ae9UOoOB.js.map} +1 -1
  65. package/dist/{dev-BDN_OKXA.js → dev-DTqVMgB3.js} +59 -32
  66. package/dist/dev-DTqVMgB3.js.map +1 -0
  67. package/dist/{dev-preflight-FT9GbJVj.js → dev-preflight-Cxv3TiD1.js} +2 -2
  68. package/dist/{dev-preflight-FT9GbJVj.js.map → dev-preflight-Cxv3TiD1.js.map} +1 -1
  69. package/dist/{dev-server-CIZwAfZa.js → dev-server-OJsUGZEB.js} +2 -2
  70. package/dist/{dev-server-CIZwAfZa.js.map → dev-server-OJsUGZEB.js.map} +1 -1
  71. package/dist/{doctor-D8YXz7df.js → doctor-BRWOlqeG.js} +13 -11
  72. package/dist/doctor-BRWOlqeG.js.map +1 -0
  73. package/dist/{eject-izG2KjMo.js → eject-DABcDnPN.js} +3 -3
  74. package/dist/{eject-izG2KjMo.js.map → eject-DABcDnPN.js.map} +1 -1
  75. package/dist/{fold-static-CybSay_W.js → fold-static-BnAK-anQ.js} +3 -3
  76. package/dist/{fold-static-CybSay_W.js.map → fold-static-BnAK-anQ.js.map} +1 -1
  77. package/dist/generate-view-IFwCADvb.js +662 -0
  78. package/dist/generate-view-IFwCADvb.js.map +1 -0
  79. package/dist/{generate_sdk-B4R65oUV.js → generate_sdk-BvcWvoUh.js} +33 -7
  80. package/dist/generate_sdk-BvcWvoUh.js.map +1 -0
  81. package/dist/index.es.js +57 -38
  82. package/dist/index.es.js.map +1 -1
  83. package/dist/{init-DYaeppEN.js → init-CaU6GhwI.js} +8 -8
  84. package/dist/{init-DYaeppEN.js.map → init-CaU6GhwI.js.map} +1 -1
  85. package/dist/last-dev-database-DpW5dfoX.js +2 -0
  86. package/dist/{manifest-nvPdLlJY.js → manifest-BtzDy7KQ.js} +36 -3
  87. package/dist/{manifest-nvPdLlJY.js.map → manifest-BtzDy7KQ.js.map} +1 -1
  88. package/dist/{normalize-imports-BYw8ad87.js → normalize-imports-D0zXlM6g.js} +3 -3
  89. package/dist/{normalize-imports-BYw8ad87.js.map → normalize-imports-D0zXlM6g.js.map} +1 -1
  90. package/dist/{path-flags-BFgG9V6y.js → path-flags-DNvtEi2-.js} +5 -4
  91. package/dist/path-flags-DNvtEi2-.js.map +1 -0
  92. package/dist/{prepare-1rVNd2PF.js → prepare-CTw9NEkh.js} +4 -4
  93. package/dist/{prepare-1rVNd2PF.js.map → prepare-CTw9NEkh.js.map} +1 -1
  94. package/dist/{project-g4K6kV1t.js → project-CasK56vN.js} +2 -2
  95. package/dist/{project-g4K6kV1t.js.map → project-CasK56vN.js.map} +1 -1
  96. package/dist/resolve-D647F1LA.js +2 -0
  97. package/dist/{resources-CovP8AZ-.js → resources-CPSC5Kcu.js} +4 -4
  98. package/dist/{resources-CovP8AZ-.js.map → resources-CPSC5Kcu.js.map} +1 -1
  99. package/dist/{schema-nuxvvc50.js → schema-BSXwZSiI.js} +9 -7
  100. package/dist/schema-BSXwZSiI.js.map +1 -0
  101. package/dist/{skills-DeUIsZcT.js → skills-BU2flMOy.js} +52 -7
  102. package/dist/skills-BU2flMOy.js.map +1 -0
  103. package/dist/{start-RzZqDroW.js → start-mVb6upwY.js} +5 -5
  104. package/dist/{start-RzZqDroW.js.map → start-mVb6upwY.js.map} +1 -1
  105. package/dist/static-syntax-check.d.ts +64 -0
  106. package/dist/{status-D9Zm88NZ.js → status-BREvtzJm.js} +7 -7
  107. package/dist/{status-D9Zm88NZ.js.map → status-BREvtzJm.js.map} +1 -1
  108. package/dist/{storage-BB3umRfw.js → storage-DtOXGflp.js} +159 -15
  109. package/dist/storage-DtOXGflp.js.map +1 -0
  110. package/dist/{telemetry-HfU5uAh1.js → telemetry-CgwJPVMO.js} +2 -2
  111. package/dist/{telemetry-HfU5uAh1.js.map → telemetry-CgwJPVMO.js.map} +1 -1
  112. package/dist/{telemetry-TseNLk6X.js → telemetry-DwK5RQJl.js} +4 -4
  113. package/dist/{telemetry-TseNLk6X.js.map → telemetry-DwK5RQJl.js.map} +1 -1
  114. package/dist/{upgrade-apiPKKE_.js → upgrade-B7sVwL8S.js} +4 -4
  115. package/dist/{upgrade-apiPKKE_.js.map → upgrade-B7sVwL8S.js.map} +1 -1
  116. package/dist/utils/collections-dir.d.ts +14 -0
  117. package/dist/utils/path-flags.d.ts +2 -1
  118. package/dist/utils/tool-stdio.d.ts +1 -1
  119. package/dist/verify-D7UsV_qe.js +730 -0
  120. package/dist/verify-D7UsV_qe.js.map +1 -0
  121. package/package.json +9 -7
  122. package/templates/eject/backend/src/index.ts +9 -1
  123. package/templates/generated-schemas/ecommerce.ts +3 -0
  124. package/templates/overlays/baas/ai-instructions.md +13 -0
  125. package/templates/template/.claude/hooks/post-edit-collection.sh +99 -0
  126. package/templates/template/.claude/settings.json +17 -0
  127. package/templates/template/.env.example +10 -1
  128. package/templates/template/ai-instructions.md +21 -1
  129. package/templates/template/config/collections/presets/ecommerce/index.ts +23 -0
  130. package/templates/template/docker-compose.yml +4 -1
  131. package/templates/template/frontend/package.json +1 -0
  132. package/templates/views/AppView.tsx.tmpl +138 -0
  133. package/templates/views/EntityView.tsx.tmpl +64 -0
  134. package/templates/views/index.ts.tmpl +8 -0
  135. package/dist/agent-setup-BYb2Tbdz.js.map +0 -1
  136. package/dist/api-keys-CSMbsmAn.js.map +0 -1
  137. package/dist/auth-DRsTWPky.js.map +0 -1
  138. package/dist/bundle-DlqkDYSe.js.map +0 -1
  139. package/dist/cloud-B-ZIjHrA.js.map +0 -1
  140. package/dist/console-BlD9kjFW.js.map +0 -1
  141. package/dist/context-DHiiiJ5C.js.map +0 -1
  142. package/dist/db-9P6MnmdC.js.map +0 -1
  143. package/dist/dev-BDN_OKXA.js.map +0 -1
  144. package/dist/doctor-D8YXz7df.js.map +0 -1
  145. package/dist/generate_sdk-B4R65oUV.js.map +0 -1
  146. package/dist/last-dev-database-B_75fxZC.js +0 -2
  147. package/dist/path-flags-BFgG9V6y.js.map +0 -1
  148. package/dist/resolve-BQUAC3Wi.js +0 -2
  149. package/dist/schema-nuxvvc50.js.map +0 -1
  150. package/dist/skills-DeUIsZcT.js.map +0 -1
  151. package/dist/storage-BB3umRfw.js.map +0 -1
@@ -94,27 +94,31 @@ export declare function describeRuntime(project: {
94
94
  export declare function statusCommand(rawArgs: string[]): Promise<void>;
95
95
  export declare function metricsCommand(rawArgs: string[]): Promise<void>;
96
96
  /**
97
- * The webhook `webhooks delete` names.
97
+ * `rebase cloud webhooks` is retired, and says where to go instead.
98
98
  *
99
- * The worst instance of the operand-filter bug in this family, because the
100
- * argument is consumed by a DELETE and the wrong value looks entirely
101
- * plausible: `rebase cloud webhooks delete --project acme 42` filtered out
102
- * `--project` and kept "acme", so the id it deleted was the project slug rather
103
- * than the 42 the caller wrote. Strict parsing consumes the flag with its
104
- * value, leaving `["42"]`.
99
+ * It never worked. It wrote rows to a data collection named `webhooks` on the
100
+ * control plane, whose real slug is `database-webhooks` — and nothing on the
101
+ * control plane ever delivered those rows anyway. What people reached for it
102
+ * to do is now two other things:
105
103
  *
106
- * Exported so its tests drive the real parser.
104
+ * - a project's own events (a deploy failed, backups stopped, a payment was
105
+ * declined, usage passed 80%) to Slack, Discord or any URL:
106
+ * `rebase cloud notifications`;
107
+ * - a POST when rows of your app's own tables change: a `WebhookDispatcher`
108
+ * in your app's code, which your backend delivers itself.
109
+ *
110
+ * Every action answers the same refusal, exit 1, code `command_retired`, with
111
+ * both routes — a retired command that still exits 0 would tell a script its
112
+ * webhook exists.
107
113
  */
108
- export declare function resolveWebhookIdArg(rawArgs: string[]): string | undefined;
109
- /** The action words `rebase cloud webhooks` dispatches. No word means `list`. */
110
- export declare const WEBHOOKS_ACTIONS: readonly ["list", "create", "delete"];
111
- export declare function webhooksCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void>;
114
+ export declare const WEBHOOKS_RETIRED_HINT: string;
115
+ export declare function webhooksCommand(_subcommand: string | undefined, _rawArgs: string[]): Promise<void>;
112
116
  /** The action words `rebase cloud storage` dispatches. No word means `list`. */
113
117
  export declare const STORAGE_ACTIONS: readonly ["list", "create", "attach"];
114
118
  export declare function storageCommand(action: string | undefined, rawArgs: string[]): Promise<void>;
115
119
  export declare function printStorageHelp(): void;
116
120
  /** The action words `rebase cloud clusters` dispatches. No word means `list`. */
117
- export declare const CLUSTERS_ACTIONS: readonly ["list", "add", "verify"];
121
+ export declare const CLUSTERS_ACTIONS: readonly ["list", "add", "verify", "registry"];
118
122
  /**
119
123
  * `rebase cloud clusters` — list, register and verify the clusters tenants run on.
120
124
  *
@@ -192,6 +196,46 @@ export interface ClusterAddArgs {
192
196
  * so it is refused here, where the operator can still fix the command.
193
197
  */
194
198
  export declare function resolveClusterAddArgs(rawArgs: string[]): ClusterAddArgs;
199
+ /** The flags `clusters registry` declares; exported for its help page's test. */
200
+ export declare const CLUSTER_REGISTRY_FLAGS: {
201
+ "--repository": StringConstructor;
202
+ "--push-service-account": StringConstructor;
203
+ "--pull-key-file": StringConstructor;
204
+ "--clear": BooleanConstructor;
205
+ };
206
+ /**
207
+ * What `clusters registry` was asked to record: a customer cluster's own image
208
+ * repository, the account its builds push as, and the file holding the key of
209
+ * its read-only account — or `--clear`, to go back to the shared registry.
210
+ */
211
+ export type ClusterRegistryArgs = {
212
+ id: string;
213
+ clear: true;
214
+ } | {
215
+ id: string;
216
+ clear: false;
217
+ repository: string;
218
+ pushServiceAccount: string;
219
+ pullKeyFile: string;
220
+ };
221
+ /**
222
+ * Parse `rebase cloud clusters registry <id> …`.
223
+ *
224
+ * All three values or `--clear`, never a part: the control plane ignores a
225
+ * partial set (and keeps handing the cluster the shared credentials), so a
226
+ * command that wrote one would look done and change nothing.
227
+ */
228
+ export declare function resolveClusterRegistryArgs(rawArgs: string[]): ClusterRegistryArgs;
229
+ /**
230
+ * The reader's key from `--pull-key-file`, checked before it leaves this
231
+ * machine: a service-account key, and not the pusher's — the pull secret sits
232
+ * where the customer's cluster admin can read it, so it must not be able to
233
+ * write. Returns the key text and the account it belongs to.
234
+ */
235
+ export declare function readPullKey(text: string, pushServiceAccount: string): {
236
+ key: string;
237
+ account: string;
238
+ };
195
239
  /**
196
240
  * The action words `rebase cloud billing` dispatches. No word at all is the
197
241
  * account view, which is why it is not in the list.
@@ -202,7 +246,7 @@ export declare function resolveClusterAddArgs(rawArgs: string[]): ClusterAddArgs
202
246
  * the account — a help page describing a command that does not exist, and a typo
203
247
  * exiting 0.
204
248
  */
205
- export declare const BILLING_ACTIONS: readonly ["setup", "checkout"];
249
+ export declare const BILLING_ACTIONS: readonly ["setup", "checkout", "invoices", "upcoming"];
206
250
  export declare function billingCommand(rawArgs: string[]): Promise<void>;
207
251
  /**
208
252
  * The action words `rebase cloud compute` dispatches. No word, or `show`,
@@ -222,6 +266,16 @@ export declare const COMPUTE_ACTIONS: readonly ["show", "set"];
222
266
  * — so this is a description of that line, not a second parser for it.
223
267
  */
224
268
  export declare const COMPUTE_SET_FLAGS: Record<string, unknown>;
269
+ /**
270
+ * The flag that used to set `scaleToZero`. Still parsed, so a script that passes
271
+ * it is told what happened rather than failing on an unknown option.
272
+ *
273
+ * The dial never did anything: it resolved to a request-billed substrate no
274
+ * deploy built, and every backend kept running as an always-on pod. The control
275
+ * plane refuses `true` now; this refuses it before the round trip, and lets
276
+ * `false` — what every project already gets — through with a warning.
277
+ */
278
+ export declare const RETIRED_SCALE_TO_ZERO = "--scale-to-zero";
225
279
  /**
226
280
  * `rebase cloud compute` — show what a project reserves, and change it.
227
281
  *
@@ -0,0 +1,176 @@
1
+ import { type CloudClient } from "./context.js";
2
+ import { type RuntimeLogsPod } from "./debug.js";
3
+ /** The control-plane function this module reads. */
4
+ export declare const RUNTIME_LOGS_FUNCTION = "runtime-logs";
5
+ /** How often a follow polls. The console polls at the same rate. */
6
+ export declare const FOLLOW_INTERVAL_MS = 2000;
7
+ /** The longest a follow waits between retries of a failed poll. */
8
+ export declare const MAX_BACKOFF_MS = 30000;
9
+ /** A poll with no answer by then is treated as a dropped connection. */
10
+ export declare const POLL_TIMEOUT_MS = 30000;
11
+ /** What one request asks the route for. `sinceTime` and `sinceSeconds` are exclusive. */
12
+ export interface RuntimeLogsQuery {
13
+ sinceSeconds?: number;
14
+ /** RFC3339. */
15
+ sinceTime?: string;
16
+ tailLines?: number;
17
+ previous?: boolean;
18
+ /** One backend preview's pod instead of production's. */
19
+ preview?: string;
20
+ }
21
+ export interface RuntimeLogsPodState extends RuntimeLogsPod {
22
+ /** The container's restart count. Absent from control planes before it was reported; null when unknown. */
23
+ restarts?: number | null;
24
+ }
25
+ /** The route's answer, read defensively: every field may be missing on an older control plane. */
26
+ export interface RuntimeLogsPage {
27
+ logs?: string;
28
+ pods?: RuntimeLogsPodState[];
29
+ ordering?: string;
30
+ truncated?: boolean;
31
+ previous?: boolean;
32
+ /** Echoed by control planes that understand `?preview=`. */
33
+ preview?: string | null;
34
+ nextSinceTime?: string | null;
35
+ state?: "ok" | "no_pods" | "error" | string;
36
+ message?: string | null;
37
+ }
38
+ /** The request path for a query: `<projectId>?…`. Timestamps are always asked for — the cursor is built from them. */
39
+ export declare function runtimeLogsPath(projectId: string, q: RuntimeLogsQuery): string;
40
+ /**
41
+ * Read one page, refusing to pass off production's log as a preview's.
42
+ *
43
+ * A control plane from before `?preview=` ignores the parameter and answers with
44
+ * production's pods. It does not echo `preview`, and that silence is the tell.
45
+ */
46
+ export declare function fetchRuntimeLogsPage(client: CloudClient, projectId: string, q: RuntimeLogsQuery): Promise<RuntimeLogsPage>;
47
+ /**
48
+ * `--since`: a duration (`30s`, `5m`, `1h`, `2d`) or an RFC3339 instant.
49
+ * Returns null for anything else.
50
+ */
51
+ export declare function parseSinceFlag(input: string): {
52
+ sinceSeconds: number;
53
+ } | {
54
+ sinceTime: string;
55
+ } | null;
56
+ /** Severity, as the console's log explorer reads it. */
57
+ export type LogLevel = "error" | "warn" | "info" | "debug" | "unknown";
58
+ /** `--level` names a floor: `warn` keeps warnings and errors. */
59
+ export declare const LEVEL_FLOOR: Record<Exclude<LogLevel, "unknown">, number>;
60
+ /**
61
+ * A line's severity: the structured field when the payload is a JSON object
62
+ * (a Rebase backend logs `{"severity":"ERROR",…}`), else a level token at the
63
+ * head of the line — the console explorer's rules. A line with neither that
64
+ * `cloud debug errors` would flag (`Error:`, `EACCES`, a refusal) counts as an
65
+ * error, because an unstructured stack trace is exactly what `--level error`
66
+ * is run to find.
67
+ */
68
+ export declare function lineLevel(text: string): LogLevel;
69
+ /**
70
+ * `--grep`: a case-insensitive substring of the whole line (timestamp and pod
71
+ * included, as in the console), or a regular expression written `/re/flags`.
72
+ */
73
+ export declare function grepMatcher(pattern: string): (line: string) => boolean;
74
+ /** Read `--level`, refusing anything that is not a level. */
75
+ export declare function parseLevelFlag(value: string): Exclude<LogLevel, "unknown">;
76
+ /** One printed line, parsed. */
77
+ export interface LogRecord {
78
+ /** The kubelet's RFC3339(Nano) timestamp, or null when the line carried none. */
79
+ ts: string | null;
80
+ pod: string | null;
81
+ text: string;
82
+ /** The line exactly as the control plane rendered it. */
83
+ raw: string;
84
+ }
85
+ export declare function parseRecords(logs: string | undefined): LogRecord[];
86
+ /** The lines `--grep` and `--level` keep. Both unset keeps everything. */
87
+ export declare function recordFilter(opts: {
88
+ grep?: string;
89
+ level?: Exclude<LogLevel, "unknown">;
90
+ }): (rec: LogRecord) => boolean;
91
+ /**
92
+ * The newest line printed so far, and which lines share its millisecond.
93
+ *
94
+ * Polls overlap by design (see the module docs), so a line can arrive twice.
95
+ * A line older than the cursor was printed by an earlier poll — every pod is
96
+ * read at the same instant, so nothing older can still be on its way. A line
97
+ * in the cursor's own millisecond was printed if it is one of the lines
98
+ * remembered there. A line with no timestamp cannot be placed and is printed:
99
+ * a duplicate is a kinder failure than a lost line.
100
+ */
101
+ export declare class FollowCursor {
102
+ private ms;
103
+ private boundary;
104
+ /** Keep the lines of one page that have not been printed, and move the cursor past them. */
105
+ admit(records: LogRecord[]): LogRecord[];
106
+ /** Where the next poll starts: one millisecond before the newest line, or null before any. */
107
+ sinceTime(): string | null;
108
+ }
109
+ /** Something a follower says besides a log line. */
110
+ export type FollowEvent = {
111
+ event: "no_pods";
112
+ message: string;
113
+ } | {
114
+ event: "pod_added";
115
+ pod: string;
116
+ } | {
117
+ event: "pod_removed";
118
+ pod: string;
119
+ } | {
120
+ event: "pod_state";
121
+ pod: string;
122
+ state: string;
123
+ message: string | null;
124
+ } | {
125
+ event: "pod_restarted";
126
+ pod: string;
127
+ restarts: number;
128
+ missed: number;
129
+ } | {
130
+ event: "truncated";
131
+ message: string;
132
+ } | {
133
+ event: "server_error";
134
+ message: string;
135
+ } | {
136
+ event: "reconnecting";
137
+ message: string;
138
+ retryInMs: number;
139
+ } | {
140
+ event: "reconnected";
141
+ };
142
+ export interface FollowSink {
143
+ line(rec: LogRecord): void;
144
+ event(e: FollowEvent): void;
145
+ }
146
+ export interface FollowDeps {
147
+ fetch(q: RuntimeLogsQuery): Promise<RuntimeLogsPage>;
148
+ /** Resolves after `ms`, or as soon as `signal` aborts. */
149
+ sleep(ms: number, signal: AbortSignal): Promise<void>;
150
+ signal: AbortSignal;
151
+ sink: FollowSink;
152
+ /** A monotonic clock, in milliseconds. */
153
+ now(): number;
154
+ /** Whether a failed poll is worth retrying. */
155
+ isTransient(e: unknown): boolean;
156
+ intervalMs?: number;
157
+ pollTimeoutMs?: number;
158
+ }
159
+ export interface FollowOptions {
160
+ /** The first poll, as the flags asked for it. */
161
+ initial: RuntimeLogsQuery;
162
+ filter: (rec: LogRecord) => boolean;
163
+ }
164
+ /** The delay before retry `attempt` (1-based): 2s, 4s, 8s, 16s, then 30s. */
165
+ export declare function backoffMs(attempt: number, base?: number): number;
166
+ /**
167
+ * Poll until `deps.signal` aborts. Returns normally then; throws only a
168
+ * failure that is not worth retrying (the caller reports it).
169
+ */
170
+ export declare function followRuntimeLogs(deps: FollowDeps, opts: FollowOptions): Promise<void>;
171
+ /** Colour a line by its severity on a terminal; the text itself is never changed. */
172
+ export declare function paintLine(rec: LogRecord): string;
173
+ /** The human sentence for an event, or null for one that needs none. */
174
+ export declare function describeEvent(e: FollowEvent, opts?: {
175
+ preview?: string;
176
+ }): string | null;
@@ -0,0 +1,15 @@
1
+ export declare const SERVICE_KEY_FLAGS: {};
2
+ export declare const SERVICE_KEY_ACTIONS: readonly ["rotate"];
3
+ /** What `GET /credentials/:projectId/service-key` answers. Never the key. */
4
+ export interface CliServiceKeyStatus {
5
+ generation: number;
6
+ liveGeneration: number;
7
+ rotatedAt: string | null;
8
+ pending: boolean;
9
+ }
10
+ /** What a rotation answers. */
11
+ export interface CliServiceKeyRotation {
12
+ generation: number;
13
+ state: "restarting" | "pending";
14
+ }
15
+ export declare function serviceKeyCommand(rawArgs: string[]): Promise<void>;
@@ -15,18 +15,33 @@
15
15
  * hold:
16
16
  *
17
17
  * - `deploy` — `rebase cloud deploy` (bundle and source paths, uploads, the
18
- * build follow) and `rebase cloud deployments`.
19
- * - `logs` — `rebase cloud logs` (build, `--follow`, `--runtime`),
20
- * `rebase cloud metrics` and `rebase cloud cron` — whose
21
- * `runtime-token` call is how a token reads the app's own
22
- * cron history.
23
- * - `env` — `rebase cloud env list|set|unset|reveal|pull`.
18
+ * build follow, `--preview`), `rebase cloud deployments` and
19
+ * `rebase cloud previews`.
20
+ * - `logs` — `rebase cloud logs` (build, `--follow`, `--runtime`,
21
+ * `--preview`),
22
+ * `rebase cloud metrics`, `rebase cloud usage` and
23
+ * `rebase cloud cron` — whose `runtime-token` call is how a
24
+ * token reads the app's own cron history.
25
+ * - `env` — `rebase cloud env list|set|unset|reveal|pull`, and the
26
+ * same with `--preview` (and `env reset --preview`).
24
27
  * - `database` — `rebase cloud db list|info|connect`.
25
28
  * - `backups` — `rebase cloud db backup list|create|status|download` and
26
29
  * `db pitr status`. Restoring takes `project:restore`, which no
27
30
  * capability grants: putting old data over a live database is
28
31
  * for a signed-in person.
29
32
  *
33
+ * Three more capabilities act on one ORGANIZATION rather than a project, and a
34
+ * token holds one only when it is asked for ({@link ORG_CAPABILITIES}):
35
+ *
36
+ * - `billing` — `rebase cloud billing`, `billing invoices|upcoming`.
37
+ * - `audit` — `rebase cloud activity`.
38
+ * - `notifications` — `rebase cloud notifications` on the organization's
39
+ * projects (adding and removing one still takes the
40
+ * owner or admin role).
41
+ *
42
+ * Each holds its `org:*` scope narrowed to the organization
43
+ * (`org:billing:<organizationId>`).
44
+ *
30
45
  * Every project-level scope is narrowed to the one project the token is for
31
46
  * (`project:deploy:<projectId>`). The data and function scopes cannot be: they
32
47
  * name a collection or a function, not a row, and the control plane's
@@ -43,8 +58,9 @@ export type TokenCapability = "deploy" | "logs" | "env" | "database" | "backups"
43
58
  export declare const TOKEN_CAPABILITY_NAMES: readonly TokenCapability[];
44
59
  /**
45
60
  * Scopes every token holds, whatever it was created for: resolving a project
46
- * by its slug, reading the deployment a command follows, the organization a
47
- * project belongs to, and the control plane's public description of itself.
61
+ * by its slug, reading the deployment a command follows (a production one, or
62
+ * a preview's), the organization a project belongs to, and the control plane's
63
+ * public description of itself.
48
64
  */
49
65
  export declare const ALWAYS_SCOPES: string[];
50
66
  /** Each capability: what it lets a token do, and the scopes that does on one project. */
@@ -74,3 +90,40 @@ export declare function capabilitiesInScopes(scopes: readonly string[]): Array<{
74
90
  projectId: string;
75
91
  capabilities: TokenCapability[];
76
92
  }>;
93
+ /**
94
+ * Whether a token's scopes reach one project: a project scope narrowed to it,
95
+ * or an unnarrowed one, which reaches every project.
96
+ *
97
+ * What decides, in a directory `rebase cloud init --claim` linked, whether
98
+ * `REBASE_TOKEN` or the token stored for that project acts on it: a
99
+ * `REBASE_TOKEN` made for other projects would be refused on this one.
100
+ */
101
+ export declare function scopesReachProject(scopes: readonly string[], projectId: string): boolean;
102
+ /** A capability on one organization. A token holds one only when asked for. */
103
+ export type OrgCapability = "billing" | "audit" | "notifications";
104
+ /** Every organization capability, in the order they are offered. */
105
+ export declare const ORG_CAPABILITY_NAMES: readonly OrgCapability[];
106
+ /** Each organization capability: what it lets a token do, and the scopes that does on one organization. */
107
+ export declare const ORG_CAPABILITIES: Record<OrgCapability, {
108
+ label: string;
109
+ scopes: (organizationId: string) => string[];
110
+ }>;
111
+ /** Whether a word names an organization capability. */
112
+ export declare function isOrgCapability(value: string): value is OrgCapability;
113
+ /**
114
+ * The scopes `capabilities` hold on one organization, each once — added to a
115
+ * token's project scopes, so not {@link ALWAYS_SCOPES}.
116
+ *
117
+ * Throws on an organization id a scope cannot carry, and on an unknown
118
+ * capability.
119
+ */
120
+ export declare function scopesForOrgCapabilities(organizationId: string, capabilities: readonly OrgCapability[]): string[];
121
+ /**
122
+ * Read a token's `org:*` scopes back as organization capabilities: the
123
+ * organizations they name, and, for each, the capabilities it holds every
124
+ * scope of.
125
+ */
126
+ export declare function orgCapabilitiesInScopes(scopes: readonly string[]): Array<{
127
+ organizationId: string;
128
+ capabilities: OrgCapability[];
129
+ }>;
@@ -1,4 +1,4 @@
1
- import { type TokenCapability } from "./token-capabilities.js";
1
+ import { type OrgCapability, type TokenCapability } from "./token-capabilities.js";
2
2
  /** Every action the group dispatches. */
3
3
  export declare const TOKENS_ACTIONS: readonly ["list", "create", "revoke"];
4
4
  /** What `rebase cloud tokens create` parses, beside the global flags (`--project` among them). */
@@ -6,14 +6,21 @@ export declare const CREATE_TOKEN_FLAGS: {
6
6
  "--can": [StringConstructor];
7
7
  "--name": StringConstructor;
8
8
  "--expires-in": StringConstructor;
9
+ "--org": StringConstructor;
9
10
  };
10
11
  export declare function tokensCommand(action: string | undefined, rawArgs: string[]): Promise<void>;
12
+ /** What `--can` names: capabilities on one project, and on one organization. */
13
+ export interface RequestedCapabilities {
14
+ project: TokenCapability[];
15
+ org: OrgCapability[];
16
+ }
11
17
  /**
12
- * The capabilities `--can` names, comma-separated or repeated, each once.
18
+ * The capabilities `--can` names, comma-separated or repeated, each once —
19
+ * split into the project's and the organization's.
13
20
  *
14
21
  * Exported so its tests can drive it without a session.
15
22
  */
16
- export declare function parseCapabilities(values: readonly string[] | undefined): TokenCapability[];
23
+ export declare function parseCapabilities(values: readonly string[] | undefined): RequestedCapabilities;
17
24
  /**
18
25
  * `--expires-in <days>` as an ISO timestamp, or null for a token that does not
19
26
  * expire.
@@ -21,3 +28,11 @@ export declare function parseCapabilities(values: readonly string[] | undefined)
21
28
  * Exported so its tests can drive it without a session.
22
29
  */
23
30
  export declare function resolveTokenExpiry(value: string | undefined, now?: Date): string | null;
31
+ /**
32
+ * What a token was created for, read back from its scopes:
33
+ * `deploy, logs on proj_1; billing on organization org_1`. Undefined when no
34
+ * capability explains them.
35
+ *
36
+ * Exported for `whoami`, which reads a token back the same way.
37
+ */
38
+ export declare function describeGrants(scopes: readonly string[]): string | undefined;
@@ -0,0 +1,63 @@
1
+ export declare const USAGE_FLAGS: {
2
+ readonly "--month": StringConstructor;
3
+ };
4
+ export declare const USAGE_ACTIONS: readonly ["org"];
5
+ /** A caveat on the figures, as the control plane sends it. */
6
+ export interface CliUsageCaveat {
7
+ code: string;
8
+ message: string;
9
+ count?: number;
10
+ }
11
+ /** One project's month, as `GET /usage/:projectId` answers it. */
12
+ export interface CliProjectUsage {
13
+ projectId: string;
14
+ month: string;
15
+ complete: boolean;
16
+ days: {
17
+ day: string;
18
+ requests: number;
19
+ errors: number;
20
+ missedSamples: number;
21
+ }[];
22
+ totals: {
23
+ requests: number;
24
+ errors: number;
25
+ daysRecorded: number;
26
+ daysWithGaps: number;
27
+ };
28
+ quotas: {
29
+ requestsPerMonth: number | null;
30
+ };
31
+ fraction: number;
32
+ warn: boolean;
33
+ overageEur: number;
34
+ billed: boolean;
35
+ projection: {
36
+ requests: number;
37
+ fraction: number;
38
+ overageEur: number;
39
+ } | null;
40
+ enforcement: {
41
+ kind: string;
42
+ message: string;
43
+ };
44
+ caveats: CliUsageCaveat[];
45
+ }
46
+ export interface CliOrgUsage {
47
+ organizationId: string;
48
+ month: string;
49
+ complete: boolean;
50
+ projects: (CliProjectUsage & {
51
+ name: string | null;
52
+ })[];
53
+ totals: {
54
+ requests: number;
55
+ errors: number;
56
+ overageEur: number;
57
+ projectedOverageEur: number | null;
58
+ };
59
+ truncated: boolean;
60
+ }
61
+ /** The allowance as a bar of 20 cells, coloured like the console: amber from 80%, red past it. */
62
+ export declare function usageBar(fraction: number): string;
63
+ export declare function usageCommand(rawArgs: string[]): Promise<void>;
@@ -380,6 +380,16 @@ export type SchemaGeneration = "generated" | "skipped" | "failed";
380
380
  * failed, the preflight is the remaining safety net and still runs.
381
381
  */
382
382
  export declare function needsStaleSchemaPreflight(generation: SchemaGeneration): boolean;
383
+ /**
384
+ * What dev prints once a collection edit's regeneration is done.
385
+ *
386
+ * The green "regenerated" box only when neither half failed. It used to be
387
+ * printed unconditionally, right under "⚠ Could not regenerate the database
388
+ * schema … nothing was applied" — and then the backend refused to boot over
389
+ * the same collection error, so the success line was the one wrong thing on
390
+ * the screen.
391
+ */
392
+ export declare function collectionChangeSummary(schema: SchemaGeneration, sdk: SchemaGeneration): string[];
383
393
  /**
384
394
  * One variable's value out of `.env` text, or undefined when it has none.
385
395
  *
@@ -61,5 +61,5 @@ export declare const DOCTOR_FLAGS: {
61
61
  * The line handed to the driver, every path on it resolved from where the
62
62
  * command was run — the driver runs in `backend/`. See `utils/path-flags.ts`.
63
63
  */
64
- export declare function doctorDriverArgs(rawArgs: string[], cwd: string): string[];
64
+ export declare function doctorDriverArgs(rawArgs: string[], cwd: string, projectRoot?: string): string[];
65
65
  export declare function doctorCommand(rawArgs: string[]): Promise<void>;
@@ -0,0 +1,94 @@
1
+ import { resolveCollectionsDir } from "../utils/collections-dir.js";
2
+ /** What `rebase generate` dispatches. Read by `cli.ts` to name the subcommand. */
3
+ export declare const GENERATE_SUBCOMMANDS: readonly ["view"];
4
+ export interface GenerateViewOptions {
5
+ projectRoot: string;
6
+ slug: string;
7
+ /** Register as a tab on this collection's records instead of as a screen. */
8
+ collection?: string;
9
+ /** The label in the sidebar or on the tab. Defaults to the slug in sentence case. */
10
+ name?: string;
11
+ /** A Lucide icon name for the sidebar. Screens only. */
12
+ icon?: string;
13
+ /** Replace an existing view file. Registration is never duplicated. */
14
+ force?: boolean;
15
+ }
16
+ export interface PlannedFile {
17
+ /** Absolute path. */
18
+ path: string;
19
+ contents: string;
20
+ action: "create" | "update" | "replace";
21
+ }
22
+ export interface GenerateViewPlan {
23
+ kind: "app" | "entity";
24
+ componentName: string;
25
+ viewFile: string;
26
+ files: PlannedFile[];
27
+ /** Steps the command could not take itself, as sentences to print. */
28
+ manualSteps: string[];
29
+ }
30
+ /** `orders-board` → `OrdersBoardView`; `sales-view` → `SalesView`, not `SalesViewView`. */
31
+ export declare function viewComponentName(slug: string): string;
32
+ /** `orders-board` → `Orders board`: labels are sentence case in the admin. */
33
+ export declare function viewLabel(slug: string): string;
34
+ /**
35
+ * The source with every string, template literal, regular expression and
36
+ * comment blanked out, character for character, so brackets and keys can be
37
+ * found by position without being fooled by a `{` inside a string. String
38
+ * contents become `_` (they are still "something"), comments become spaces.
39
+ *
40
+ * Exported for its tests.
41
+ */
42
+ export declare function maskCode(source: string): string;
43
+ /** The admin's frontend directory: the static app that mounts the CMS, or `frontend/`. */
44
+ export declare function resolveFrontendDir(projectRoot: string): string | undefined;
45
+ /** `<config>/collections`, as the backend app declares it — one resolver for every command. */
46
+ export { resolveCollectionsDir };
47
+ type ViewTemplateOptions = {
48
+ slug: string;
49
+ componentName: string;
50
+ label: string;
51
+ collection: string;
52
+ };
53
+ export declare function appViewSource(options: ViewTemplateOptions): string;
54
+ export declare function entityViewSource(options: ViewTemplateOptions): string;
55
+ /**
56
+ * Everything `rebase generate view` would write, without writing it.
57
+ *
58
+ * @throws UsageError when the slug is not a slug, there is no admin panel, the
59
+ * view already exists (without `force`), or `--collection` names nothing.
60
+ */
61
+ export declare function planGenerateView(options: GenerateViewOptions): GenerateViewPlan;
62
+ /**
63
+ * `views/index.ts` with one more entry, `"already"` when the slug is listed, or
64
+ * `undefined` when the file has no `export const views … = [`.
65
+ *
66
+ * Exported for its tests.
67
+ */
68
+ export declare function registerAppView(source: string, options: {
69
+ slug: string;
70
+ label: string;
71
+ icon: string;
72
+ componentName: string;
73
+ }): string | "already" | undefined;
74
+ /**
75
+ * `App.tsx` with `views={views}` on `<RebaseCMS>` and its import, `"already"`
76
+ * when it passes exactly that, or `undefined` when it cannot be done safely:
77
+ * no `<RebaseCMS`, a `views` prop of its own, or a `views` name already in scope.
78
+ *
79
+ * Exported for its tests.
80
+ */
81
+ export declare function wireViewsIntoApp(source: string): string | "already" | undefined;
82
+ /**
83
+ * The collection file with a `{ key, name, Builder }` entry in the
84
+ * `admin.entityViews` of the collection whose `slug:` is at `slugAt`;
85
+ * `"already"` when that key is there; `undefined` when the shape cannot be read.
86
+ *
87
+ * Exported for its tests.
88
+ */
89
+ export declare function registerEntityView(source: string, slugAt: number, view: {
90
+ key: string;
91
+ name: string;
92
+ builder: string;
93
+ }): string | "already" | undefined;
94
+ export declare function generateCommand(subcommand: string | undefined, rawArgs?: string[]): Promise<void>;
@@ -50,6 +50,21 @@ export declare const REGISTER_FILE = "register.ts";
50
50
  * the registration rather than imported from the SDK.
51
51
  */
52
52
  export declare function registrationDir(collectionsDir: string): string;
53
+ /**
54
+ * Write the server-side registration from the collection files in
55
+ * `collectionsDir`, exactly as `rebase generate-sdk` writes it, for a build.
56
+ *
57
+ * Only for a project that asked for it: `registerDatabase` in `rebase.json`,
58
+ * or a registration an earlier `--register` left, which is kept current. The
59
+ * registration lives in gitignored `config/generated/`, so a fresh clone (a CI
60
+ * job) has none until something writes it, and a bundle compiled without it
61
+ * types `context.data` as untyped rows: callbacks that read a typed column
62
+ * fail to compile there while they compile locally.
63
+ *
64
+ * Returns the directory written, or null when there was nothing to do.
65
+ * Throws when a `register.ts` there is not ours, as `generate-sdk` refuses.
66
+ */
67
+ export declare function writeRegistrationForBuild(collectionsDir: string, registerDatabase: boolean): Promise<string | null>;
53
68
  /**
54
69
  * The base URL to show in the printed usage example.
55
70
  *