@rebasepro/cli 0.10.1-canary.18115ba → 0.10.1-canary.811b3da
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/dist/commands/cloud/context.d.ts +0 -10
- package/dist/commands/cloud/deployments.d.ts +0 -16
- package/dist/commands/cloud/env.d.ts +0 -2
- package/dist/commands/cloud/resources.d.ts +0 -38
- package/dist/index.es.js +56 -327
- package/dist/index.es.js.map +1 -1
- package/dist/utils/package-manager.d.ts +2 -26
- package/package.json +7 -7
|
@@ -100,16 +100,6 @@ export declare function initOutputMode(rawArgs: string[]): boolean;
|
|
|
100
100
|
export declare function isJsonMode(): boolean;
|
|
101
101
|
/** Force the mode (tests only — production latches it via `initOutputMode`). */
|
|
102
102
|
export declare function setJsonModeForTest(value: boolean): void;
|
|
103
|
-
/**
|
|
104
|
-
* Write one JSON value to stdout, followed by a newline.
|
|
105
|
-
*
|
|
106
|
-
* Indented, because the overwhelmingly common reader is a person or an agent
|
|
107
|
-
* looking at a terminal — JSON mode is entered automatically whenever stdout is
|
|
108
|
-
* not a TTY, so `rebase cloud deployments list` piped anywhere at all produced
|
|
109
|
-
* a project's entire deployment history as one unwrapped line. `JSON.parse`
|
|
110
|
-
* does not care about the whitespace; everything else does.
|
|
111
|
-
*/
|
|
112
|
-
export declare function printJson(value: unknown): void;
|
|
113
103
|
/**
|
|
114
104
|
* The one output primitive every new command uses: in JSON mode emit `json`
|
|
115
105
|
* (and nothing else); otherwise run `human`. Keeping the two behind a single
|
|
@@ -18,10 +18,6 @@ export interface DeploymentRow {
|
|
|
18
18
|
triggered_by_user_id?: string;
|
|
19
19
|
gitCommitHash?: string;
|
|
20
20
|
gitCommitMessage?: string;
|
|
21
|
-
deployMessage?: string;
|
|
22
|
-
deploy_message?: string;
|
|
23
|
-
frameworkVersion?: string;
|
|
24
|
-
framework_version?: string;
|
|
25
21
|
}
|
|
26
22
|
/**
|
|
27
23
|
* The backend's rule EXACTLY: a rollback is honoured only for a successful
|
|
@@ -37,18 +33,6 @@ export declare function triggerInfo(dep: DeploymentRow): {
|
|
|
37
33
|
};
|
|
38
34
|
/** Shape one deployment row into the stable JSON view the CLI publishes. */
|
|
39
35
|
export declare function deploymentView(dep: DeploymentRow): Record<string, unknown>;
|
|
40
|
-
/**
|
|
41
|
-
* Rows shown when `--limit` is not given.
|
|
42
|
-
*
|
|
43
|
-
* History is unbounded and grows one row per deploy, so "all of it" is the
|
|
44
|
-
* wrong default in both directions: a wall of near-identical lines in a
|
|
45
|
-
* terminal, and — since JSON mode is entered automatically for any non-TTY
|
|
46
|
-
* stdout — a project's entire history dumped at anything that pipes the
|
|
47
|
-
* command. Recent deploys are what the question is almost always about.
|
|
48
|
-
*/
|
|
49
|
-
export declare const DEFAULT_DEPLOYMENTS_LIMIT = 20;
|
|
50
|
-
/** `--limit N`, bounded. A garbage value is a refusal, never a silent default. */
|
|
51
|
-
export declare function parseDeploymentsLimit(raw: number | undefined): number;
|
|
52
36
|
export declare function deploymentsListCommand(rawArgs: string[]): Promise<void>;
|
|
53
37
|
export declare function rollbackCommand(rawArgs: string[]): Promise<void>;
|
|
54
38
|
export declare function cancelCommand(rawArgs: string[]): Promise<void>;
|
|
@@ -1,44 +1,6 @@
|
|
|
1
|
-
/** The control plane's verdict on what a tenant's uploads actually do. */
|
|
2
|
-
interface StorageState {
|
|
3
|
-
effective?: {
|
|
4
|
-
kind?: string;
|
|
5
|
-
summary?: string;
|
|
6
|
-
storageType?: string;
|
|
7
|
-
missing?: string[];
|
|
8
|
-
};
|
|
9
|
-
source?: string;
|
|
10
|
-
configured?: string;
|
|
11
|
-
overridden?: boolean;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* One line describing this project's storage — or `undefined` when the control
|
|
15
|
-
* plane could not be asked, which prints as a blank rather than a guess.
|
|
16
|
-
*
|
|
17
|
-
* `status` used to render the `storages` row and nothing else, so a project
|
|
18
|
-
* whose bucket is configured through its own `STORAGE_TYPE`/`S3_*` variables —
|
|
19
|
-
* the supported path, and the one `mergeStorageEnv` deliberately lets WIN over
|
|
20
|
-
* the row — was reported as `Storage: none` while its pod logged `Initialized
|
|
21
|
-
* storage backends count: 1` against a live bucket. Storage is the thing an app
|
|
22
|
-
* refuses to boot without, so that false negative sends someone off to
|
|
23
|
-
* provision a bucket they already have. The row is not the answer; the tenant's
|
|
24
|
-
* resolved environment is, and the control plane computes it with the same two
|
|
25
|
-
* functions the build log uses.
|
|
26
|
-
*/
|
|
27
|
-
export declare function describeStorageState(state: StorageState | undefined): string | undefined;
|
|
28
|
-
/**
|
|
29
|
-
* One line describing the database.
|
|
30
|
-
*
|
|
31
|
-
* `connectionStatus` is written `"untested"` at creation and only ever changed
|
|
32
|
-
* by `rebase cloud db test`, so `managed (untested)` was reporting the absence
|
|
33
|
-
* of a manual test as though it were the database's condition — on a project
|
|
34
|
-
* that had just deployed against it. A never-tested database says only its
|
|
35
|
-
* type; the verdict appears once there is one.
|
|
36
|
-
*/
|
|
37
|
-
export declare function describeDatabaseState(db: Record<string, unknown> | undefined): string | undefined;
|
|
38
1
|
export declare function statusCommand(rawArgs: string[]): Promise<void>;
|
|
39
2
|
export declare function metricsCommand(rawArgs: string[]): Promise<void>;
|
|
40
3
|
export declare function webhooksCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void>;
|
|
41
4
|
export declare function storageCommand(action: string | undefined, rawArgs: string[]): Promise<void>;
|
|
42
5
|
export declare function clustersCommand(rawArgs: string[]): Promise<void>;
|
|
43
6
|
export declare function billingCommand(rawArgs: string[]): Promise<void>;
|
|
44
|
-
export {};
|
package/dist/index.es.js
CHANGED
|
@@ -23,61 +23,21 @@ import { createRequire } from "module";
|
|
|
23
23
|
* the rest of the CLI never has to hardcode a specific PM.
|
|
24
24
|
*/
|
|
25
25
|
/**
|
|
26
|
-
* How long to wait for `pnpm --version` before giving up on the probe.
|
|
27
|
-
*
|
|
28
|
-
* `pnpm --version` is a cold Node start, and on a machine that is busy — a
|
|
29
|
-
* parallel install, a full test run — it routinely takes seconds. Measured at
|
|
30
|
-
* 630ms, 990ms and 4293ms on three consecutive runs of one developer laptop
|
|
31
|
-
* under load, so the previous 3s budget was inside the normal spread rather
|
|
32
|
-
* than safely outside it.
|
|
33
|
-
*/
|
|
34
|
-
var PNPM_PROBE_TIMEOUT_MS = 5e3;
|
|
35
|
-
/** Memoised result of the probe. pnpm cannot appear or vanish mid-process. */
|
|
36
|
-
var cachedPnpmAvailable;
|
|
37
|
-
/**
|
|
38
|
-
* Decide availability from a `spawnSync` outcome.
|
|
39
|
-
*
|
|
40
|
-
* Split out from the spawn itself so the decision is testable without starting
|
|
41
|
-
* a process — which is what made the old test load-sensitive and occasionally
|
|
42
|
-
* red for reasons that had nothing to do with the code under test.
|
|
43
|
-
*
|
|
44
|
-
* The three outcomes are distinguishable, and the old code conflated two of
|
|
45
|
-
* them by asking only `status === 0`:
|
|
46
|
-
*
|
|
47
|
-
* not installed status null, signal null, error.code ENOENT
|
|
48
|
-
* timed out status null, signal SIGTERM, error.code ETIMEDOUT
|
|
49
|
-
* broken install status non-zero, no error
|
|
50
|
-
*/
|
|
51
|
-
function pnpmAvailabilityFromProbe(res) {
|
|
52
|
-
const code = res.error?.code;
|
|
53
|
-
if (code === "ENOENT") return false;
|
|
54
|
-
if (code === "ETIMEDOUT" || res.signal) return true;
|
|
55
|
-
if (res.error) return false;
|
|
56
|
-
return res.status === 0;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
26
|
* Whether pnpm is runnable on this machine.
|
|
60
27
|
*
|
|
61
28
|
* Used to decide whether a fresh project can be scaffolded with pnpm. Kept
|
|
62
|
-
* cheap and non-interactive (
|
|
63
|
-
* hangs detection if a corepack shim misbehaves
|
|
64
|
-
* detection in one CLI run costs one process rather than one per call.
|
|
29
|
+
* cheap and non-interactive (short timeout, output discarded) so it never
|
|
30
|
+
* hangs detection if a corepack shim misbehaves.
|
|
65
31
|
*/
|
|
66
32
|
function isPnpmAvailable() {
|
|
67
|
-
if (cachedPnpmAvailable !== void 0) return cachedPnpmAvailable;
|
|
68
33
|
try {
|
|
69
|
-
|
|
34
|
+
return spawnSync("pnpm", ["--version"], {
|
|
70
35
|
stdio: "ignore",
|
|
71
|
-
timeout:
|
|
72
|
-
})
|
|
36
|
+
timeout: 3e3
|
|
37
|
+
}).status === 0;
|
|
73
38
|
} catch {
|
|
74
|
-
|
|
39
|
+
return false;
|
|
75
40
|
}
|
|
76
|
-
return cachedPnpmAvailable;
|
|
77
|
-
}
|
|
78
|
-
/** Forget the memoised probe. For tests; nothing in a CLI run needs it. */
|
|
79
|
-
function resetPnpmAvailabilityCache() {
|
|
80
|
-
cachedPnpmAvailable = void 0;
|
|
81
41
|
}
|
|
82
42
|
/**
|
|
83
43
|
* Detect the package manager for a Rebase project.
|
|
@@ -676,17 +636,9 @@ var ANSI_RE = /\[[0-9;]*m/g;
|
|
|
676
636
|
function stripAnsi(s) {
|
|
677
637
|
return s.replace(ANSI_RE, "");
|
|
678
638
|
}
|
|
679
|
-
/**
|
|
680
|
-
* Write one JSON value to stdout, followed by a newline.
|
|
681
|
-
*
|
|
682
|
-
* Indented, because the overwhelmingly common reader is a person or an agent
|
|
683
|
-
* looking at a terminal — JSON mode is entered automatically whenever stdout is
|
|
684
|
-
* not a TTY, so `rebase cloud deployments list` piped anywhere at all produced
|
|
685
|
-
* a project's entire deployment history as one unwrapped line. `JSON.parse`
|
|
686
|
-
* does not care about the whitespace; everything else does.
|
|
687
|
-
*/
|
|
639
|
+
/** Write one JSON value to stdout, followed by a newline. */
|
|
688
640
|
function printJson(value) {
|
|
689
|
-
process.stdout.write(JSON.stringify(value
|
|
641
|
+
process.stdout.write(JSON.stringify(value) + "\n");
|
|
690
642
|
}
|
|
691
643
|
/**
|
|
692
644
|
* The one output primitive every new command uses: in JSON mode emit `json`
|
|
@@ -3469,35 +3421,6 @@ async function createSourceTarball(sourceDir) {
|
|
|
3469
3421
|
}
|
|
3470
3422
|
return tarPath;
|
|
3471
3423
|
}
|
|
3472
|
-
/**
|
|
3473
|
-
* The `@rebasepro/*` version this source directory actually resolves.
|
|
3474
|
-
*
|
|
3475
|
-
* Recorded on the deployment so a row in Deployment History says which
|
|
3476
|
-
* framework build shipped. Nothing else on the platform knows: an app that
|
|
3477
|
-
* links the framework locally pins it at package time, and a silent bump is
|
|
3478
|
-
* invisible afterwards — it has already cost one debugging session.
|
|
3479
|
-
*
|
|
3480
|
-
* `@rebasepro/server` first, because that is what the deployed backend runs;
|
|
3481
|
-
* `@rebasepro/client` is the fallback for a frontend-only bundle. Resolution is
|
|
3482
|
-
* a plain walk up from the source directory rather than `require.resolve`,
|
|
3483
|
-
* which would answer for the CLI's own install tree instead of the app's.
|
|
3484
|
-
*
|
|
3485
|
-
* Best effort by construction: a version that cannot be read is simply not
|
|
3486
|
-
* recorded. Nothing about a deploy should fail over a bookkeeping string.
|
|
3487
|
-
*/
|
|
3488
|
-
function resolveFrameworkVersion(sourceDir) {
|
|
3489
|
-
let dir = path.resolve(sourceDir);
|
|
3490
|
-
for (;;) {
|
|
3491
|
-
for (const pkg of ["@rebasepro/server", "@rebasepro/client"]) try {
|
|
3492
|
-
const manifest = path.join(dir, "node_modules", ...pkg.split("/"), "package.json");
|
|
3493
|
-
const version = JSON.parse(fs.readFileSync(manifest, "utf8")).version;
|
|
3494
|
-
if (typeof version === "string" && version.trim() !== "") return version.trim();
|
|
3495
|
-
} catch {}
|
|
3496
|
-
const parent = path.dirname(dir);
|
|
3497
|
-
if (parent === dir) return void 0;
|
|
3498
|
-
dir = parent;
|
|
3499
|
-
}
|
|
3500
|
-
}
|
|
3501
3424
|
/** Upload a build-context tarball; returns the opaque `source` ref for deploy. */
|
|
3502
3425
|
async function uploadSource(url, token, projectId, tarPath) {
|
|
3503
3426
|
const bytes = fs.readFileSync(tarPath);
|
|
@@ -3523,9 +3446,7 @@ async function uploadSource(url, token, projectId, tarPath) {
|
|
|
3523
3446
|
async function deployCommand(rawArgs, projectRef) {
|
|
3524
3447
|
const args = arg({
|
|
3525
3448
|
"--no-follow": Boolean,
|
|
3526
|
-
"--source": String
|
|
3527
|
-
"--message": String,
|
|
3528
|
-
"-m": "--message"
|
|
3449
|
+
"--source": String
|
|
3529
3450
|
}, {
|
|
3530
3451
|
argv: rawArgs.slice(2),
|
|
3531
3452
|
permissive: true
|
|
@@ -3545,87 +3466,32 @@ async function deployCommand(rawArgs, projectRef) {
|
|
|
3545
3466
|
}
|
|
3546
3467
|
console.log("");
|
|
3547
3468
|
console.log(` 🚀 Triggering deployment for project ${chalk.bold(projectRef)}${source ? " from uploaded source" : ""}...`);
|
|
3548
|
-
|
|
3549
|
-
if (source) body.source = source;
|
|
3550
|
-
if (args["--message"]) body.message = args["--message"];
|
|
3551
|
-
body.client = "cli";
|
|
3552
|
-
const frameworkVersion = resolveFrameworkVersion(args["--source"] ?? process.cwd());
|
|
3553
|
-
if (frameworkVersion) body.frameworkVersion = frameworkVersion;
|
|
3554
|
-
let triggered;
|
|
3469
|
+
let deploymentId;
|
|
3555
3470
|
try {
|
|
3556
|
-
const res = await client.functions.invoke("deploy",
|
|
3471
|
+
const res = await client.functions.invoke("deploy", source ? {
|
|
3472
|
+
projectId,
|
|
3473
|
+
source
|
|
3474
|
+
} : { projectId });
|
|
3557
3475
|
if (!res?.deployment?.id) fail("Control plane did not return a deployment id.");
|
|
3558
|
-
|
|
3559
|
-
deploymentId: String(res.deployment.id),
|
|
3560
|
-
deduplicated: res.deduplicated === true
|
|
3561
|
-
};
|
|
3476
|
+
deploymentId = String(res.deployment.id);
|
|
3562
3477
|
} catch (e) {
|
|
3563
|
-
|
|
3478
|
+
const err = e;
|
|
3479
|
+
if (err?.status === 409) fail("A deployment is already in progress for this project.");
|
|
3480
|
+
if (err?.status === 402) fail(err.message || "Payment required before deploying.", "Attach a card once with `rebase cloud billing setup`, then deploy again.");
|
|
3481
|
+
reportError(e, "Failed to trigger deployment");
|
|
3564
3482
|
}
|
|
3565
|
-
|
|
3566
|
-
if (!isJsonMode()) console.log(chalk.gray(deduplicated ? ` Deployment ${deploymentId} is already running — following it.` : ` Deployment ${deploymentId} created.${frameworkVersion ? ` (@rebasepro/* ${frameworkVersion})` : ""}`));
|
|
3483
|
+
console.log(chalk.gray(` Deployment ${deploymentId} created.`));
|
|
3567
3484
|
if (args["--no-follow"]) {
|
|
3568
|
-
|
|
3569
|
-
console.log(chalk.gray(" Not following logs (--no-follow). Check status with `rebase cloud logs`."));
|
|
3570
|
-
console.log("");
|
|
3571
|
-
}, {
|
|
3572
|
-
deploymentId,
|
|
3573
|
-
deduplicated,
|
|
3574
|
-
frameworkVersion: frameworkVersion ?? null,
|
|
3575
|
-
following: false
|
|
3576
|
-
});
|
|
3577
|
-
return;
|
|
3578
|
-
}
|
|
3579
|
-
if (!isJsonMode()) {
|
|
3580
|
-
console.log(chalk.gray(" Streaming build logs (Ctrl-C to stop watching — the build keeps running):"));
|
|
3485
|
+
console.log(chalk.gray(" Not following logs (--no-follow). Check status with `rebase cloud logs`."));
|
|
3581
3486
|
console.log("");
|
|
3487
|
+
return;
|
|
3582
3488
|
}
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
deduplicated,
|
|
3587
|
-
frameworkVersion: frameworkVersion ?? null,
|
|
3588
|
-
following: true,
|
|
3589
|
-
status
|
|
3590
|
-
});
|
|
3591
|
-
}
|
|
3592
|
-
/**
|
|
3593
|
-
* Turn a failed trigger into either a deployment to follow, or an exit.
|
|
3594
|
-
*
|
|
3595
|
-
* The 409 is the interesting one. A deploy trigger can reach the control plane
|
|
3596
|
-
* twice without anybody asking twice — the SDK transport replays a request once
|
|
3597
|
-
* after refreshing an expired token, and any lost response has the same effect
|
|
3598
|
-
* — so "a deployment is already in progress" was routinely describing the
|
|
3599
|
-
* deployment this very command had just created. With no id in the message the
|
|
3600
|
-
* only available reading was "someone else is deploying, back off", and the
|
|
3601
|
-
* build stream was lost either way.
|
|
3602
|
-
*
|
|
3603
|
-
* So: if the control plane says the blocking deployment is ours, we attach to
|
|
3604
|
-
* it. If it is not ours, we still name it, because "which one, since when, from
|
|
3605
|
-
* where" is the difference between an actionable refusal and a dead end.
|
|
3606
|
-
*/
|
|
3607
|
-
function resolveTriggerFailure(e) {
|
|
3608
|
-
const err = e;
|
|
3609
|
-
if (err?.status === 409) {
|
|
3610
|
-
const blocking = err.details?.deployment;
|
|
3611
|
-
if (blocking?.id && blocking.mine) return {
|
|
3612
|
-
deploymentId: String(blocking.id),
|
|
3613
|
-
deduplicated: true
|
|
3614
|
-
};
|
|
3615
|
-
fail(blocking?.id ? `Deployment ${blocking.id} is already in progress for this project${blocking.triggerSource && blocking.triggerSource !== "unknown" ? `, triggered from the ${blocking.triggerSource}` : ""}${blocking.createdAt ? ` at ${fmtDate(blocking.createdAt)}` : ""}.` : "A deployment is already in progress for this project.", blocking?.id ? `Follow it with \`rebase cloud logs -f\`, or stop it with \`rebase cloud cancel ${blocking.id}\`.` : "Follow it with `rebase cloud logs -f`.", "deploy_in_progress");
|
|
3616
|
-
}
|
|
3617
|
-
if (err?.status === 402) fail(err.message || "Payment required before deploying.", "Attach a card once with `rebase cloud billing setup`, then deploy again.", "payment_required");
|
|
3618
|
-
reportError(e, "Failed to trigger deployment");
|
|
3489
|
+
console.log(chalk.gray(" Streaming build logs (Ctrl-C to stop watching — the build keeps running):"));
|
|
3490
|
+
console.log("");
|
|
3491
|
+
await streamBuildLogs(client, deploymentId);
|
|
3619
3492
|
}
|
|
3620
|
-
/**
|
|
3621
|
-
|
|
3622
|
-
* terminal status; a non-success still exits non-zero, as it always has.
|
|
3623
|
-
*
|
|
3624
|
-
* `quiet` follows without printing — JSON mode, where the log stream would
|
|
3625
|
-
* corrupt the one object the caller is parsing.
|
|
3626
|
-
*/
|
|
3627
|
-
async function streamBuildLogs(client, deploymentId, opts = {}) {
|
|
3628
|
-
const quiet = opts.quiet === true;
|
|
3493
|
+
/** Poll a deployment record and print new log output as it arrives. */
|
|
3494
|
+
async function streamBuildLogs(client, deploymentId) {
|
|
3629
3495
|
let printed = 0;
|
|
3630
3496
|
const started = Date.now();
|
|
3631
3497
|
for (;;) {
|
|
@@ -3635,37 +3501,26 @@ async function streamBuildLogs(client, deploymentId, opts = {}) {
|
|
|
3635
3501
|
} catch (e) {
|
|
3636
3502
|
reportError(e, "Failed to read deployment status");
|
|
3637
3503
|
}
|
|
3638
|
-
if (!dep) fail(`Deployment ${deploymentId} disappeared
|
|
3504
|
+
if (!dep) fail(`Deployment ${deploymentId} disappeared.`);
|
|
3639
3505
|
const logs = dep.logs ?? "";
|
|
3640
|
-
if (
|
|
3641
|
-
|
|
3506
|
+
if (logs.length > printed) {
|
|
3507
|
+
process.stdout.write(logs.slice(printed));
|
|
3508
|
+
printed = logs.length;
|
|
3509
|
+
}
|
|
3642
3510
|
if (dep.status && dep.status !== "deploying") {
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
message: `Deployment ${deploymentId} ${dep.status}.`,
|
|
3647
|
-
code: "deploy_failed",
|
|
3648
|
-
status: null,
|
|
3649
|
-
deploymentId,
|
|
3650
|
-
logs
|
|
3651
|
-
} });
|
|
3652
|
-
process.exit(1);
|
|
3653
|
-
}
|
|
3654
|
-
console.log("");
|
|
3511
|
+
console.log("");
|
|
3512
|
+
if (dep.status === "success") console.log(chalk.bold.green(" ✓ Deployment succeeded"));
|
|
3513
|
+
else {
|
|
3655
3514
|
console.log(chalk.bold.red(` ✗ Deployment ${dep.status}`));
|
|
3656
3515
|
console.log("");
|
|
3657
3516
|
process.exit(1);
|
|
3658
3517
|
}
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
console.log(chalk.bold.green(" ✓ Deployment succeeded"));
|
|
3662
|
-
console.log("");
|
|
3663
|
-
}
|
|
3664
|
-
return dep.status;
|
|
3518
|
+
console.log("");
|
|
3519
|
+
return;
|
|
3665
3520
|
}
|
|
3666
3521
|
if (Date.now() - started > POLL_TIMEOUT_MS) {
|
|
3667
|
-
|
|
3668
|
-
fail("Timed out waiting for the build to finish.", "The deployment may still be running — check `rebase cloud logs`."
|
|
3522
|
+
console.log("");
|
|
3523
|
+
fail("Timed out waiting for the build to finish.", "The deployment may still be running — check `rebase cloud logs`.");
|
|
3669
3524
|
}
|
|
3670
3525
|
await sleep(POLL_INTERVAL_MS);
|
|
3671
3526
|
}
|
|
@@ -4378,35 +4233,9 @@ function parseEnvAssignment(operands) {
|
|
|
4378
4233
|
value: operands[1] ?? ""
|
|
4379
4234
|
};
|
|
4380
4235
|
}
|
|
4381
|
-
/**
|
|
4382
|
-
* Prefixes whose variables are read by a BUNDLER at build time, not by the
|
|
4383
|
-
* process at run time.
|
|
4384
|
-
*
|
|
4385
|
-
* These are the ones this command cannot deliver. A project's environment is
|
|
4386
|
-
* applied at rollout — after Kaniko has already built the image — so a
|
|
4387
|
-
* `VITE_API_URL` set here is present in the running container and absent from
|
|
4388
|
-
* the JavaScript that was compiled minutes earlier. Nothing fails: the variable
|
|
4389
|
-
* exists, the deploy succeeds, and the bundle carries `undefined` where the
|
|
4390
|
-
* value should be. The bug then presents in the browser as missing
|
|
4391
|
-
* configuration, which is several steps away from the cause.
|
|
4392
|
-
*
|
|
4393
|
-
* `import.meta.env` inlining is Vite's; `NEXT_PUBLIC_`/`PUBLIC_`/`REACT_APP_`
|
|
4394
|
-
* are the same contract in Next, Astro/SvelteKit and CRA.
|
|
4395
|
-
*/
|
|
4396
|
-
var BUILD_TIME_ENV_PREFIXES = [
|
|
4397
|
-
"VITE_",
|
|
4398
|
-
"NEXT_PUBLIC_",
|
|
4399
|
-
"PUBLIC_",
|
|
4400
|
-
"REACT_APP_"
|
|
4401
|
-
];
|
|
4402
|
-
/** The prefix that makes `key` a build-time variable, or undefined. */
|
|
4403
|
-
function buildTimeEnvPrefix(key) {
|
|
4404
|
-
return BUILD_TIME_ENV_PREFIXES.find((prefix) => key.toUpperCase().startsWith(prefix));
|
|
4405
|
-
}
|
|
4406
4236
|
async function setEnv(rawArgs) {
|
|
4407
4237
|
const args = arg({
|
|
4408
4238
|
"--secret": Boolean,
|
|
4409
|
-
"--force": Boolean,
|
|
4410
4239
|
"--project": String,
|
|
4411
4240
|
"-p": "--project"
|
|
4412
4241
|
}, {
|
|
@@ -4418,8 +4247,6 @@ async function setEnv(rawArgs) {
|
|
|
4418
4247
|
displayProjectRef(rawArgs);
|
|
4419
4248
|
const parsed = parseEnvAssignment(cloudPositionals(rawArgs).slice(2));
|
|
4420
4249
|
if (!parsed || !parsed.key) fail("Usage: rebase cloud env set KEY=VALUE [--secret]", void 0, "usage");
|
|
4421
|
-
const buildTimePrefix = buildTimeEnvPrefix(parsed.key);
|
|
4422
|
-
if (buildTimePrefix && !args["--force"]) fail(`${parsed.key} is read by your bundler at BUILD time, and project variables are applied at rollout — after the image is built. Setting it here would not reach the bundle.`, `Put ${buildTimePrefix}* variables in the source you deploy (a committed .env, or your build config), then \`rebase cloud deploy\`. Pass --force if your build genuinely reads this at run time.`, "build_time_variable");
|
|
4423
4250
|
const body = {
|
|
4424
4251
|
key: parsed.key,
|
|
4425
4252
|
value: parsed.value
|
|
@@ -4576,13 +4403,10 @@ ${chalk.green.bold("Commands")}
|
|
|
4576
4403
|
|
|
4577
4404
|
${chalk.green.bold("Options")}
|
|
4578
4405
|
${chalk.blue("--secret")} Mark a variable write-only ${chalk.gray("(set)")}
|
|
4579
|
-
${chalk.blue("--force")} Set a build-time key anyway ${chalk.gray("(set)")}
|
|
4580
4406
|
${chalk.blue("--json")} Machine-readable output
|
|
4581
4407
|
${chalk.blue("--project, -p")} Project slug ${chalk.gray("(defaults to the linked project)")}
|
|
4582
4408
|
|
|
4583
4409
|
${chalk.gray("Values are encrypted at rest (AES-256-GCM) and only decrypted at deploy time.")}
|
|
4584
|
-
${chalk.gray("VITE_* / NEXT_PUBLIC_* / PUBLIC_* / REACT_APP_* are read by your bundler at BUILD time;")}
|
|
4585
|
-
${chalk.gray("these are applied at rollout, after the image is built, so they never reach the bundle.")}
|
|
4586
4410
|
`);
|
|
4587
4411
|
}
|
|
4588
4412
|
function printEnvHelpJson() {
|
|
@@ -5178,8 +5002,6 @@ function deploymentView(dep) {
|
|
|
5178
5002
|
isRollback: str(dep, "rollbackOf", "rollback_of") !== null,
|
|
5179
5003
|
rollbackable: isRollbackable(dep),
|
|
5180
5004
|
trigger: triggerInfo(dep),
|
|
5181
|
-
message: str(dep, "deployMessage", "deploy_message"),
|
|
5182
|
-
frameworkVersion: str(dep, "frameworkVersion", "framework_version"),
|
|
5183
5005
|
commit: {
|
|
5184
5006
|
hash: str(dep, "gitCommitHash", "gitCommitHash"),
|
|
5185
5007
|
message: str(dep, "gitCommitMessage", "gitCommitMessage")
|
|
@@ -5193,31 +5015,12 @@ async function fetchDeployments(client, projectId, limit = 100) {
|
|
|
5193
5015
|
limit
|
|
5194
5016
|
})).data;
|
|
5195
5017
|
}
|
|
5196
|
-
/** Hard ceiling on `--limit`, matching the backend's own page size. */
|
|
5197
|
-
var MAX_DEPLOYMENTS_LIMIT = 100;
|
|
5198
|
-
/** `--limit N`, bounded. A garbage value is a refusal, never a silent default. */
|
|
5199
|
-
function parseDeploymentsLimit(raw) {
|
|
5200
|
-
if (raw === void 0) return 20;
|
|
5201
|
-
if (!Number.isInteger(raw) || raw < 1 || raw > MAX_DEPLOYMENTS_LIMIT) fail(`--limit must be a whole number between 1 and ${MAX_DEPLOYMENTS_LIMIT}.`, void 0, "usage");
|
|
5202
|
-
return raw;
|
|
5203
|
-
}
|
|
5204
5018
|
async function deploymentsListCommand(rawArgs) {
|
|
5205
|
-
const args = arg({
|
|
5206
|
-
"--limit": Number,
|
|
5207
|
-
"--all": Boolean,
|
|
5208
|
-
"--project": String,
|
|
5209
|
-
"-p": "--project"
|
|
5210
|
-
}, {
|
|
5211
|
-
argv: rawArgs.slice(2),
|
|
5212
|
-
permissive: true
|
|
5213
|
-
});
|
|
5214
|
-
const limit = args["--all"] ? MAX_DEPLOYMENTS_LIMIT : parseDeploymentsLimit(args["--limit"]);
|
|
5215
5019
|
const { client } = await requireClient(rawArgs);
|
|
5216
5020
|
const projectId = await requireProject(rawArgs, client);
|
|
5217
5021
|
const projectRef = displayProjectRef(rawArgs);
|
|
5218
5022
|
try {
|
|
5219
|
-
const views = (await fetchDeployments(client, projectId
|
|
5220
|
-
const truncated = views.length === limit;
|
|
5023
|
+
const views = (await fetchDeployments(client, projectId)).map(deploymentView);
|
|
5221
5024
|
emit(() => {
|
|
5222
5025
|
console.log("");
|
|
5223
5026
|
console.log(chalk.bold(` 🚀 Deployments — project ${projectRef}`));
|
|
@@ -5232,18 +5035,10 @@ async function deploymentsListCommand(rawArgs) {
|
|
|
5232
5035
|
const trig = v.trigger.source;
|
|
5233
5036
|
const roll = v.rollbackable ? chalk.green(" ↺ rollbackable") : "";
|
|
5234
5037
|
console.log(` ${chalk.gray(`[${v.id}]`)} ${colorStatus(v.status)} ${chalk.gray(String(v.createdAt ?? "—"))} ${dur} ${chalk.gray(trig)}${roll}`);
|
|
5235
|
-
const label = [v.message, v.frameworkVersion ? `@rebasepro/* ${v.frameworkVersion}` : null].filter(Boolean).join(" · ");
|
|
5236
|
-
if (label) console.log(` ${chalk.gray(label)}`);
|
|
5237
|
-
}
|
|
5238
|
-
if (truncated) {
|
|
5239
|
-
console.log("");
|
|
5240
|
-
console.log(chalk.gray(` Showing the ${limit} most recent. Use \`--limit N\` or \`--all\` for more.`));
|
|
5241
5038
|
}
|
|
5242
5039
|
console.log("");
|
|
5243
5040
|
}, {
|
|
5244
5041
|
projectId,
|
|
5245
|
-
limit,
|
|
5246
|
-
truncated,
|
|
5247
5042
|
deployments: views
|
|
5248
5043
|
});
|
|
5249
5044
|
} catch (e) {
|
|
@@ -6143,95 +5938,29 @@ ${chalk.gray("so it works in a deploy script. To restart a workload, use `rebase
|
|
|
6143
5938
|
* `rebase cloud` resource subcommands: status, metrics, webhooks, storage,
|
|
6144
5939
|
* clusters, billing.
|
|
6145
5940
|
*/
|
|
6146
|
-
/**
|
|
6147
|
-
* One line describing this project's storage — or `undefined` when the control
|
|
6148
|
-
* plane could not be asked, which prints as a blank rather than a guess.
|
|
6149
|
-
*
|
|
6150
|
-
* `status` used to render the `storages` row and nothing else, so a project
|
|
6151
|
-
* whose bucket is configured through its own `STORAGE_TYPE`/`S3_*` variables —
|
|
6152
|
-
* the supported path, and the one `mergeStorageEnv` deliberately lets WIN over
|
|
6153
|
-
* the row — was reported as `Storage: none` while its pod logged `Initialized
|
|
6154
|
-
* storage backends count: 1` against a live bucket. Storage is the thing an app
|
|
6155
|
-
* refuses to boot without, so that false negative sends someone off to
|
|
6156
|
-
* provision a bucket they already have. The row is not the answer; the tenant's
|
|
6157
|
-
* resolved environment is, and the control plane computes it with the same two
|
|
6158
|
-
* functions the build log uses.
|
|
6159
|
-
*/
|
|
6160
|
-
function describeStorageState(state) {
|
|
6161
|
-
const verdict = state?.effective;
|
|
6162
|
-
if (!verdict?.kind) return void 0;
|
|
6163
|
-
const via = state?.overridden ? chalk.gray(" · from env vars") : "";
|
|
6164
|
-
switch (verdict.kind) {
|
|
6165
|
-
case "durable": return `${chalk.green("durable")}${verdict.summary ? ` · ${verdict.summary}` : ""}${via}`;
|
|
6166
|
-
case "ephemeral": return `${chalk.yellow("ephemeral")} ${chalk.gray("· uploads are lost on restart")}`;
|
|
6167
|
-
case "incomplete": return `${chalk.red("incomplete")} ${chalk.gray(`· missing ${(verdict.missing ?? []).join(", ")}`)}`;
|
|
6168
|
-
case "unrecognized": return `${chalk.red("unrecognized")} ${chalk.gray(`· STORAGE_TYPE=${verdict.storageType ?? "?"}`)}`;
|
|
6169
|
-
default: return;
|
|
6170
|
-
}
|
|
6171
|
-
}
|
|
6172
|
-
/**
|
|
6173
|
-
* One line describing the database.
|
|
6174
|
-
*
|
|
6175
|
-
* `connectionStatus` is written `"untested"` at creation and only ever changed
|
|
6176
|
-
* by `rebase cloud db test`, so `managed (untested)` was reporting the absence
|
|
6177
|
-
* of a manual test as though it were the database's condition — on a project
|
|
6178
|
-
* that had just deployed against it. A never-tested database says only its
|
|
6179
|
-
* type; the verdict appears once there is one.
|
|
6180
|
-
*/
|
|
6181
|
-
function describeDatabaseState(db) {
|
|
6182
|
-
if (!db) return void 0;
|
|
6183
|
-
const type = typeof db.type === "string" ? db.type : "database";
|
|
6184
|
-
const connection = db.connectionStatus;
|
|
6185
|
-
if (connection === "connected" || connection === "failed") return `${type} (${colorStatus(connection)})`;
|
|
6186
|
-
return `${type} ${chalk.gray("· not tested (`rebase cloud db test`)")}`;
|
|
6187
|
-
}
|
|
6188
5941
|
async function statusCommand(rawArgs) {
|
|
6189
5942
|
const { client, url } = await requireClient(rawArgs);
|
|
6190
5943
|
const projectId = await requireProject(rawArgs, client);
|
|
6191
5944
|
try {
|
|
6192
5945
|
const project = await client.data.collection("projects").findById(projectId);
|
|
6193
|
-
if (!project) fail(`Project ${displayProjectRef(rawArgs)} not found
|
|
5946
|
+
if (!project) fail(`Project ${displayProjectRef(rawArgs)} not found.`);
|
|
6194
5947
|
const [db, storage, deploy, baseDomain] = await Promise.all([
|
|
6195
5948
|
firstRow(client, "databases", projectId),
|
|
6196
|
-
client
|
|
6197
|
-
method: "GET",
|
|
6198
|
-
path: projectId
|
|
6199
|
-
}).catch(() => void 0),
|
|
5949
|
+
firstRow(client, "storages", projectId),
|
|
6200
5950
|
latestDeployment(client, projectId),
|
|
6201
5951
|
fetchTenantBaseDomain(client, url)
|
|
6202
5952
|
]);
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
["Storage", storageLine]
|
|
6215
|
-
]);
|
|
6216
|
-
console.log("");
|
|
6217
|
-
}, {
|
|
6218
|
-
projectId: String(project.id),
|
|
6219
|
-
name: project.name ?? null,
|
|
6220
|
-
subdomain: project.subdomain ?? null,
|
|
6221
|
-
status: project.status ?? null,
|
|
6222
|
-
url: projectHost(project, baseDomain) ?? null,
|
|
6223
|
-
branch: project.gitBranch ?? null,
|
|
6224
|
-
lastDeploy: deploy ? {
|
|
6225
|
-
id: String(deploy.id),
|
|
6226
|
-
status: deploy.status ?? null,
|
|
6227
|
-
createdAt: deploy.createdAt ?? null
|
|
6228
|
-
} : null,
|
|
6229
|
-
database: db ? {
|
|
6230
|
-
type: db.type ?? null,
|
|
6231
|
-
connectionStatus: db.connectionStatus ?? null
|
|
6232
|
-
} : null,
|
|
6233
|
-
storage: storage ?? null
|
|
6234
|
-
});
|
|
5953
|
+
console.log("");
|
|
5954
|
+
console.log(` ${chalk.bold(project.name ?? project.subdomain ?? "")} ${chalk.gray(`[${project.subdomain ?? displayProjectRef(rawArgs)}]`)} ${colorStatus(project.status)}`);
|
|
5955
|
+
console.log("");
|
|
5956
|
+
keyValues([
|
|
5957
|
+
["URL", projectHost(project, baseDomain)],
|
|
5958
|
+
["Branch", project.gitBranch],
|
|
5959
|
+
["Last deploy", deploy ? `${colorStatus(deploy.status)} · ${fmtDate(deploy.createdAt)}` : "never"],
|
|
5960
|
+
["Database", db ? `${db.type} (${colorStatus(db.connectionStatus)})` : "none"],
|
|
5961
|
+
["Storage", storage ? `${storage.type} (${colorStatus(storage.status)})` : "none"]
|
|
5962
|
+
]);
|
|
5963
|
+
console.log("");
|
|
6235
5964
|
} catch (e) {
|
|
6236
5965
|
reportError(e, "Failed to load status");
|
|
6237
5966
|
}
|
|
@@ -6742,9 +6471,9 @@ ${chalk.green.bold("Projects")}
|
|
|
6742
6471
|
${chalk.blue.bold("projects delete")} ${chalk.gray("[id]")} Delete a project
|
|
6743
6472
|
|
|
6744
6473
|
${chalk.green.bold("Deploy & observe")}
|
|
6745
|
-
${chalk.blue.bold("deploy")} ${chalk.gray("[--source .]
|
|
6474
|
+
${chalk.blue.bold("deploy")} ${chalk.gray("[--source .]")} Deploy the linked project + stream build logs
|
|
6746
6475
|
${chalk.blue.bold("logs")} ${chalk.gray("[--runtime] [-f]")} Show build (or runtime) logs
|
|
6747
|
-
${chalk.blue.bold("deployments list")}
|
|
6476
|
+
${chalk.blue.bold("deployments list")} Deployment history ${chalk.gray("(status, duration, trigger)")}
|
|
6748
6477
|
${chalk.blue.bold("rollback")} ${chalk.gray("[id] [-y]")} Roll back to a successful deploy
|
|
6749
6478
|
${chalk.blue.bold("cancel")} ${chalk.gray("[-y]")} Cancel the in-flight build
|
|
6750
6479
|
${chalk.blue.bold("start|stop|restart")} ${chalk.gray("[-y]")} Power ops ${chalk.gray("(stop/restart need -y)")}
|
|
@@ -6943,6 +6672,6 @@ ${chalk.gray("Documentation: https://rebase.pro/docs")}
|
|
|
6943
6672
|
`);
|
|
6944
6673
|
}
|
|
6945
6674
|
//#endregion
|
|
6946
|
-
export { authCommand, buildCommand, buildInitQuestions, cloudCommand, configureEnvFile, createRebaseApp, dbCommand, detectPackageManager, devCommand, doctorCommand, entry, findBackendDir, findEnvFile, findFrontendDir, findProjectRoot, formatCdTarget, generateSdkCommand, getActiveBackendPlugin, getPMCommands, isPnpmAvailable,
|
|
6675
|
+
export { authCommand, buildCommand, buildInitQuestions, cloudCommand, configureEnvFile, createRebaseApp, dbCommand, detectPackageManager, devCommand, doctorCommand, entry, findBackendDir, findEnvFile, findFrontendDir, findProjectRoot, formatCdTarget, generateSdkCommand, getActiveBackendPlugin, getPMCommands, isPnpmAvailable, printInitHelp, requireBackendDir, requireProjectRoot, resolveLocalBin, resolvePluginCliScript, resolveTsx, schemaCommand, startCommand, validateProjectName, validateTsxInstallation };
|
|
6947
6676
|
|
|
6948
6677
|
//# sourceMappingURL=index.es.js.map
|