@rebasepro/cli 0.12.1-canary.g389e9b2 → 0.12.1-canary.g4e7bcbf
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 +53 -0
- package/dist/commands/cloud/deploy.d.ts +64 -0
- package/dist/commands/cloud/index.d.ts +23 -0
- package/dist/commands/dev.d.ts +16 -0
- package/dist/index.es.js +204 -29
- package/dist/index.es.js.map +1 -1
- package/package.json +7 -7
|
@@ -84,6 +84,39 @@ export interface ProjectLink {
|
|
|
84
84
|
export declare function readLink(cwd?: string): ProjectLink | null;
|
|
85
85
|
export declare function writeLink(link: ProjectLink, cwd?: string): void;
|
|
86
86
|
export declare function removeLink(cwd?: string): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Flags that may appear anywhere on a `rebase cloud` line, including *before*
|
|
89
|
+
* the resource group.
|
|
90
|
+
*
|
|
91
|
+
* They have to be declared wherever positionals are resolved, because `arg`'s
|
|
92
|
+
* `permissive: true` does not merely tolerate an undeclared flag — it pushes it
|
|
93
|
+
* into `_` alongside the positionals, and for a flag that takes a value it
|
|
94
|
+
* pushes the value in too. So `cloud --project acme storage create` parsed
|
|
95
|
+
* without this spec yields `_` of `["--project", "acme", "storage", "create"]`,
|
|
96
|
+
* and the group reads as `"acme"`: a real project name, in the group position,
|
|
97
|
+
* dispatching to nothing. Skipping tokens that start with `-` does not save you
|
|
98
|
+
* there — the damage is the orphaned value, which looks exactly like a
|
|
99
|
+
* positional.
|
|
100
|
+
*
|
|
101
|
+
* Only genuinely global flags belong here. Group-specific ones (`--bucket`,
|
|
102
|
+
* `--region`, …) are declared by the handler that owns them and always follow
|
|
103
|
+
* the group, so they cannot shift the group or action.
|
|
104
|
+
*
|
|
105
|
+
* `-p` is `--project` in eighteen places and `--password` in `login`. That
|
|
106
|
+
* ambiguity does not matter to the one caller that reads this spec: it resolves
|
|
107
|
+
* positionals and never looks at a flag's value, so all it needs to know is
|
|
108
|
+
* that `-p` takes one. Anything that wants the value must keep declaring it
|
|
109
|
+
* itself, with the meaning its own command gives it.
|
|
110
|
+
*/
|
|
111
|
+
export declare const GLOBAL_CLOUD_FLAGS: {
|
|
112
|
+
readonly "--json": BooleanConstructor;
|
|
113
|
+
readonly "--yes": BooleanConstructor;
|
|
114
|
+
readonly "--help": BooleanConstructor;
|
|
115
|
+
readonly "--project": StringConstructor;
|
|
116
|
+
readonly "-p": "--project";
|
|
117
|
+
readonly "-y": "--yes";
|
|
118
|
+
readonly "-h": "--help";
|
|
119
|
+
};
|
|
87
120
|
/**
|
|
88
121
|
* The raw project reference to operate on: explicit `--project` flag wins,
|
|
89
122
|
* otherwise the linked project. Exits with guidance when neither is present.
|
|
@@ -134,6 +167,26 @@ export declare function printJson(value: unknown): void;
|
|
|
134
167
|
* call is what guarantees a command can never print a table AND a JSON blob.
|
|
135
168
|
*/
|
|
136
169
|
export declare function emit(human: () => void, json: unknown): void;
|
|
170
|
+
/**
|
|
171
|
+
* Print a warning (+ optional hint) — in every output mode, always to stderr.
|
|
172
|
+
*
|
|
173
|
+
* `emit` is for a command's *result*, and JSON mode legitimately replaces the
|
|
174
|
+
* human rendering of one. A warning is not a result: it says the command is
|
|
175
|
+
* about to do something the caller may not have meant, and that is exactly as
|
|
176
|
+
* true when the output is piped. Gating one on `!isJsonMode()` deleted it
|
|
177
|
+
* precisely where nobody was watching the terminal — a `--source` deploy ejected
|
|
178
|
+
* a live project off the managed runtime and said so only to a TTY that wasn't
|
|
179
|
+
* there.
|
|
180
|
+
*
|
|
181
|
+
* stdout carries the JSON value and nothing else, so warnings go to stderr:
|
|
182
|
+
* a machine parser reading stdout cannot be corrupted by one. Only the
|
|
183
|
+
* *formatting* may depend on the mode — colour and indentation for a terminal,
|
|
184
|
+
* plain ASCII otherwise. Whether a warning is emitted at all may not.
|
|
185
|
+
*
|
|
186
|
+
* Anything a caller might branch on belongs in the JSON payload as well; stderr
|
|
187
|
+
* is for whoever reads the transcript afterwards.
|
|
188
|
+
*/
|
|
189
|
+
export declare function warn(message: string, hint?: string): void;
|
|
137
190
|
/** Print an error (+ optional hint) and exit non-zero. Never returns. */
|
|
138
191
|
export declare function fail(message: string, hint?: string, code?: string): never;
|
|
139
192
|
/**
|
|
@@ -46,5 +46,69 @@ export declare function timeAgo(value: string | Date | undefined, now: Date): st
|
|
|
46
46
|
export declare function isManagedProject(project: DeployProjectRow | undefined, latest: DeploySourceRow | undefined): boolean;
|
|
47
47
|
/** What a `deploy` with nothing attached will build, in the words to print. */
|
|
48
48
|
export declare function planBareDeploy(project: DeployProjectRow | undefined, latest: DeploySourceRow | undefined, now: Date): BareDeployPlan;
|
|
49
|
+
/**
|
|
50
|
+
* A warning attached to a deploy: printed for the human, carried in the JSON.
|
|
51
|
+
*
|
|
52
|
+
* `code` is the stable half — the message is prose and will be reworded, so it
|
|
53
|
+
* is the code that CI or an agent branches on.
|
|
54
|
+
*/
|
|
55
|
+
export interface DeployWarning {
|
|
56
|
+
code: string;
|
|
57
|
+
message: string;
|
|
58
|
+
hint?: string;
|
|
59
|
+
}
|
|
60
|
+
/** `code` of the warning below, and the field name it sets in the payload. */
|
|
61
|
+
export declare const EJECTS_MANAGED_RUNTIME = "ejects_managed_runtime";
|
|
62
|
+
/** The one sentence that says a source build undoes `runtimeMode: managed`. */
|
|
63
|
+
export declare function ejectWarning(projectRef: string): DeployWarning;
|
|
64
|
+
/** How a container-image deploy was asked for — the input to both rules below. */
|
|
65
|
+
export interface EjectContext {
|
|
66
|
+
/** The project currently runs on the managed runtime. */
|
|
67
|
+
managed: boolean;
|
|
68
|
+
/** `--source` was passed: build this directory. */
|
|
69
|
+
source: boolean;
|
|
70
|
+
/** `--force` was passed: eject on purpose. */
|
|
71
|
+
force: boolean;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Why a container-image deploy of a managed project is refused — or `undefined`
|
|
75
|
+
* to let it through.
|
|
76
|
+
*
|
|
77
|
+
* Every path below this point builds a container image, and a successful one
|
|
78
|
+
* sets `runtimeMode: "custom"` server-side. So the question is never "which flag
|
|
79
|
+
* was used" but "did the caller ask to leave the managed runtime", and only
|
|
80
|
+
* `--force` answers it.
|
|
81
|
+
*
|
|
82
|
+
* `--source` used to be read as answering it too, on the theory that uploading a
|
|
83
|
+
* build context is self-evidently a deliberate eject. It is not: `--source`
|
|
84
|
+
* picks *which source* gets built — this directory, rather than the stale
|
|
85
|
+
* archive the control plane is holding — and the eject is a side effect of the
|
|
86
|
+
* answer. That is exactly how a live project got flipped to `custom` by someone
|
|
87
|
+
* whose actual intent was "deploy what I have here", and it is the same
|
|
88
|
+
* ignorance the bare form is refused for. Same ignorance, same refusal.
|
|
89
|
+
*/
|
|
90
|
+
export declare function ejectRefusal(opts: EjectContext, projectRef: string): {
|
|
91
|
+
message: string;
|
|
92
|
+
hint: string;
|
|
93
|
+
code: string;
|
|
94
|
+
} | undefined;
|
|
95
|
+
/**
|
|
96
|
+
* Which warnings a container-image deploy has earned.
|
|
97
|
+
*
|
|
98
|
+
* Pure, and separate from the printing, because the printing is what went
|
|
99
|
+
* wrong: the eject warning used to be written inline behind `!isJsonMode()`, so
|
|
100
|
+
* the fact that a deploy ejects a managed project existed only as a side effect
|
|
101
|
+
* of a TTY being attached. Deciding here, emitting once at the call site, means
|
|
102
|
+
* the decision cannot be output-mode-dependent again.
|
|
103
|
+
*
|
|
104
|
+
* The condition is just `managed`: anything reaching this point is a container
|
|
105
|
+
* image build that `ejectRefusal` has already let through, and on a managed
|
|
106
|
+
* project that is an eject however it was spelled. A caller who passed `--force`
|
|
107
|
+
* knows — the warning is for the transcript and the payload, which is what
|
|
108
|
+
* anyone reviewing the deploy afterwards actually reads.
|
|
109
|
+
*/
|
|
110
|
+
export declare function deployWarnings(opts: EjectContext, projectRef: string): DeployWarning[];
|
|
111
|
+
/** The warning half of a deploy's JSON payload — merged into whatever it emits. */
|
|
112
|
+
export declare function warningPayload(warnings: DeployWarning[]): Record<string, unknown>;
|
|
49
113
|
export declare function deployCommand(rawArgs: string[], projectRef: string): Promise<void>;
|
|
50
114
|
export declare function logsCommand(rawArgs: string[], projectRef: string): Promise<void>;
|
|
@@ -1 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Positional tokens after `rebase cloud` (group, action, …).
|
|
3
|
+
*
|
|
4
|
+
* Two things stop a flag being mistaken for the group. `GLOBAL_CLOUD_FLAGS` is
|
|
5
|
+
* declared so `arg` *consumes* the flags that may precede it — critically
|
|
6
|
+
* together with their values, which is the half that filtering cannot do. The
|
|
7
|
+
* leading-`-` skip then covers a flag nobody declared, so an unrecognised
|
|
8
|
+
* boolean shifts nothing.
|
|
9
|
+
*
|
|
10
|
+
* Only leading tokens are skipped: past the group and action, an undeclared
|
|
11
|
+
* flag and its value are somebody else's positionals and none of our business.
|
|
12
|
+
* A flag this file has never heard of, that takes a value, placed before the
|
|
13
|
+
* group, is the one shape still unresolvable here — there is no way to know
|
|
14
|
+
* whether the token after it is its value or the group, and guessing either way
|
|
15
|
+
* is worse than the handler reporting an unknown group.
|
|
16
|
+
*
|
|
17
|
+
* Exported so its tests can drive the real thing. The dispatch test used to
|
|
18
|
+
* re-implement it locally as `slice(3).filter(a => !a.startsWith("-"))` — which
|
|
19
|
+
* filtered flags, while this function did not — so the test asserted the
|
|
20
|
+
* behaviour we wanted against a copy that had it, and stayed green for as long
|
|
21
|
+
* as the real dispatcher was broken.
|
|
22
|
+
*/
|
|
23
|
+
export declare function positionals(rawArgs: string[]): string[];
|
|
1
24
|
export declare function cloudCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void>;
|
package/dist/commands/dev.d.ts
CHANGED
|
@@ -1 +1,17 @@
|
|
|
1
|
+
/** Well-known filename the backend writes its actual port to. */
|
|
2
|
+
export declare const DEV_PORT_FILENAME = ".rebase-dev-port";
|
|
3
|
+
/**
|
|
4
|
+
* Compute a deterministic port from the project root path.
|
|
5
|
+
* Range: 3001–3999 (avoids privileged ports and common services).
|
|
6
|
+
* Two different project directories will almost always get different ports.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getProjectPort(projectRoot: string): number;
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the best starting port for this project:
|
|
11
|
+
* 1. Explicit --port flag (highest priority)
|
|
12
|
+
* 2. PORT env var
|
|
13
|
+
* 3. Previously used port from .rebase-dev-port (port affinity across restarts)
|
|
14
|
+
* 4. Deterministic hash from project path (unique per project)
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveStartPort(projectRoot: string, explicitPort?: number): number;
|
|
1
17
|
export declare function devCommand(rawArgs: string[]): Promise<void>;
|
package/dist/index.es.js
CHANGED
|
@@ -603,6 +603,39 @@ function removeLink(cwd = process.cwd()) {
|
|
|
603
603
|
}
|
|
604
604
|
return false;
|
|
605
605
|
}
|
|
606
|
+
/**
|
|
607
|
+
* Flags that may appear anywhere on a `rebase cloud` line, including *before*
|
|
608
|
+
* the resource group.
|
|
609
|
+
*
|
|
610
|
+
* They have to be declared wherever positionals are resolved, because `arg`'s
|
|
611
|
+
* `permissive: true` does not merely tolerate an undeclared flag — it pushes it
|
|
612
|
+
* into `_` alongside the positionals, and for a flag that takes a value it
|
|
613
|
+
* pushes the value in too. So `cloud --project acme storage create` parsed
|
|
614
|
+
* without this spec yields `_` of `["--project", "acme", "storage", "create"]`,
|
|
615
|
+
* and the group reads as `"acme"`: a real project name, in the group position,
|
|
616
|
+
* dispatching to nothing. Skipping tokens that start with `-` does not save you
|
|
617
|
+
* there — the damage is the orphaned value, which looks exactly like a
|
|
618
|
+
* positional.
|
|
619
|
+
*
|
|
620
|
+
* Only genuinely global flags belong here. Group-specific ones (`--bucket`,
|
|
621
|
+
* `--region`, …) are declared by the handler that owns them and always follow
|
|
622
|
+
* the group, so they cannot shift the group or action.
|
|
623
|
+
*
|
|
624
|
+
* `-p` is `--project` in eighteen places and `--password` in `login`. That
|
|
625
|
+
* ambiguity does not matter to the one caller that reads this spec: it resolves
|
|
626
|
+
* positionals and never looks at a flag's value, so all it needs to know is
|
|
627
|
+
* that `-p` takes one. Anything that wants the value must keep declaring it
|
|
628
|
+
* itself, with the meaning its own command gives it.
|
|
629
|
+
*/
|
|
630
|
+
var GLOBAL_CLOUD_FLAGS = {
|
|
631
|
+
"--json": Boolean,
|
|
632
|
+
"--yes": Boolean,
|
|
633
|
+
"--help": Boolean,
|
|
634
|
+
"--project": String,
|
|
635
|
+
"-p": "--project",
|
|
636
|
+
"-y": "--yes",
|
|
637
|
+
"-h": "--help"
|
|
638
|
+
};
|
|
606
639
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
607
640
|
/**
|
|
608
641
|
* The raw project reference to operate on: explicit `--project` flag wins,
|
|
@@ -708,6 +741,35 @@ function emit(human, json) {
|
|
|
708
741
|
if (JSON_MODE) printJson(json);
|
|
709
742
|
else human();
|
|
710
743
|
}
|
|
744
|
+
/**
|
|
745
|
+
* Print a warning (+ optional hint) — in every output mode, always to stderr.
|
|
746
|
+
*
|
|
747
|
+
* `emit` is for a command's *result*, and JSON mode legitimately replaces the
|
|
748
|
+
* human rendering of one. A warning is not a result: it says the command is
|
|
749
|
+
* about to do something the caller may not have meant, and that is exactly as
|
|
750
|
+
* true when the output is piped. Gating one on `!isJsonMode()` deleted it
|
|
751
|
+
* precisely where nobody was watching the terminal — a `--source` deploy ejected
|
|
752
|
+
* a live project off the managed runtime and said so only to a TTY that wasn't
|
|
753
|
+
* there.
|
|
754
|
+
*
|
|
755
|
+
* stdout carries the JSON value and nothing else, so warnings go to stderr:
|
|
756
|
+
* a machine parser reading stdout cannot be corrupted by one. Only the
|
|
757
|
+
* *formatting* may depend on the mode — colour and indentation for a terminal,
|
|
758
|
+
* plain ASCII otherwise. Whether a warning is emitted at all may not.
|
|
759
|
+
*
|
|
760
|
+
* Anything a caller might branch on belongs in the JSON payload as well; stderr
|
|
761
|
+
* is for whoever reads the transcript afterwards.
|
|
762
|
+
*/
|
|
763
|
+
function warn(message, hint) {
|
|
764
|
+
if (JSON_MODE) {
|
|
765
|
+
process.stderr.write(`warning: ${stripAnsi(message)}\n`);
|
|
766
|
+
if (hint) process.stderr.write(` ${stripAnsi(hint)}\n`);
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
console.error("");
|
|
770
|
+
console.error(chalk.yellow(` ⚠ ${message}`));
|
|
771
|
+
if (hint) console.error(chalk.gray(` ${hint}`));
|
|
772
|
+
}
|
|
711
773
|
/** Print an error (+ optional hint) and exit non-zero. Never returns. */
|
|
712
774
|
function fail(message, hint, code) {
|
|
713
775
|
if (JSON_MODE) {
|
|
@@ -1569,6 +1631,8 @@ async function configureEnvFile(targetDirectory, databaseUrl) {
|
|
|
1569
1631
|
});
|
|
1570
1632
|
envContent = envContent.replace(/^JWT_SECRET=.*$/m, `JWT_SECRET=${jwtSecret}`);
|
|
1571
1633
|
envContent = envContent.replace(/^#\s*REBASE_SERVICE_KEY=.*$/m, `REBASE_SERVICE_KEY=${serviceKey}`);
|
|
1634
|
+
const composeApiPort = /^PORT=(\d+)/m.exec(envContent)?.[1] ?? "3001";
|
|
1635
|
+
envContent = envContent.replace(/^#\s*CORS_ORIGINS=.*$/m, `CORS_ORIGINS=http://localhost:${composeApiPort}`);
|
|
1572
1636
|
const runtimeVersion = readCliVersion();
|
|
1573
1637
|
envContent = /^#?\s*REBASE_VERSION=.*$/m.test(envContent) ? envContent.replace(/^#?\s*REBASE_VERSION=.*$/m, `REBASE_VERSION=${runtimeVersion}`) : `${envContent.trimEnd()}\n\n# The Rebase runtime image tag docker-compose.yml pulls.\n# Change this and restart to upgrade; your project bundle is untouched.\nREBASE_VERSION=${runtimeVersion}\n`;
|
|
1574
1638
|
if (databaseUrl) {
|
|
@@ -6238,12 +6302,24 @@ function resolveFrameworkVersion(sourceDir) {
|
|
|
6238
6302
|
dir = parent;
|
|
6239
6303
|
}
|
|
6240
6304
|
}
|
|
6305
|
+
/**
|
|
6306
|
+
* A progress line for a human — dropped entirely in JSON mode.
|
|
6307
|
+
*
|
|
6308
|
+
* Progress is not a result. In JSON mode stdout carries the one result value
|
|
6309
|
+
* and nothing else, so every unguarded `console.log` on a deploy path was a
|
|
6310
|
+
* line printed in front of the JSON, breaking the parser meant to read it.
|
|
6311
|
+
* Warnings are the other half of this rule and go the other way: they are
|
|
6312
|
+
* `warn`, which prints in every mode, to stderr. See `warn` in `context.ts`.
|
|
6313
|
+
*/
|
|
6314
|
+
function progress(line) {
|
|
6315
|
+
if (!isJsonMode()) console.log(line);
|
|
6316
|
+
}
|
|
6241
6317
|
/** Upload a build-context tarball; returns the opaque `source` ref for deploy. */
|
|
6242
6318
|
async function uploadSource(url, token, projectId, tarPath) {
|
|
6243
6319
|
const bytes = fs.readFileSync(tarPath);
|
|
6244
6320
|
const sizeMb = (bytes.length / 1024 / 1024).toFixed(1);
|
|
6245
6321
|
if (bytes.length > MAX_SOURCE_UPLOAD_BYTES) fail(`Source context is ${sizeMb} MB — the upload cap is ${Math.round(MAX_SOURCE_UPLOAD_BYTES / 1024 / 1024)} MB.`, "Trim the build context: exclude sourcemaps (*.map), build output and large assets via .rebaseignore or .gitignore.");
|
|
6246
|
-
|
|
6322
|
+
progress(chalk.gray(` Uploading source (${sizeMb} MB)...`));
|
|
6247
6323
|
const res = await fetch(`${url}/api/functions/deploy/upload?projectId=${encodeURIComponent(projectId)}`, {
|
|
6248
6324
|
method: "POST",
|
|
6249
6325
|
headers: {
|
|
@@ -6275,7 +6351,7 @@ async function deployBundle(opts) {
|
|
|
6275
6351
|
const loaded = loadManifest(projectRoot);
|
|
6276
6352
|
const backend = findBackendApp(loaded.manifest);
|
|
6277
6353
|
if (!backend) fail("This repository declares no backend app to deploy as a bundle.", "A managed deploy runs the backend; declare one in rebase.json, or deploy from the backend's repository.");
|
|
6278
|
-
|
|
6354
|
+
progress(chalk.gray(" Building bundle..."));
|
|
6279
6355
|
bundleDir = (await buildBundle({
|
|
6280
6356
|
projectRoot,
|
|
6281
6357
|
appName: backend.name,
|
|
@@ -6283,16 +6359,16 @@ async function deployBundle(opts) {
|
|
|
6283
6359
|
runtimeRange: loaded.manifest.rebase,
|
|
6284
6360
|
storage: loaded.manifest.storage,
|
|
6285
6361
|
skipTypeCheck: opts.skipTypeCheck,
|
|
6286
|
-
log: (m) =>
|
|
6362
|
+
log: (m) => progress(chalk.gray(m))
|
|
6287
6363
|
})).outDir;
|
|
6288
6364
|
try {
|
|
6289
6365
|
const folded = await foldFrontendIntoBundle({
|
|
6290
6366
|
projectRoot,
|
|
6291
6367
|
manifest: loaded.manifest,
|
|
6292
6368
|
bundleDir,
|
|
6293
|
-
log: (m) =>
|
|
6369
|
+
log: (m) => progress(m)
|
|
6294
6370
|
});
|
|
6295
|
-
for (const outcome of folded)
|
|
6371
|
+
for (const outcome of folded) progress(chalk.gray(` folded ${outcome.appName} in (${outcome.fileCount} file(s), served at ${outcome.path})`));
|
|
6296
6372
|
} catch (err) {
|
|
6297
6373
|
fail(err instanceof Error ? err.message : String(err), "Fix the frontend build, or pass --no-static to deploy the API alone.");
|
|
6298
6374
|
}
|
|
@@ -6309,7 +6385,7 @@ async function deployBundle(opts) {
|
|
|
6309
6385
|
try {
|
|
6310
6386
|
await packBundle(bundleDir, tarPath);
|
|
6311
6387
|
const sizeMb = (fs.statSync(tarPath).size / 1024 / 1024).toFixed(1);
|
|
6312
|
-
|
|
6388
|
+
progress(chalk.gray(` Uploading bundle (${sizeMb} MB)...`));
|
|
6313
6389
|
bundleId = await uploadBundle(url, token, projectId, tarPath);
|
|
6314
6390
|
} catch (e) {
|
|
6315
6391
|
fail(e instanceof Error ? e.message : String(e));
|
|
@@ -6317,8 +6393,10 @@ async function deployBundle(opts) {
|
|
|
6317
6393
|
} finally {
|
|
6318
6394
|
fs.rmSync(tarPath, { force: true });
|
|
6319
6395
|
}
|
|
6320
|
-
|
|
6321
|
-
|
|
6396
|
+
if (!isJsonMode()) {
|
|
6397
|
+
console.log("");
|
|
6398
|
+
console.log(` 🚀 Triggering managed deployment for ${chalk.bold(projectRef)} (schema ${manifest.schemaVersion})...`);
|
|
6399
|
+
}
|
|
6322
6400
|
let declaredApps = [];
|
|
6323
6401
|
try {
|
|
6324
6402
|
declaredApps = declaredAppsFrom(loadManifest(process.cwd()).manifest);
|
|
@@ -6406,9 +6484,75 @@ function planBareDeploy(project, latest, now) {
|
|
|
6406
6484
|
lines: ["This project has no git repository configured and no stored source archive to rebuild.", "Upload this directory with `--source .`, or set a repository URL in the project settings."]
|
|
6407
6485
|
};
|
|
6408
6486
|
}
|
|
6487
|
+
/** `code` of the warning below, and the field name it sets in the payload. */
|
|
6488
|
+
var EJECTS_MANAGED_RUNTIME = "ejects_managed_runtime";
|
|
6409
6489
|
/** The one sentence that says a source build undoes `runtimeMode: managed`. */
|
|
6410
6490
|
function ejectWarning(projectRef) {
|
|
6411
|
-
return
|
|
6491
|
+
return {
|
|
6492
|
+
code: EJECTS_MANAGED_RUNTIME,
|
|
6493
|
+
message: `${projectRef} runs on the managed runtime — this build ejects it to a custom container.`,
|
|
6494
|
+
hint: "Use `rebase cloud deploy --bundle` to stay on managed."
|
|
6495
|
+
};
|
|
6496
|
+
}
|
|
6497
|
+
/**
|
|
6498
|
+
* Why a container-image deploy of a managed project is refused — or `undefined`
|
|
6499
|
+
* to let it through.
|
|
6500
|
+
*
|
|
6501
|
+
* Every path below this point builds a container image, and a successful one
|
|
6502
|
+
* sets `runtimeMode: "custom"` server-side. So the question is never "which flag
|
|
6503
|
+
* was used" but "did the caller ask to leave the managed runtime", and only
|
|
6504
|
+
* `--force` answers it.
|
|
6505
|
+
*
|
|
6506
|
+
* `--source` used to be read as answering it too, on the theory that uploading a
|
|
6507
|
+
* build context is self-evidently a deliberate eject. It is not: `--source`
|
|
6508
|
+
* picks *which source* gets built — this directory, rather than the stale
|
|
6509
|
+
* archive the control plane is holding — and the eject is a side effect of the
|
|
6510
|
+
* answer. That is exactly how a live project got flipped to `custom` by someone
|
|
6511
|
+
* whose actual intent was "deploy what I have here", and it is the same
|
|
6512
|
+
* ignorance the bare form is refused for. Same ignorance, same refusal.
|
|
6513
|
+
*/
|
|
6514
|
+
function ejectRefusal(opts, projectRef) {
|
|
6515
|
+
if (!opts.managed || opts.force) return void 0;
|
|
6516
|
+
const eject = "To eject on purpose, add `--force`.";
|
|
6517
|
+
if (opts.source) return {
|
|
6518
|
+
message: `${projectRef} runs on the managed runtime, and \`--source\` builds a container image from this directory — which ejects it from managed. Picking a build method is not the same as asking to leave the runtime.`,
|
|
6519
|
+
hint: `Deploy this directory to the managed runtime with \`rebase cloud deploy --bundle\`. ${eject}`,
|
|
6520
|
+
code: "managed_project"
|
|
6521
|
+
};
|
|
6522
|
+
return {
|
|
6523
|
+
message: `${projectRef} runs on the managed runtime, and a plain \`rebase cloud deploy\` builds a container image instead — ejecting it from managed, from source the control plane already holds rather than this directory.`,
|
|
6524
|
+
hint: `Redeploy it with \`rebase cloud deploy --bundle\`. ${eject} \`--source . --force\` builds this directory; \`--force\` alone builds what the control plane holds.`,
|
|
6525
|
+
code: "managed_project"
|
|
6526
|
+
};
|
|
6527
|
+
}
|
|
6528
|
+
/**
|
|
6529
|
+
* Which warnings a container-image deploy has earned.
|
|
6530
|
+
*
|
|
6531
|
+
* Pure, and separate from the printing, because the printing is what went
|
|
6532
|
+
* wrong: the eject warning used to be written inline behind `!isJsonMode()`, so
|
|
6533
|
+
* the fact that a deploy ejects a managed project existed only as a side effect
|
|
6534
|
+
* of a TTY being attached. Deciding here, emitting once at the call site, means
|
|
6535
|
+
* the decision cannot be output-mode-dependent again.
|
|
6536
|
+
*
|
|
6537
|
+
* The condition is just `managed`: anything reaching this point is a container
|
|
6538
|
+
* image build that `ejectRefusal` has already let through, and on a managed
|
|
6539
|
+
* project that is an eject however it was spelled. A caller who passed `--force`
|
|
6540
|
+
* knows — the warning is for the transcript and the payload, which is what
|
|
6541
|
+
* anyone reviewing the deploy afterwards actually reads.
|
|
6542
|
+
*/
|
|
6543
|
+
function deployWarnings(opts, projectRef) {
|
|
6544
|
+
return opts.managed ? [ejectWarning(projectRef)] : [];
|
|
6545
|
+
}
|
|
6546
|
+
/** The warning half of a deploy's JSON payload — merged into whatever it emits. */
|
|
6547
|
+
function warningPayload(warnings) {
|
|
6548
|
+
return {
|
|
6549
|
+
warnings: warnings.map((w) => ({
|
|
6550
|
+
code: w.code,
|
|
6551
|
+
message: w.message,
|
|
6552
|
+
hint: w.hint ?? null
|
|
6553
|
+
})),
|
|
6554
|
+
ejectsManagedRuntime: warnings.some((w) => w.code === EJECTS_MANAGED_RUNTIME)
|
|
6555
|
+
};
|
|
6412
6556
|
}
|
|
6413
6557
|
/**
|
|
6414
6558
|
* Read the two rows the preflight needs.
|
|
@@ -6479,17 +6623,18 @@ async function deployCommand(rawArgs, projectRef) {
|
|
|
6479
6623
|
}
|
|
6480
6624
|
const { project, latest } = await readDeployContext(client, projectId);
|
|
6481
6625
|
const plan = planBareDeploy(project, latest, /* @__PURE__ */ new Date());
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6626
|
+
const eject = {
|
|
6627
|
+
managed: plan.managed,
|
|
6628
|
+
source: Boolean(args["--source"]),
|
|
6629
|
+
force: args["--force"] === true
|
|
6630
|
+
};
|
|
6631
|
+
const refusal = ejectRefusal(eject, projectRef);
|
|
6632
|
+
if (refusal) fail(refusal.message, refusal.hint, refusal.code);
|
|
6633
|
+
const warnings = deployWarnings(eject, projectRef);
|
|
6634
|
+
for (const w of warnings) warn(w.message, w.hint);
|
|
6635
|
+
if (!args["--source"] && !isJsonMode()) {
|
|
6490
6636
|
console.log("");
|
|
6491
|
-
console.log(chalk.
|
|
6492
|
-
console.log(chalk.gray(" Use `rebase cloud deploy --bundle` to stay on managed."));
|
|
6637
|
+
for (const line of plan.lines) console.log(chalk.gray(` ${line}`));
|
|
6493
6638
|
}
|
|
6494
6639
|
let source;
|
|
6495
6640
|
if (args["--source"]) {
|
|
@@ -6502,8 +6647,10 @@ async function deployCommand(rawArgs, projectRef) {
|
|
|
6502
6647
|
fs.rmSync(tarPath, { force: true });
|
|
6503
6648
|
}
|
|
6504
6649
|
}
|
|
6505
|
-
|
|
6506
|
-
|
|
6650
|
+
if (!isJsonMode()) {
|
|
6651
|
+
console.log("");
|
|
6652
|
+
console.log(` 🚀 Triggering deployment for project ${chalk.bold(projectRef)}${source ? " from uploaded source" : ""}...`);
|
|
6653
|
+
}
|
|
6507
6654
|
const body = { projectId };
|
|
6508
6655
|
if (source) body.source = source;
|
|
6509
6656
|
if (args["--message"]) body.message = args["--message"];
|
|
@@ -6531,7 +6678,8 @@ async function deployCommand(rawArgs, projectRef) {
|
|
|
6531
6678
|
deploymentId,
|
|
6532
6679
|
deduplicated,
|
|
6533
6680
|
frameworkVersion: frameworkVersion ?? null,
|
|
6534
|
-
following: false
|
|
6681
|
+
following: false,
|
|
6682
|
+
...warningPayload(warnings)
|
|
6535
6683
|
});
|
|
6536
6684
|
return;
|
|
6537
6685
|
}
|
|
@@ -6545,7 +6693,8 @@ async function deployCommand(rawArgs, projectRef) {
|
|
|
6545
6693
|
deduplicated,
|
|
6546
6694
|
frameworkVersion: frameworkVersion ?? null,
|
|
6547
6695
|
following: true,
|
|
6548
|
-
status
|
|
6696
|
+
status,
|
|
6697
|
+
...warningPayload(warnings)
|
|
6549
6698
|
});
|
|
6550
6699
|
}
|
|
6551
6700
|
/**
|
|
@@ -9159,6 +9308,7 @@ function describeDatabaseState(db) {
|
|
|
9159
9308
|
* So both are printed, rather than leaving anyone to infer one from a Docker tag.
|
|
9160
9309
|
*/
|
|
9161
9310
|
function describeRuntime(project) {
|
|
9311
|
+
if (project.runtimeMode == null || project.runtimeMode.trim() === "") return `not deployed yet ${chalk.gray("· the first deploy decides (`--bundle` keeps it managed)")}`;
|
|
9162
9312
|
if (project.runtimeMode !== "managed") return `custom ${chalk.gray("· your own image")}`;
|
|
9163
9313
|
const version = project.runtimeVersion ?? "unknown";
|
|
9164
9314
|
const framework = project.runtimeFrameworkVersion;
|
|
@@ -9557,17 +9707,41 @@ async function billingCommand(rawArgs) {
|
|
|
9557
9707
|
* dispatched from here. Individual groups live in sibling modules; this file
|
|
9558
9708
|
* only routes and prints help.
|
|
9559
9709
|
*/
|
|
9560
|
-
/**
|
|
9710
|
+
/**
|
|
9711
|
+
* Positional tokens after `rebase cloud` (group, action, …).
|
|
9712
|
+
*
|
|
9713
|
+
* Two things stop a flag being mistaken for the group. `GLOBAL_CLOUD_FLAGS` is
|
|
9714
|
+
* declared so `arg` *consumes* the flags that may precede it — critically
|
|
9715
|
+
* together with their values, which is the half that filtering cannot do. The
|
|
9716
|
+
* leading-`-` skip then covers a flag nobody declared, so an unrecognised
|
|
9717
|
+
* boolean shifts nothing.
|
|
9718
|
+
*
|
|
9719
|
+
* Only leading tokens are skipped: past the group and action, an undeclared
|
|
9720
|
+
* flag and its value are somebody else's positionals and none of our business.
|
|
9721
|
+
* A flag this file has never heard of, that takes a value, placed before the
|
|
9722
|
+
* group, is the one shape still unresolvable here — there is no way to know
|
|
9723
|
+
* whether the token after it is its value or the group, and guessing either way
|
|
9724
|
+
* is worse than the handler reporting an unknown group.
|
|
9725
|
+
*
|
|
9726
|
+
* Exported so its tests can drive the real thing. The dispatch test used to
|
|
9727
|
+
* re-implement it locally as `slice(3).filter(a => !a.startsWith("-"))` — which
|
|
9728
|
+
* filtered flags, while this function did not — so the test asserted the
|
|
9729
|
+
* behaviour we wanted against a copy that had it, and stayed green for as long
|
|
9730
|
+
* as the real dispatcher was broken.
|
|
9731
|
+
*/
|
|
9561
9732
|
function positionals(rawArgs) {
|
|
9562
|
-
|
|
9733
|
+
const rest = arg(GLOBAL_CLOUD_FLAGS, {
|
|
9563
9734
|
argv: rawArgs.slice(3),
|
|
9564
9735
|
permissive: true
|
|
9565
9736
|
})._;
|
|
9737
|
+
let i = 0;
|
|
9738
|
+
while (i < rest.length && rest[i].startsWith("-")) i++;
|
|
9739
|
+
return rest.slice(i);
|
|
9566
9740
|
}
|
|
9567
9741
|
async function cloudCommand(subcommand, rawArgs) {
|
|
9568
9742
|
initOutputMode(rawArgs);
|
|
9569
9743
|
const pos = positionals(rawArgs);
|
|
9570
|
-
const group =
|
|
9744
|
+
const group = pos[0] ?? (subcommand !== "--help" ? subcommand : void 0);
|
|
9571
9745
|
const action = pos[1];
|
|
9572
9746
|
if (!group || subcommand === "--help") {
|
|
9573
9747
|
printCloudHelp();
|
|
@@ -9989,8 +10163,9 @@ async function entry(args) {
|
|
|
9989
10163
|
console.log(getVersion());
|
|
9990
10164
|
return;
|
|
9991
10165
|
}
|
|
9992
|
-
const
|
|
9993
|
-
const
|
|
10166
|
+
const words = parsedArgs._.filter((a) => !a.startsWith("-"));
|
|
10167
|
+
const command = words[0];
|
|
10168
|
+
const subcommand = words[1];
|
|
9994
10169
|
if (!command || parsedArgs["--help"] && ![
|
|
9995
10170
|
"init",
|
|
9996
10171
|
"schema",
|
|
@@ -10142,6 +10317,6 @@ ${chalk.gray("Documentation: https://rebase.pro/docs")}
|
|
|
10142
10317
|
`);
|
|
10143
10318
|
}
|
|
10144
10319
|
//#endregion
|
|
10145
|
-
export { CURRENT_RUNTIME_RANGE, DEFAULT_BUNDLE_DIR, DEFAULT_CONFIG_DIR, DEFAULT_CRONS_DIR, DEFAULT_FUNCTIONS_DIR, DEFAULT_SCHEMA_FILE, MANIFEST_FILENAME, ManifestError, TEMPLATE_PLACEHOLDER_FILES, appsCommand, assessManagedCompatibility, authCommand, buildBundle, buildCommand, buildInitQuestions, buildStaticBundle, buildableApps, cloudCommand, collectDeclaredDependencies, configureEnvFile, createRebaseApp, dbCommand, detectFrameworkDepDrift, detectNativeDependencies, detectPackageManager, detectStorageAuthorize, devCommand, doctorCommand, ejectCommand, entry, findBackendApp, findBackendDir, findEnvFile, findFrontendDir, findProjectRoot, findUnusedServerEntry, foldStaticIntoBundle, formatCdTarget, generateSdkCommand, getActiveBackendPlugin, getPMCommands, isIdentifierLike, isPnpmAvailable, loadManifest, manifestExists, manifestPath, normalizeEsmSpecifiers, pnpmAvailabilityFromProbe, printInitHelp, requireBackendDir, requireProjectRoot, resetPnpmAvailabilityCache, resolveBackendPaths, resolveCliVersion, resolveExampleBaseUrl, resolveLocalBin, resolvePluginCliScript, resolveTsx, schemaCommand, startCommand, synthesizeManifest, validateManifest, validateProjectName, validateTsxInstallation, writeManifest };
|
|
10320
|
+
export { CURRENT_RUNTIME_RANGE, DEFAULT_BUNDLE_DIR, DEFAULT_CONFIG_DIR, DEFAULT_CRONS_DIR, DEFAULT_FUNCTIONS_DIR, DEFAULT_SCHEMA_FILE, DEV_PORT_FILENAME, MANIFEST_FILENAME, ManifestError, TEMPLATE_PLACEHOLDER_FILES, appsCommand, assessManagedCompatibility, authCommand, buildBundle, buildCommand, buildInitQuestions, buildStaticBundle, buildableApps, cloudCommand, collectDeclaredDependencies, configureEnvFile, createRebaseApp, dbCommand, detectFrameworkDepDrift, detectNativeDependencies, detectPackageManager, detectStorageAuthorize, devCommand, doctorCommand, ejectCommand, entry, findBackendApp, findBackendDir, findEnvFile, findFrontendDir, findProjectRoot, findUnusedServerEntry, foldStaticIntoBundle, formatCdTarget, generateSdkCommand, getActiveBackendPlugin, getPMCommands, getProjectPort, isIdentifierLike, isPnpmAvailable, loadManifest, manifestExists, manifestPath, normalizeEsmSpecifiers, pnpmAvailabilityFromProbe, positionals, printInitHelp, requireBackendDir, requireProjectRoot, resetPnpmAvailabilityCache, resolveBackendPaths, resolveCliVersion, resolveExampleBaseUrl, resolveLocalBin, resolvePluginCliScript, resolveStartPort, resolveTsx, schemaCommand, startCommand, synthesizeManifest, validateManifest, validateProjectName, validateTsxInstallation, writeManifest };
|
|
10146
10321
|
|
|
10147
10322
|
//# sourceMappingURL=index.es.js.map
|