@rebasepro/cli 0.21.0 → 0.21.1-canary.g8c5a265
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.
- package/README.md +13 -3
- package/bin/rebase.js +4 -1
- package/dist/commands/cloud/errors.d.ts +5 -0
- package/dist/index.es.js +53 -14
- package/dist/index.es.js.map +1 -1
- package/dist/manifest.d.ts +1 -1
- package/package.json +7 -7
- package/templates/overlays/baas/README.md +5 -3
- package/templates/overlays/baas/ai-instructions.md +40 -0
- package/templates/template/README.md +2 -2
- package/templates/template/ai-instructions.md +2 -2
package/README.md
CHANGED
|
@@ -9,8 +9,8 @@ pnpm add -g @rebasepro/cli
|
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
ESM-only: `"type": "module"` with no CommonJS build, so it is loaded with
|
|
12
|
-
`import`.
|
|
13
|
-
`require(esm)
|
|
12
|
+
`import`. It needs Node `>=22.22.0` (its `engines` floor), where `require()`
|
|
13
|
+
of it resolves too: Node has supported `require(esm)` since 22.12.
|
|
14
14
|
|
|
15
15
|
The CLI is also bundled with every Rebase project as a local dependency.
|
|
16
16
|
|
|
@@ -20,19 +20,29 @@ The CLI is also bundled with every Rebase project as a local dependency.
|
|
|
20
20
|
|---------|-------------|
|
|
21
21
|
| `rebase init` | Scaffold a new Rebase project |
|
|
22
22
|
| `rebase dev` | Start the development server (backend + frontend) |
|
|
23
|
-
| `rebase build` | Build
|
|
23
|
+
| `rebase build` | Build the apps declared in `rebase.json` into a bundle |
|
|
24
|
+
| `rebase normalize-imports` | Complete compiled output's relative imports for Node ESM |
|
|
24
25
|
| `rebase start` | Start the backend server (production) |
|
|
26
|
+
| `rebase apps list` | Show the apps this repository declares |
|
|
25
27
|
| `rebase schema generate` | Generate Drizzle schema from collection definitions |
|
|
26
28
|
| `rebase schema introspect` | Introspect an existing database → Rebase collections |
|
|
29
|
+
| `rebase schema stale` | Report generated schema files the collections have moved past |
|
|
27
30
|
| `rebase db push` | Apply schema directly to database (dev). Previews the plan and refuses destructive changes (e.g. dropped columns) unless confirmed interactively or run with `--allow-destructive`. |
|
|
28
31
|
| `rebase db generate` | Generate SQL migration files |
|
|
29
32
|
| `rebase db migrate` | Run pending migrations |
|
|
33
|
+
| `rebase db pull` | Copy another database into local development |
|
|
34
|
+
| `rebase db branch` | Create, list, switch and delete database branches |
|
|
35
|
+
| `rebase db stop` | Stop the managed development database (data is kept) |
|
|
36
|
+
| `rebase db reset` | Delete the managed development database and start over |
|
|
30
37
|
| `rebase generate-sdk` | Generate a typed TypeScript SDK from collections |
|
|
31
38
|
| `rebase auth reset-password` | Reset a user's password |
|
|
39
|
+
| `rebase api-keys list \| create \| revoke` | Manage scoped service API keys |
|
|
32
40
|
| `rebase doctor` | Detect schema drift between collections, Drizzle schema, and database |
|
|
33
41
|
| `rebase status` | Show every resource this project declares and whether its variables are set |
|
|
34
42
|
| `rebase resources` | List the databases, buckets and topics this project declares |
|
|
43
|
+
| `rebase eject` | Own the server process and the image (one-way) |
|
|
35
44
|
| `rebase skills install` | Install Rebase agent skills for your AI coding assistant |
|
|
45
|
+
| `rebase telemetry` | Anonymous usage sharing (opt-in, off by default) |
|
|
36
46
|
| `rebase cloud <command>` | Manage your apps on Rebase Cloud (auth, deploy, databases, …) |
|
|
37
47
|
|
|
38
48
|
Run `rebase --help` or `rebase <command> --help` for detailed usage.
|
package/bin/rebase.js
CHANGED
|
@@ -188,7 +188,10 @@ const { entry } = await import("../dist/index.es.js");
|
|
|
188
188
|
* `utils/args.ts` marks those with `isUsageError` rather than a class, because
|
|
189
189
|
* this file imports the bundle and `instanceof` cannot reach across it.
|
|
190
190
|
*/
|
|
191
|
-
|
|
191
|
+
// After the bundle, which already imports this package, and spelled as the
|
|
192
|
+
// commands spell it: `wantsRawError` in `commands/cloud/errors.ts`.
|
|
193
|
+
const { parseEnvBoolean } = await import("@rebasepro/types");
|
|
194
|
+
const wantsStack = process.argv.includes("--debug") || parseEnvBoolean(process.env.REBASE_DEBUG) === true;
|
|
192
195
|
|
|
193
196
|
entry(process.argv).catch((error) => {
|
|
194
197
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -76,5 +76,10 @@ export declare function summarizeError(error: unknown, context: string): ErrorSu
|
|
|
76
76
|
* `--debug` is already what `bin/rebase.js` prints after every failure as the
|
|
77
77
|
* thing to add, so the raw payload hangs off the flag people are told to reach
|
|
78
78
|
* for rather than off one invented here.
|
|
79
|
+
*
|
|
80
|
+
* The one reader of `REBASE_DEBUG` in the commands, spelled as the bin spells
|
|
81
|
+
* it. It used to be `=== "1"` here while the quote fallbacks in `resources.ts`
|
|
82
|
+
* tested the raw string for truthiness, so `=true` hid the body and `=0`
|
|
83
|
+
* printed the fallback.
|
|
79
84
|
*/
|
|
80
85
|
export declare function wantsRawError(argv?: readonly string[]): boolean;
|
package/dist/index.es.js
CHANGED
|
@@ -22,7 +22,7 @@ import { execFileSync, spawn, spawnSync } from "child_process";
|
|
|
22
22
|
import os from "os";
|
|
23
23
|
import { createRebaseClient } from "@rebasepro/client";
|
|
24
24
|
import dotenv from "dotenv";
|
|
25
|
-
import { BUNDLE_FORMAT_VERSION, DEFAULT_DATA_SOURCE_KEY, DEFAULT_RESOURCE_KEY, DEFAULT_STORAGE_SOURCE_KEY, RUNTIME_CONTRACT_VERSION, buildResourceGraph, computeSchemaVersion, declareFunction, declaredQueueConsumers, declaredResources, declaredSubscriptions, deserializeCollections, envBasesForResource, findEnvSuffixCollision, findStorageSuffixCollision, getDataSourceCapabilities, isResourceHandle, reservedPrefixFor, resetDeclaredQueueConsumers, resetDeclaredResources, resetDeclaredSubscriptions, resolveResourceRefs, resourceEnvSuffix, resourceId, resourceKeyOf, resourceToDataSource } from "@rebasepro/types";
|
|
25
|
+
import { BUNDLE_FORMAT_VERSION, DEFAULT_DATA_SOURCE_KEY, DEFAULT_RESOURCE_KEY, DEFAULT_STORAGE_SOURCE_KEY, RUNTIME_CONTRACT_VERSION, buildResourceGraph, computeSchemaVersion, declareFunction, declaredQueueConsumers, declaredResources, declaredSubscriptions, deserializeCollections, envBasesForResource, findEnvSuffixCollision, findStorageSuffixCollision, getDataSourceCapabilities, isResourceHandle, parseEnvBoolean, reservedPrefixFor, resetDeclaredQueueConsumers, resetDeclaredResources, resetDeclaredSubscriptions, resolveResourceRefs, resourceEnvSuffix, resourceId, resourceKeyOf, resourceToDataSource } from "@rebasepro/types";
|
|
26
26
|
import { CodegenError, generateSDK, toSafeIdentifier } from "@rebasepro/codegen";
|
|
27
27
|
import { createRequire } from "module";
|
|
28
28
|
import { randomBytes as randomBytes$1 } from "node:crypto";
|
|
@@ -186,6 +186,29 @@ function parseCommandArgs({ spec, rawArgs, commandWords, command, maxPositionals
|
|
|
186
186
|
//#endregion
|
|
187
187
|
//#region src/commands/cloud/errors.ts
|
|
188
188
|
/**
|
|
189
|
+
* Turning a control-plane failure into something the caller can act on.
|
|
190
|
+
*
|
|
191
|
+
* The control plane talks to Kubernetes, and when Kubernetes refuses it, the
|
|
192
|
+
* refusal travels back verbatim: a whole `Status` object, the request headers,
|
|
193
|
+
* an `audit-id`, an `x-kubernetes-pf-flowschema-uid`. That reached the user's
|
|
194
|
+
* terminal unedited. Two things are wrong with it beyond the noise.
|
|
195
|
+
*
|
|
196
|
+
* The first is that the one sentence that matters is buried in the middle of a
|
|
197
|
+
* JSON blob, so the remedy — if there is one — is the hardest part to find.
|
|
198
|
+
*
|
|
199
|
+
* The second is worse, and is the reason this file exists rather than a
|
|
200
|
+
* `slice(0, 200)`. A `403` naming a `system:serviceaccount:` is a statement
|
|
201
|
+
* about the PLATFORM's own credentials: some role the control plane runs as is
|
|
202
|
+
* missing a grant. Nothing in the user's project can change that — not the
|
|
203
|
+
* collections, not `rebase.json`, not the deploy flags — and the error, printed
|
|
204
|
+
* raw in the middle of `rebase cloud deploy`, reads exactly like a project
|
|
205
|
+
* fault. Someone acting on that reading deletes working code looking for the
|
|
206
|
+
* cause. (That is not hypothetical: three cron jobs were removed from a project
|
|
207
|
+
* to test whether they caused a `cronjobs.batch` 403. They did not.)
|
|
208
|
+
*
|
|
209
|
+
* So this classifies before it summarises, and says whose problem it is.
|
|
210
|
+
*/
|
|
211
|
+
/**
|
|
189
212
|
* The service accounts a Kubernetes 403 can name, and what each means.
|
|
190
213
|
*
|
|
191
214
|
* `system:serviceaccount:` is the platform's own identity — the control plane's
|
|
@@ -308,9 +331,14 @@ function truncate(text) {
|
|
|
308
331
|
* `--debug` is already what `bin/rebase.js` prints after every failure as the
|
|
309
332
|
* thing to add, so the raw payload hangs off the flag people are told to reach
|
|
310
333
|
* for rather than off one invented here.
|
|
334
|
+
*
|
|
335
|
+
* The one reader of `REBASE_DEBUG` in the commands, spelled as the bin spells
|
|
336
|
+
* it. It used to be `=== "1"` here while the quote fallbacks in `resources.ts`
|
|
337
|
+
* tested the raw string for truthiness, so `=true` hid the body and `=0`
|
|
338
|
+
* printed the fallback.
|
|
311
339
|
*/
|
|
312
340
|
function wantsRawError(argv = process.argv) {
|
|
313
|
-
return argv.includes("--debug") || process.env.REBASE_DEBUG ===
|
|
341
|
+
return argv.includes("--debug") || parseEnvBoolean(process.env.REBASE_DEBUG) === true;
|
|
314
342
|
}
|
|
315
343
|
//#endregion
|
|
316
344
|
//#region src/commands/cloud/context.ts
|
|
@@ -714,8 +742,7 @@ function initOutputMode(rawArgs) {
|
|
|
714
742
|
argv: rawArgs.slice(2),
|
|
715
743
|
permissive: true
|
|
716
744
|
})["--json"]) JSON_MODE = true;
|
|
717
|
-
else
|
|
718
|
-
else JSON_MODE = process.env.REBASE_JSON === "1" || process.stdout.isTTY !== true;
|
|
745
|
+
else JSON_MODE = parseEnvBoolean(process.env.REBASE_JSON) ?? process.stdout.isTTY !== true;
|
|
719
746
|
return JSON_MODE;
|
|
720
747
|
}
|
|
721
748
|
/** Whether the current invocation is emitting machine-readable JSON. */
|
|
@@ -1446,6 +1473,18 @@ function endpoint() {
|
|
|
1446
1473
|
return process.env.REBASE_TELEMETRY_ENDPOINT?.trim() || "https://app.rebase.pro/api/functions/telemetry";
|
|
1447
1474
|
}
|
|
1448
1475
|
/**
|
|
1476
|
+
* Set to anything but a spelled no.
|
|
1477
|
+
*
|
|
1478
|
+
* The conventions behind these variables make presence the signal —
|
|
1479
|
+
* `CI=woodpecker` is a CI run, `DO_NOT_TRACK=please` is an answer — so a value
|
|
1480
|
+
* the parser does not recognise still counts, and the refusal holds. Only the
|
|
1481
|
+
* platform's spellings of no turn one off. It was `!== "0"` for two of them and
|
|
1482
|
+
* `!== "false"` for `CI`, so `CI=0` read as a runner.
|
|
1483
|
+
*/
|
|
1484
|
+
function setAndNotNo(value) {
|
|
1485
|
+
return value !== void 0 && value.trim() !== "" && parseEnvBoolean(value) !== false;
|
|
1486
|
+
}
|
|
1487
|
+
/**
|
|
1449
1488
|
* The one function that decides whether anything leaves the machine.
|
|
1450
1489
|
*
|
|
1451
1490
|
* Every path is a refusal except the last, which is the point: consent is
|
|
@@ -1465,9 +1504,9 @@ function endpoint() {
|
|
|
1465
1504
|
* project.ts on why the reverse is refused.
|
|
1466
1505
|
*/
|
|
1467
1506
|
function suppressionReason(env = process.env, cwd = process.cwd()) {
|
|
1468
|
-
if (env.DO_NOT_TRACK
|
|
1469
|
-
if (env.REBASE_TELEMETRY_DISABLED
|
|
1470
|
-
if (env.CI
|
|
1507
|
+
if (setAndNotNo(env.DO_NOT_TRACK)) return "do_not_track";
|
|
1508
|
+
if (setAndNotNo(env.REBASE_TELEMETRY_DISABLED)) return "rebase_telemetry_disabled";
|
|
1509
|
+
if (setAndNotNo(env.CI)) return "ci";
|
|
1471
1510
|
if (readProjectPolicy(cwd) === "opt_out") return "project_opt_out";
|
|
1472
1511
|
const config = readConfig();
|
|
1473
1512
|
if (config.enabled === void 0) return "not_asked";
|
|
@@ -2343,7 +2382,7 @@ async function replacePlaceholders(options) {
|
|
|
2343
2382
|
const matches = [...content.matchAll(/"(@rebasepro\/[^"]+)":\s*"workspace:\*"/g)];
|
|
2344
2383
|
for (const match of matches) allPackages.add(match[1]);
|
|
2345
2384
|
}
|
|
2346
|
-
const probe = process.env.REBASE_E2E ===
|
|
2385
|
+
const probe = parseEnvBoolean(process.env.REBASE_E2E) === true || version === "unknown" ? { kind: "published" } : await probeRelease(version);
|
|
2347
2386
|
if (probe.kind === "gap") throw new Error(`Rebase ${version} is not fully published to npm.\n\n${RELEASE_PROBE_PACKAGE} has no ${version} release — the registry has ${probe.found}.\nEvery @rebasepro package ships at one version, so scaffolding would pin ${allPackages.size}\ndependencies at a version that is not there, and the install would fail.\n\nThat is a release gap in Rebase itself — not a problem with your machine,
|
|
2348
2387
|
your network, or your package manager.
|
|
2349
2388
|
|
|
@@ -4856,7 +4895,7 @@ function refuseStorageBlock(raw, issues) {
|
|
|
4856
4895
|
* else. It used to be inferred from the presence of `backend/src/index.ts`,
|
|
4857
4896
|
* which every scaffolded project had whether or not it wanted its own server, so
|
|
4858
4897
|
* projects predating the manifest silently landed on the custom runtime and paid
|
|
4859
|
-
* for it
|
|
4898
|
+
* for it.
|
|
4860
4899
|
*/
|
|
4861
4900
|
function synthesizeManifest(projectRoot) {
|
|
4862
4901
|
const exists = (relative) => fs.existsSync(path.join(projectRoot, relative));
|
|
@@ -5774,8 +5813,8 @@ async function devCommand(rawArgs) {
|
|
|
5774
5813
|
* gating only the preflight left the managed PGlite starting anyway, which
|
|
5775
5814
|
* is the one database a scaffolded project would otherwise get.
|
|
5776
5815
|
*/
|
|
5777
|
-
const noDb = Boolean(args["--no-db"]) || process.env.REBASE_DEV_NO_DB ===
|
|
5778
|
-
const shouldGenerate = args["--generate"] || process.env.REBASE_AUTO_GENERATE ===
|
|
5816
|
+
const noDb = Boolean(args["--no-db"]) || parseEnvBoolean(process.env.REBASE_DEV_NO_DB) === true;
|
|
5817
|
+
const shouldGenerate = args["--generate"] || parseEnvBoolean(process.env.REBASE_AUTO_GENERATE) === true || parseEnvBoolean(process.env.REBASE_GENERATE) === true;
|
|
5779
5818
|
const { port: startPort, source: startPortSource } = resolveStartPort(projectRoot, args["--port"]);
|
|
5780
5819
|
const portIsPinned = args["--port"] !== void 0;
|
|
5781
5820
|
const pinnedFrontendPort = process.env.REBASE_FRONTEND_PORT;
|
|
@@ -7184,7 +7223,7 @@ function collectDeclaredDependencies(projectRoot) {
|
|
|
7184
7223
|
if (typeof version === "string" && version.startsWith("workspace:")) continue;
|
|
7185
7224
|
if (resolvesToWorkspacePackage(projectRoot, name)) continue;
|
|
7186
7225
|
const protocol = typeof version === "string" ? nonRegistrySpecifier(version) : null;
|
|
7187
|
-
if (protocol && process.env.REBASE_E2E ===
|
|
7226
|
+
if (protocol && parseEnvBoolean(process.env.REBASE_E2E) === true && protocol === "file:") {
|
|
7188
7227
|
declared[name] = version;
|
|
7189
7228
|
continue;
|
|
7190
7229
|
}
|
|
@@ -13351,7 +13390,7 @@ async function billingCommand(rawArgs) {
|
|
|
13351
13390
|
if (hasCluster) monthly = `${monthly} — platform fee, your own cluster`;
|
|
13352
13391
|
}
|
|
13353
13392
|
} catch (err) {
|
|
13354
|
-
if (
|
|
13393
|
+
if (wantsRawError()) console.error(` (no price: ${err instanceof Error ? err.message : String(err)})`);
|
|
13355
13394
|
}
|
|
13356
13395
|
emit(() => {
|
|
13357
13396
|
console.log("");
|
|
@@ -13470,7 +13509,7 @@ async function computeCommand(action, rawArgs) {
|
|
|
13470
13509
|
path: "quote"
|
|
13471
13510
|
});
|
|
13472
13511
|
} catch (err) {
|
|
13473
|
-
if (
|
|
13512
|
+
if (wantsRawError()) console.error(` (no price: ${err instanceof Error ? err.message : String(err)})`);
|
|
13474
13513
|
}
|
|
13475
13514
|
emit(() => {
|
|
13476
13515
|
console.log("");
|