@moku-labs/worker 0.7.1 → 0.7.3
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/{cli-BBO_YNVC.cjs → cli-DQcpvh2s.cjs} +152 -23
- package/dist/{cli-D67ea3Lu.mjs → cli-MICK1cvv.mjs} +152 -23
- package/dist/cli.cjs +1 -1
- package/dist/cli.d.cts +1 -1
- package/dist/cli.d.mts +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/{index-Dse6wZJH.d.cts → index-DCweBI9s.d.cts} +13 -5
- package/dist/{index-Dse6wZJH.d.mts → index-DCweBI9s.d.mts} +13 -5
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
|
@@ -1984,8 +1984,9 @@ const runDev = async (ctx, opts, deps) => {
|
|
|
1984
1984
|
//#region src/plugins/deploy/infra/plan.ts
|
|
1985
1985
|
/**
|
|
1986
1986
|
* Decide whether a single declared resource already exists in the account, recovering its id
|
|
1987
|
-
* (kv/d1) when it does. Durable Objects are config-only
|
|
1988
|
-
*
|
|
1987
|
+
* (kv/d1) when it does. Durable Objects are config-only — they ship with the Worker (`wrangler
|
|
1988
|
+
* deploy` + the auto-derived DO migration create the namespace), never provisioned via the API — so
|
|
1989
|
+
* they are treated as already EXISTING, and the plan never re-offers to "create" them each deploy.
|
|
1989
1990
|
*
|
|
1990
1991
|
* @param resource - The declared resource descriptor.
|
|
1991
1992
|
* @param existing - The indexed set of resources already in the account.
|
|
@@ -2013,7 +2014,7 @@ const checkExisting = (resource, existing) => {
|
|
|
2013
2014
|
}
|
|
2014
2015
|
case "r2": return { exists: existing.r2.has(resource.name) };
|
|
2015
2016
|
case "queue": return { exists: existing.queue.has(resource.name) };
|
|
2016
|
-
case "do": return { exists:
|
|
2017
|
+
case "do": return { exists: true };
|
|
2017
2018
|
}
|
|
2018
2019
|
};
|
|
2019
2020
|
/**
|
|
@@ -2207,6 +2208,57 @@ const renderProvisionResult = (ui, result) => {
|
|
|
2207
2208
|
}
|
|
2208
2209
|
}
|
|
2209
2210
|
};
|
|
2211
|
+
/**
|
|
2212
|
+
* Format an elapsed duration compactly: sub-second as `820ms`, otherwise one-decimal seconds (`4.2s`),
|
|
2213
|
+
* and minutes once it crosses 60s (`1m04s`) so a long deploy stays readable.
|
|
2214
|
+
*
|
|
2215
|
+
* @param ms - The elapsed milliseconds.
|
|
2216
|
+
* @returns The compact duration string.
|
|
2217
|
+
* @example
|
|
2218
|
+
* ```ts
|
|
2219
|
+
* formatDuration(4234); // "4.2s"
|
|
2220
|
+
* ```
|
|
2221
|
+
*/
|
|
2222
|
+
const formatDuration = (ms) => {
|
|
2223
|
+
if (ms < 1e3) return `${String(ms)}ms`;
|
|
2224
|
+
const seconds = ms / 1e3;
|
|
2225
|
+
if (seconds < 60) return `${seconds.toFixed(1)}s`;
|
|
2226
|
+
const whole = Math.floor(seconds);
|
|
2227
|
+
return `${String(Math.floor(whole / 60))}m${String(whole % 60).padStart(2, "0")}s`;
|
|
2228
|
+
};
|
|
2229
|
+
/**
|
|
2230
|
+
* Render the terminal deploy summary as a branded panel — the headline the user actually wants. The
|
|
2231
|
+
* live URL leads on its own line (pink, so it is the first thing the eye lands on), then a dim
|
|
2232
|
+
* key/value block: the target stage, the resource tally (with a red `failed` count when non-zero),
|
|
2233
|
+
* and the wall-clock time the whole deploy took. Replaces the prior single `deployed → url` line.
|
|
2234
|
+
*
|
|
2235
|
+
* @param ui - The branded console to render through.
|
|
2236
|
+
* @param summary - The deploy summary fields.
|
|
2237
|
+
* @param summary.url - The live deployed URL (the panel headline).
|
|
2238
|
+
* @param summary.stage - The target stage the worker deployed to.
|
|
2239
|
+
* @param summary.created - How many resources were created this run.
|
|
2240
|
+
* @param summary.exists - How many resources already existed (skipped).
|
|
2241
|
+
* @param summary.failed - How many resources failed to provision.
|
|
2242
|
+
* @param summary.elapsedMs - The wall-clock deploy duration in milliseconds.
|
|
2243
|
+
* @example
|
|
2244
|
+
* ```ts
|
|
2245
|
+
* renderDeploySummary(ui, { url, stage: "production", created: 0, exists: 5, failed: 0, elapsedMs: 4234 });
|
|
2246
|
+
* ```
|
|
2247
|
+
*/
|
|
2248
|
+
const renderDeploySummary = (ui, summary) => {
|
|
2249
|
+
const { palette } = ui;
|
|
2250
|
+
const tally = `${String(summary.exists)} exist · ${String(summary.created)} created`;
|
|
2251
|
+
const failedLabel = palette.red(`${String(summary.failed)} failed`);
|
|
2252
|
+
const resources = summary.failed > 0 ? `${tally} · ${failedLabel}` : tally;
|
|
2253
|
+
ui.heading("Deployed");
|
|
2254
|
+
ui.box([
|
|
2255
|
+
palette.pink(summary.url),
|
|
2256
|
+
"",
|
|
2257
|
+
`${palette.dim("stage".padEnd(10))}${summary.stage}`,
|
|
2258
|
+
`${palette.dim("resources".padEnd(10))}${resources}`,
|
|
2259
|
+
`${palette.dim("took".padEnd(10))}${formatDuration(summary.elapsedMs)}`
|
|
2260
|
+
]);
|
|
2261
|
+
};
|
|
2210
2262
|
//#endregion
|
|
2211
2263
|
//#region src/plugins/deploy/naming.ts
|
|
2212
2264
|
/**
|
|
@@ -3086,6 +3138,34 @@ const guidedUpload = async (ctx, manifest, deps) => {
|
|
|
3086
3138
|
return true;
|
|
3087
3139
|
};
|
|
3088
3140
|
/**
|
|
3141
|
+
* The final deploy step: confirm the target (guided only), run `wrangler deploy` with interactive
|
|
3142
|
+
* retry, then emit deploy:complete. Returns the deployed URL, or undefined when the target gate or a
|
|
3143
|
+
* deploy retry is declined (so the caller renders the summary panel only on a real success).
|
|
3144
|
+
*
|
|
3145
|
+
* @param ctx - The deploy plugin context.
|
|
3146
|
+
* @param manifest - The assembled (or caller-supplied) deploy manifest.
|
|
3147
|
+
* @param stage - The resolved deploy stage (for the confirm prompt).
|
|
3148
|
+
* @param deps - Interactivity + the confirm prompt.
|
|
3149
|
+
* @returns The deployed URL once live; undefined when the user declined the gate or a retry (abort).
|
|
3150
|
+
* @example
|
|
3151
|
+
* ```ts
|
|
3152
|
+
* const url = await guidedDeployStep(ctx, manifest, stage, deps);
|
|
3153
|
+
* if (url === undefined) return emitAborted(ctx);
|
|
3154
|
+
* ```
|
|
3155
|
+
*/
|
|
3156
|
+
const guidedDeployStep = async (ctx, manifest, stage, deps) => {
|
|
3157
|
+
if (!await deps.confirm(`Deploy "${manifest.name}" to ${stage}?`)) return void 0;
|
|
3158
|
+
ctx.emit("deploy:phase", { phase: "deploy" });
|
|
3159
|
+
const url = await guidedStep(() => runWrangler([
|
|
3160
|
+
"deploy",
|
|
3161
|
+
"--config",
|
|
3162
|
+
ctx.config.configFile
|
|
3163
|
+
]), HINTS.deploy, deps);
|
|
3164
|
+
if (url === ABORTED) return void 0;
|
|
3165
|
+
ctx.emit("deploy:complete", { url });
|
|
3166
|
+
return url;
|
|
3167
|
+
};
|
|
3168
|
+
/**
|
|
3089
3169
|
* Create the deploy api. Assembles the manifest from each resource plugin's own deployManifest(),
|
|
3090
3170
|
* runs an infra preflight (check-before-create + id capture), generates config, uploads, and runs
|
|
3091
3171
|
* `wrangler deploy`, emitting global deploy events along the way.
|
|
@@ -3127,11 +3207,11 @@ const createDeployApi = (ctx) => ({
|
|
|
3127
3207
|
const ci = opts?.ci ?? ctx.config.ci;
|
|
3128
3208
|
const stage = opts?.stage ?? ctx.global.stage;
|
|
3129
3209
|
const interactive = !ci && stdoutIsTty();
|
|
3130
|
-
const confirm = interactive ? (0, _moku_labs_common_cli.createBrandPrompts)().confirm : async (_question) => true;
|
|
3131
3210
|
const deps = {
|
|
3132
3211
|
interactive,
|
|
3133
|
-
confirm
|
|
3212
|
+
confirm: interactive ? (0, _moku_labs_common_cli.createBrandPrompts)().confirm : async (_question) => true
|
|
3134
3213
|
};
|
|
3214
|
+
const startedAt = Date.now();
|
|
3135
3215
|
ctx.emit("deploy:phase", { phase: "auth" });
|
|
3136
3216
|
if (!await guidedAuth(ctx, deps)) return emitAborted(ctx);
|
|
3137
3217
|
if (!await guidedWebBuild(ctx, opts?.webBuild ?? ctx.config.webBuild, deps)) return emitAborted(ctx);
|
|
@@ -3143,15 +3223,16 @@ const createDeployApi = (ctx) => ({
|
|
|
3143
3223
|
ctx.emit("deploy:phase", { phase: "wrangler-config" });
|
|
3144
3224
|
await writeWranglerConfig(ctx.config.configFile, manifest, provisioned.ids, wranglerExtra(ctx.config));
|
|
3145
3225
|
if (!await guidedUpload(ctx, manifest, deps)) return emitAborted(ctx);
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3226
|
+
const url = await guidedDeployStep(ctx, manifest, stage, deps);
|
|
3227
|
+
if (url === void 0) return emitAborted(ctx);
|
|
3228
|
+
renderDeploySummary((0, _moku_labs_common_cli.createBrandConsole)(), {
|
|
3229
|
+
url,
|
|
3230
|
+
stage,
|
|
3231
|
+
created: provisioned.created.length,
|
|
3232
|
+
exists: provisioned.skipped.length,
|
|
3233
|
+
failed: provisioned.failed.length,
|
|
3234
|
+
elapsedMs: Date.now() - startedAt
|
|
3235
|
+
});
|
|
3155
3236
|
},
|
|
3156
3237
|
/**
|
|
3157
3238
|
* Start a long-lived local dev session: cold-build the Moku site, spawn `wrangler dev
|
|
@@ -3603,6 +3684,25 @@ const createCliApi = (ctx) => ({
|
|
|
3603
3684
|
//#region src/plugins/cli/handlers.ts
|
|
3604
3685
|
/** Divider drawn before the native `wrangler dev` TUI so the moku preamble reads as one section. */
|
|
3605
3686
|
const WRANGLER_DIVIDER = ` ── wrangler ${"─".repeat(48)}`;
|
|
3687
|
+
/** Deploy phases that are a slow, opaque wait (captured output) — worth a live spinner on a TTY. */
|
|
3688
|
+
const SPINNER_PHASES = new Set(["upload", "deploy"]);
|
|
3689
|
+
/** Braille spinner glyphs; advance one per tick. */
|
|
3690
|
+
const SPINNER_FRAMES = [
|
|
3691
|
+
"⠋",
|
|
3692
|
+
"⠙",
|
|
3693
|
+
"⠹",
|
|
3694
|
+
"⠸",
|
|
3695
|
+
"⠼",
|
|
3696
|
+
"⠴",
|
|
3697
|
+
"⠦",
|
|
3698
|
+
"⠧",
|
|
3699
|
+
"⠇",
|
|
3700
|
+
"⠏"
|
|
3701
|
+
];
|
|
3702
|
+
/** Spinner tick interval (ms). */
|
|
3703
|
+
const SPINNER_TICK_MS = 80;
|
|
3704
|
+
/** Carriage-return + blanks + carriage-return that wipes the transient spinner line before settling. */
|
|
3705
|
+
const SPINNER_CLEAR = `\r${" ".repeat(72)}\r`;
|
|
3606
3706
|
/**
|
|
3607
3707
|
* Builds the hook handlers that turn global deploy events into a live progress TUI.
|
|
3608
3708
|
* Each logs a clean, prefix-free message via `ctx.log`; the branded log sink (installed
|
|
@@ -3617,24 +3717,53 @@ const WRANGLER_DIVIDER = ` ── wrangler ${"─".repeat(48)}`;
|
|
|
3617
3717
|
* const hooks = createCliHooks(ctx);
|
|
3618
3718
|
* hooks["deploy:phase"]({ phase: "detect" }); // logs "detect" → renders " › detect"
|
|
3619
3719
|
* hooks["dev:phase"]({ phase: "serve", detail: "http://localhost:8787" }); // "serve · …"
|
|
3620
|
-
* hooks["deploy:complete"](
|
|
3720
|
+
* hooks["deploy:complete"](); // settles the deploy spinner; the "Deployed" panel renders separately
|
|
3621
3721
|
* ```
|
|
3622
3722
|
*/
|
|
3623
3723
|
const createCliHooks = (ctx) => {
|
|
3624
3724
|
const ui = (0, _moku_labs_common_cli.createBrandConsole)();
|
|
3725
|
+
const { palette } = ui;
|
|
3726
|
+
let spinnerTimer;
|
|
3727
|
+
let spinnerLabel;
|
|
3728
|
+
const stopSpinner = () => {
|
|
3729
|
+
if (spinnerTimer !== void 0) {
|
|
3730
|
+
clearInterval(spinnerTimer);
|
|
3731
|
+
spinnerTimer = void 0;
|
|
3732
|
+
}
|
|
3733
|
+
if (spinnerLabel !== void 0) {
|
|
3734
|
+
process.stdout.write(SPINNER_CLEAR);
|
|
3735
|
+
ctx.log.info(spinnerLabel);
|
|
3736
|
+
spinnerLabel = void 0;
|
|
3737
|
+
}
|
|
3738
|
+
};
|
|
3739
|
+
const startSpinner = (label) => {
|
|
3740
|
+
spinnerLabel = label;
|
|
3741
|
+
let frame = 0;
|
|
3742
|
+
const text = `${label} …`;
|
|
3743
|
+
spinnerTimer = setInterval(() => {
|
|
3744
|
+
const glyph = SPINNER_FRAMES[frame % SPINNER_FRAMES.length] ?? SPINNER_FRAMES[0];
|
|
3745
|
+
frame += 1;
|
|
3746
|
+
process.stdout.write(`\r ${palette.pink(glyph)} ${palette.dim(text)}`);
|
|
3747
|
+
}, SPINNER_TICK_MS);
|
|
3748
|
+
};
|
|
3625
3749
|
return {
|
|
3626
3750
|
/**
|
|
3627
|
-
*
|
|
3751
|
+
* Render one pipeline phase. Quick phases print a clean line ("phase" / "phase · detail"); the
|
|
3752
|
+
* slow opaque waits (upload / deploy) animate a branded spinner on a TTY, settling to a line when
|
|
3753
|
+
* the next phase or completion arrives. Off a TTY every phase is a plain line (unchanged).
|
|
3628
3754
|
*
|
|
3629
3755
|
* @param p - The deploy:phase event payload.
|
|
3630
3756
|
* @example
|
|
3631
3757
|
* ```ts
|
|
3632
3758
|
* handler({ phase: "detect" }); // "detect"
|
|
3633
|
-
* handler({ phase: "
|
|
3759
|
+
* handler({ phase: "deploy" }); // spins on a TTY, else "deploy"
|
|
3634
3760
|
* ```
|
|
3635
3761
|
*/
|
|
3636
3762
|
"deploy:phase"(p) {
|
|
3637
|
-
|
|
3763
|
+
stopSpinner();
|
|
3764
|
+
const label = p.detail ? `${p.phase} · ${p.detail}` : p.phase;
|
|
3765
|
+
if (process.stdout.isTTY === true && SPINNER_PHASES.has(p.phase)) startSpinner(label);
|
|
3766
|
+
else ctx.log.info(label);
|
|
3638
3767
|
},
|
|
3639
3768
|
/**
|
|
3640
3769
|
* Log one dev-session phase: "phase" or "phase · detail".
|
|
@@ -3675,16 +3804,16 @@ const createCliHooks = (ctx) => {
|
|
|
3675
3804
|
ctx.log.warn(p.message);
|
|
3676
3805
|
},
|
|
3677
3806
|
/**
|
|
3678
|
-
*
|
|
3807
|
+
* Settle the final deploy spinner. The deployed URL + summary now render as a branded panel (the
|
|
3808
|
+
* deploy plugin's renderDeploySummary), so the cli no longer logs a duplicate `deployed → url`.
|
|
3679
3809
|
*
|
|
3680
|
-
* @param p - The deploy:complete event payload.
|
|
3681
3810
|
* @example
|
|
3682
3811
|
* ```ts
|
|
3683
|
-
* handler(
|
|
3812
|
+
* handler(); // clears the `deploy` spinner; the "Deployed" panel follows from the deploy plugin
|
|
3684
3813
|
* ```
|
|
3685
3814
|
*/
|
|
3686
|
-
"deploy:complete"(
|
|
3687
|
-
|
|
3815
|
+
"deploy:complete"() {
|
|
3816
|
+
stopSpinner();
|
|
3688
3817
|
}
|
|
3689
3818
|
};
|
|
3690
3819
|
};
|
|
@@ -1961,8 +1961,9 @@ const runDev = async (ctx, opts, deps) => {
|
|
|
1961
1961
|
//#region src/plugins/deploy/infra/plan.ts
|
|
1962
1962
|
/**
|
|
1963
1963
|
* Decide whether a single declared resource already exists in the account, recovering its id
|
|
1964
|
-
* (kv/d1) when it does. Durable Objects are config-only
|
|
1965
|
-
*
|
|
1964
|
+
* (kv/d1) when it does. Durable Objects are config-only — they ship with the Worker (`wrangler
|
|
1965
|
+
* deploy` + the auto-derived DO migration create the namespace), never provisioned via the API — so
|
|
1966
|
+
* they are treated as already EXISTING, and the plan never re-offers to "create" them each deploy.
|
|
1966
1967
|
*
|
|
1967
1968
|
* @param resource - The declared resource descriptor.
|
|
1968
1969
|
* @param existing - The indexed set of resources already in the account.
|
|
@@ -1990,7 +1991,7 @@ const checkExisting = (resource, existing) => {
|
|
|
1990
1991
|
}
|
|
1991
1992
|
case "r2": return { exists: existing.r2.has(resource.name) };
|
|
1992
1993
|
case "queue": return { exists: existing.queue.has(resource.name) };
|
|
1993
|
-
case "do": return { exists:
|
|
1994
|
+
case "do": return { exists: true };
|
|
1994
1995
|
}
|
|
1995
1996
|
};
|
|
1996
1997
|
/**
|
|
@@ -2184,6 +2185,57 @@ const renderProvisionResult = (ui, result) => {
|
|
|
2184
2185
|
}
|
|
2185
2186
|
}
|
|
2186
2187
|
};
|
|
2188
|
+
/**
|
|
2189
|
+
* Format an elapsed duration compactly: sub-second as `820ms`, otherwise one-decimal seconds (`4.2s`),
|
|
2190
|
+
* and minutes once it crosses 60s (`1m04s`) so a long deploy stays readable.
|
|
2191
|
+
*
|
|
2192
|
+
* @param ms - The elapsed milliseconds.
|
|
2193
|
+
* @returns The compact duration string.
|
|
2194
|
+
* @example
|
|
2195
|
+
* ```ts
|
|
2196
|
+
* formatDuration(4234); // "4.2s"
|
|
2197
|
+
* ```
|
|
2198
|
+
*/
|
|
2199
|
+
const formatDuration = (ms) => {
|
|
2200
|
+
if (ms < 1e3) return `${String(ms)}ms`;
|
|
2201
|
+
const seconds = ms / 1e3;
|
|
2202
|
+
if (seconds < 60) return `${seconds.toFixed(1)}s`;
|
|
2203
|
+
const whole = Math.floor(seconds);
|
|
2204
|
+
return `${String(Math.floor(whole / 60))}m${String(whole % 60).padStart(2, "0")}s`;
|
|
2205
|
+
};
|
|
2206
|
+
/**
|
|
2207
|
+
* Render the terminal deploy summary as a branded panel — the headline the user actually wants. The
|
|
2208
|
+
* live URL leads on its own line (pink, so it is the first thing the eye lands on), then a dim
|
|
2209
|
+
* key/value block: the target stage, the resource tally (with a red `failed` count when non-zero),
|
|
2210
|
+
* and the wall-clock time the whole deploy took. Replaces the prior single `deployed → url` line.
|
|
2211
|
+
*
|
|
2212
|
+
* @param ui - The branded console to render through.
|
|
2213
|
+
* @param summary - The deploy summary fields.
|
|
2214
|
+
* @param summary.url - The live deployed URL (the panel headline).
|
|
2215
|
+
* @param summary.stage - The target stage the worker deployed to.
|
|
2216
|
+
* @param summary.created - How many resources were created this run.
|
|
2217
|
+
* @param summary.exists - How many resources already existed (skipped).
|
|
2218
|
+
* @param summary.failed - How many resources failed to provision.
|
|
2219
|
+
* @param summary.elapsedMs - The wall-clock deploy duration in milliseconds.
|
|
2220
|
+
* @example
|
|
2221
|
+
* ```ts
|
|
2222
|
+
* renderDeploySummary(ui, { url, stage: "production", created: 0, exists: 5, failed: 0, elapsedMs: 4234 });
|
|
2223
|
+
* ```
|
|
2224
|
+
*/
|
|
2225
|
+
const renderDeploySummary = (ui, summary) => {
|
|
2226
|
+
const { palette } = ui;
|
|
2227
|
+
const tally = `${String(summary.exists)} exist · ${String(summary.created)} created`;
|
|
2228
|
+
const failedLabel = palette.red(`${String(summary.failed)} failed`);
|
|
2229
|
+
const resources = summary.failed > 0 ? `${tally} · ${failedLabel}` : tally;
|
|
2230
|
+
ui.heading("Deployed");
|
|
2231
|
+
ui.box([
|
|
2232
|
+
palette.pink(summary.url),
|
|
2233
|
+
"",
|
|
2234
|
+
`${palette.dim("stage".padEnd(10))}${summary.stage}`,
|
|
2235
|
+
`${palette.dim("resources".padEnd(10))}${resources}`,
|
|
2236
|
+
`${palette.dim("took".padEnd(10))}${formatDuration(summary.elapsedMs)}`
|
|
2237
|
+
]);
|
|
2238
|
+
};
|
|
2187
2239
|
//#endregion
|
|
2188
2240
|
//#region src/plugins/deploy/naming.ts
|
|
2189
2241
|
/**
|
|
@@ -3063,6 +3115,34 @@ const guidedUpload = async (ctx, manifest, deps) => {
|
|
|
3063
3115
|
return true;
|
|
3064
3116
|
};
|
|
3065
3117
|
/**
|
|
3118
|
+
* The final deploy step: confirm the target (guided only), run `wrangler deploy` with interactive
|
|
3119
|
+
* retry, then emit deploy:complete. Returns the deployed URL, or undefined when the target gate or a
|
|
3120
|
+
* deploy retry is declined (so the caller renders the summary panel only on a real success).
|
|
3121
|
+
*
|
|
3122
|
+
* @param ctx - The deploy plugin context.
|
|
3123
|
+
* @param manifest - The assembled (or caller-supplied) deploy manifest.
|
|
3124
|
+
* @param stage - The resolved deploy stage (for the confirm prompt).
|
|
3125
|
+
* @param deps - Interactivity + the confirm prompt.
|
|
3126
|
+
* @returns The deployed URL once live; undefined when the user declined the gate or a retry (abort).
|
|
3127
|
+
* @example
|
|
3128
|
+
* ```ts
|
|
3129
|
+
* const url = await guidedDeployStep(ctx, manifest, stage, deps);
|
|
3130
|
+
* if (url === undefined) return emitAborted(ctx);
|
|
3131
|
+
* ```
|
|
3132
|
+
*/
|
|
3133
|
+
const guidedDeployStep = async (ctx, manifest, stage, deps) => {
|
|
3134
|
+
if (!await deps.confirm(`Deploy "${manifest.name}" to ${stage}?`)) return void 0;
|
|
3135
|
+
ctx.emit("deploy:phase", { phase: "deploy" });
|
|
3136
|
+
const url = await guidedStep(() => runWrangler([
|
|
3137
|
+
"deploy",
|
|
3138
|
+
"--config",
|
|
3139
|
+
ctx.config.configFile
|
|
3140
|
+
]), HINTS.deploy, deps);
|
|
3141
|
+
if (url === ABORTED) return void 0;
|
|
3142
|
+
ctx.emit("deploy:complete", { url });
|
|
3143
|
+
return url;
|
|
3144
|
+
};
|
|
3145
|
+
/**
|
|
3066
3146
|
* Create the deploy api. Assembles the manifest from each resource plugin's own deployManifest(),
|
|
3067
3147
|
* runs an infra preflight (check-before-create + id capture), generates config, uploads, and runs
|
|
3068
3148
|
* `wrangler deploy`, emitting global deploy events along the way.
|
|
@@ -3104,11 +3184,11 @@ const createDeployApi = (ctx) => ({
|
|
|
3104
3184
|
const ci = opts?.ci ?? ctx.config.ci;
|
|
3105
3185
|
const stage = opts?.stage ?? ctx.global.stage;
|
|
3106
3186
|
const interactive = !ci && stdoutIsTty();
|
|
3107
|
-
const confirm = interactive ? createBrandPrompts().confirm : async (_question) => true;
|
|
3108
3187
|
const deps = {
|
|
3109
3188
|
interactive,
|
|
3110
|
-
confirm
|
|
3189
|
+
confirm: interactive ? createBrandPrompts().confirm : async (_question) => true
|
|
3111
3190
|
};
|
|
3191
|
+
const startedAt = Date.now();
|
|
3112
3192
|
ctx.emit("deploy:phase", { phase: "auth" });
|
|
3113
3193
|
if (!await guidedAuth(ctx, deps)) return emitAborted(ctx);
|
|
3114
3194
|
if (!await guidedWebBuild(ctx, opts?.webBuild ?? ctx.config.webBuild, deps)) return emitAborted(ctx);
|
|
@@ -3120,15 +3200,16 @@ const createDeployApi = (ctx) => ({
|
|
|
3120
3200
|
ctx.emit("deploy:phase", { phase: "wrangler-config" });
|
|
3121
3201
|
await writeWranglerConfig(ctx.config.configFile, manifest, provisioned.ids, wranglerExtra(ctx.config));
|
|
3122
3202
|
if (!await guidedUpload(ctx, manifest, deps)) return emitAborted(ctx);
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3203
|
+
const url = await guidedDeployStep(ctx, manifest, stage, deps);
|
|
3204
|
+
if (url === void 0) return emitAborted(ctx);
|
|
3205
|
+
renderDeploySummary(createBrandConsole(), {
|
|
3206
|
+
url,
|
|
3207
|
+
stage,
|
|
3208
|
+
created: provisioned.created.length,
|
|
3209
|
+
exists: provisioned.skipped.length,
|
|
3210
|
+
failed: provisioned.failed.length,
|
|
3211
|
+
elapsedMs: Date.now() - startedAt
|
|
3212
|
+
});
|
|
3132
3213
|
},
|
|
3133
3214
|
/**
|
|
3134
3215
|
* Start a long-lived local dev session: cold-build the Moku site, spawn `wrangler dev
|
|
@@ -3580,6 +3661,25 @@ const createCliApi = (ctx) => ({
|
|
|
3580
3661
|
//#region src/plugins/cli/handlers.ts
|
|
3581
3662
|
/** Divider drawn before the native `wrangler dev` TUI so the moku preamble reads as one section. */
|
|
3582
3663
|
const WRANGLER_DIVIDER = ` ── wrangler ${"─".repeat(48)}`;
|
|
3664
|
+
/** Deploy phases that are a slow, opaque wait (captured output) — worth a live spinner on a TTY. */
|
|
3665
|
+
const SPINNER_PHASES = new Set(["upload", "deploy"]);
|
|
3666
|
+
/** Braille spinner glyphs; advance one per tick. */
|
|
3667
|
+
const SPINNER_FRAMES = [
|
|
3668
|
+
"⠋",
|
|
3669
|
+
"⠙",
|
|
3670
|
+
"⠹",
|
|
3671
|
+
"⠸",
|
|
3672
|
+
"⠼",
|
|
3673
|
+
"⠴",
|
|
3674
|
+
"⠦",
|
|
3675
|
+
"⠧",
|
|
3676
|
+
"⠇",
|
|
3677
|
+
"⠏"
|
|
3678
|
+
];
|
|
3679
|
+
/** Spinner tick interval (ms). */
|
|
3680
|
+
const SPINNER_TICK_MS = 80;
|
|
3681
|
+
/** Carriage-return + blanks + carriage-return that wipes the transient spinner line before settling. */
|
|
3682
|
+
const SPINNER_CLEAR = `\r${" ".repeat(72)}\r`;
|
|
3583
3683
|
/**
|
|
3584
3684
|
* Builds the hook handlers that turn global deploy events into a live progress TUI.
|
|
3585
3685
|
* Each logs a clean, prefix-free message via `ctx.log`; the branded log sink (installed
|
|
@@ -3594,24 +3694,53 @@ const WRANGLER_DIVIDER = ` ── wrangler ${"─".repeat(48)}`;
|
|
|
3594
3694
|
* const hooks = createCliHooks(ctx);
|
|
3595
3695
|
* hooks["deploy:phase"]({ phase: "detect" }); // logs "detect" → renders " › detect"
|
|
3596
3696
|
* hooks["dev:phase"]({ phase: "serve", detail: "http://localhost:8787" }); // "serve · …"
|
|
3597
|
-
* hooks["deploy:complete"](
|
|
3697
|
+
* hooks["deploy:complete"](); // settles the deploy spinner; the "Deployed" panel renders separately
|
|
3598
3698
|
* ```
|
|
3599
3699
|
*/
|
|
3600
3700
|
const createCliHooks = (ctx) => {
|
|
3601
3701
|
const ui = createBrandConsole();
|
|
3702
|
+
const { palette } = ui;
|
|
3703
|
+
let spinnerTimer;
|
|
3704
|
+
let spinnerLabel;
|
|
3705
|
+
const stopSpinner = () => {
|
|
3706
|
+
if (spinnerTimer !== void 0) {
|
|
3707
|
+
clearInterval(spinnerTimer);
|
|
3708
|
+
spinnerTimer = void 0;
|
|
3709
|
+
}
|
|
3710
|
+
if (spinnerLabel !== void 0) {
|
|
3711
|
+
process.stdout.write(SPINNER_CLEAR);
|
|
3712
|
+
ctx.log.info(spinnerLabel);
|
|
3713
|
+
spinnerLabel = void 0;
|
|
3714
|
+
}
|
|
3715
|
+
};
|
|
3716
|
+
const startSpinner = (label) => {
|
|
3717
|
+
spinnerLabel = label;
|
|
3718
|
+
let frame = 0;
|
|
3719
|
+
const text = `${label} …`;
|
|
3720
|
+
spinnerTimer = setInterval(() => {
|
|
3721
|
+
const glyph = SPINNER_FRAMES[frame % SPINNER_FRAMES.length] ?? SPINNER_FRAMES[0];
|
|
3722
|
+
frame += 1;
|
|
3723
|
+
process.stdout.write(`\r ${palette.pink(glyph)} ${palette.dim(text)}`);
|
|
3724
|
+
}, SPINNER_TICK_MS);
|
|
3725
|
+
};
|
|
3602
3726
|
return {
|
|
3603
3727
|
/**
|
|
3604
|
-
*
|
|
3728
|
+
* Render one pipeline phase. Quick phases print a clean line ("phase" / "phase · detail"); the
|
|
3729
|
+
* slow opaque waits (upload / deploy) animate a branded spinner on a TTY, settling to a line when
|
|
3730
|
+
* the next phase or completion arrives. Off a TTY every phase is a plain line (unchanged).
|
|
3605
3731
|
*
|
|
3606
3732
|
* @param p - The deploy:phase event payload.
|
|
3607
3733
|
* @example
|
|
3608
3734
|
* ```ts
|
|
3609
3735
|
* handler({ phase: "detect" }); // "detect"
|
|
3610
|
-
* handler({ phase: "
|
|
3736
|
+
* handler({ phase: "deploy" }); // spins on a TTY, else "deploy"
|
|
3611
3737
|
* ```
|
|
3612
3738
|
*/
|
|
3613
3739
|
"deploy:phase"(p) {
|
|
3614
|
-
|
|
3740
|
+
stopSpinner();
|
|
3741
|
+
const label = p.detail ? `${p.phase} · ${p.detail}` : p.phase;
|
|
3742
|
+
if (process.stdout.isTTY === true && SPINNER_PHASES.has(p.phase)) startSpinner(label);
|
|
3743
|
+
else ctx.log.info(label);
|
|
3615
3744
|
},
|
|
3616
3745
|
/**
|
|
3617
3746
|
* Log one dev-session phase: "phase" or "phase · detail".
|
|
@@ -3652,16 +3781,16 @@ const createCliHooks = (ctx) => {
|
|
|
3652
3781
|
ctx.log.warn(p.message);
|
|
3653
3782
|
},
|
|
3654
3783
|
/**
|
|
3655
|
-
*
|
|
3784
|
+
* Settle the final deploy spinner. The deployed URL + summary now render as a branded panel (the
|
|
3785
|
+
* deploy plugin's renderDeploySummary), so the cli no longer logs a duplicate `deployed → url`.
|
|
3656
3786
|
*
|
|
3657
|
-
* @param p - The deploy:complete event payload.
|
|
3658
3787
|
* @example
|
|
3659
3788
|
* ```ts
|
|
3660
|
-
* handler(
|
|
3789
|
+
* handler(); // clears the `deploy` spinner; the "Deployed" panel follows from the deploy plugin
|
|
3661
3790
|
* ```
|
|
3662
3791
|
*/
|
|
3663
|
-
"deploy:complete"(
|
|
3664
|
-
|
|
3792
|
+
"deploy:complete"() {
|
|
3793
|
+
stopSpinner();
|
|
3665
3794
|
}
|
|
3666
3795
|
};
|
|
3667
3796
|
};
|
package/dist/cli.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_cli = require("./cli-
|
|
2
|
+
const require_cli = require("./cli-DQcpvh2s.cjs");
|
|
3
3
|
exports.cliPlugin = require_cli.cliPlugin;
|
|
4
4
|
exports.deployPlugin = require_cli.deployPlugin;
|
package/dist/cli.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as ResourceManifest, n as cliPlugin, r as ExternalManifest, t as deployPlugin } from "./index-
|
|
1
|
+
import { i as ResourceManifest, n as cliPlugin, r as ExternalManifest, t as deployPlugin } from "./index-DCweBI9s.cjs";
|
|
2
2
|
export { type ExternalManifest, type ResourceManifest, cliPlugin, deployPlugin };
|
package/dist/cli.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as ResourceManifest, n as cliPlugin, r as ExternalManifest, t as deployPlugin } from "./index-
|
|
1
|
+
import { i as ResourceManifest, n as cliPlugin, r as ExternalManifest, t as deployPlugin } from "./index-DCweBI9s.mjs";
|
|
2
2
|
export { type ExternalManifest, type ResourceManifest, cliPlugin, deployPlugin };
|
package/dist/cli.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as deployPlugin, t as cliPlugin } from "./cli-
|
|
1
|
+
import { n as deployPlugin, t as cliPlugin } from "./cli-MICK1cvv.mjs";
|
|
2
2
|
export { cliPlugin, deployPlugin };
|
|
@@ -267,17 +267,21 @@ type Api = {
|
|
|
267
267
|
* when omitted. A failure renders a branded `✗` line and sets a non-zero exit code rather than
|
|
268
268
|
* throwing a raw stack trace.
|
|
269
269
|
*
|
|
270
|
-
* @param opts - Optional port and web build hook.
|
|
270
|
+
* @param opts - Optional port, stage, and web build hook.
|
|
271
271
|
* @param opts.port - Local dev port to bind. Defaults to 8787 when omitted.
|
|
272
|
+
* @param opts.stage - Stage for the generated wrangler config's resource names. Falls back to the
|
|
273
|
+
* `--stage` CLI flag, then the app's configured stage. Pass it explicitly from a script for a
|
|
274
|
+
* self-documenting `dev({ stage })` instead of relying on the hidden flag.
|
|
272
275
|
* @param opts.webBuild - Rebuild the web site on change (e.g. `() => webApp.cli.build()`).
|
|
273
276
|
* @returns Resolves when the dev session ends.
|
|
274
277
|
* @example
|
|
275
278
|
* ```ts
|
|
276
|
-
* await app.cli.dev({ port: 7878, webBuild: () => web.cli.build() });
|
|
279
|
+
* await app.cli.dev({ stage: "dev", port: 7878, webBuild: () => web.cli.build() });
|
|
277
280
|
* ```
|
|
278
281
|
*/
|
|
279
282
|
dev(opts?: {
|
|
280
283
|
port?: number;
|
|
284
|
+
stage?: string;
|
|
281
285
|
webBuild?: WebBuild;
|
|
282
286
|
}): Promise<void>;
|
|
283
287
|
/**
|
|
@@ -285,18 +289,22 @@ type Api = {
|
|
|
285
289
|
* `{ ci: true }` for the automated/non-interactive path (CI). A failure renders a branded `✗`
|
|
286
290
|
* line and sets a non-zero exit code rather than throwing a raw stack trace.
|
|
287
291
|
*
|
|
288
|
-
* @param opts - Optional ci flag and a web build hook.
|
|
292
|
+
* @param opts - Optional ci flag, stage, and a web build hook.
|
|
289
293
|
* @param opts.ci - Automated mode: never prompts, auto-confirms. Omit/false → guided on a TTY.
|
|
294
|
+
* @param opts.stage - Stage for the generated wrangler config's resource names (e.g. "production",
|
|
295
|
+
* "staging"). Falls back to the `--stage` CLI flag, then the app's configured stage. Pass it
|
|
296
|
+
* explicitly from a script for a self-documenting `deploy({ stage })` instead of the hidden flag.
|
|
290
297
|
* @param opts.webBuild - Build the web site first (e.g. `() => webApp.cli.build()`), before deploy.
|
|
291
298
|
* @returns Resolves once the deploy completes (or after a failure is rendered).
|
|
292
299
|
* @example
|
|
293
300
|
* ```ts
|
|
294
|
-
* await app.cli.deploy({ webBuild: () => web.cli.build() });
|
|
295
|
-
* await app.cli.deploy({ ci: true, webBuild: () => web.cli.build() });
|
|
301
|
+
* await app.cli.deploy({ stage: "production", webBuild: () => web.cli.build() }); // guided
|
|
302
|
+
* await app.cli.deploy({ ci: true, webBuild: () => web.cli.build() }); // CI
|
|
296
303
|
* ```
|
|
297
304
|
*/
|
|
298
305
|
deploy(opts?: {
|
|
299
306
|
ci?: boolean;
|
|
307
|
+
stage?: string;
|
|
300
308
|
webBuild?: WebBuild;
|
|
301
309
|
}): Promise<void>;
|
|
302
310
|
/**
|
|
@@ -267,17 +267,21 @@ type Api = {
|
|
|
267
267
|
* when omitted. A failure renders a branded `✗` line and sets a non-zero exit code rather than
|
|
268
268
|
* throwing a raw stack trace.
|
|
269
269
|
*
|
|
270
|
-
* @param opts - Optional port and web build hook.
|
|
270
|
+
* @param opts - Optional port, stage, and web build hook.
|
|
271
271
|
* @param opts.port - Local dev port to bind. Defaults to 8787 when omitted.
|
|
272
|
+
* @param opts.stage - Stage for the generated wrangler config's resource names. Falls back to the
|
|
273
|
+
* `--stage` CLI flag, then the app's configured stage. Pass it explicitly from a script for a
|
|
274
|
+
* self-documenting `dev({ stage })` instead of relying on the hidden flag.
|
|
272
275
|
* @param opts.webBuild - Rebuild the web site on change (e.g. `() => webApp.cli.build()`).
|
|
273
276
|
* @returns Resolves when the dev session ends.
|
|
274
277
|
* @example
|
|
275
278
|
* ```ts
|
|
276
|
-
* await app.cli.dev({ port: 7878, webBuild: () => web.cli.build() });
|
|
279
|
+
* await app.cli.dev({ stage: "dev", port: 7878, webBuild: () => web.cli.build() });
|
|
277
280
|
* ```
|
|
278
281
|
*/
|
|
279
282
|
dev(opts?: {
|
|
280
283
|
port?: number;
|
|
284
|
+
stage?: string;
|
|
281
285
|
webBuild?: WebBuild;
|
|
282
286
|
}): Promise<void>;
|
|
283
287
|
/**
|
|
@@ -285,18 +289,22 @@ type Api = {
|
|
|
285
289
|
* `{ ci: true }` for the automated/non-interactive path (CI). A failure renders a branded `✗`
|
|
286
290
|
* line and sets a non-zero exit code rather than throwing a raw stack trace.
|
|
287
291
|
*
|
|
288
|
-
* @param opts - Optional ci flag and a web build hook.
|
|
292
|
+
* @param opts - Optional ci flag, stage, and a web build hook.
|
|
289
293
|
* @param opts.ci - Automated mode: never prompts, auto-confirms. Omit/false → guided on a TTY.
|
|
294
|
+
* @param opts.stage - Stage for the generated wrangler config's resource names (e.g. "production",
|
|
295
|
+
* "staging"). Falls back to the `--stage` CLI flag, then the app's configured stage. Pass it
|
|
296
|
+
* explicitly from a script for a self-documenting `deploy({ stage })` instead of the hidden flag.
|
|
290
297
|
* @param opts.webBuild - Build the web site first (e.g. `() => webApp.cli.build()`), before deploy.
|
|
291
298
|
* @returns Resolves once the deploy completes (or after a failure is rendered).
|
|
292
299
|
* @example
|
|
293
300
|
* ```ts
|
|
294
|
-
* await app.cli.deploy({ webBuild: () => web.cli.build() });
|
|
295
|
-
* await app.cli.deploy({ ci: true, webBuild: () => web.cli.build() });
|
|
301
|
+
* await app.cli.deploy({ stage: "production", webBuild: () => web.cli.build() }); // guided
|
|
302
|
+
* await app.cli.deploy({ ci: true, webBuild: () => web.cli.build() }); // CI
|
|
296
303
|
* ```
|
|
297
304
|
*/
|
|
298
305
|
deploy(opts?: {
|
|
299
306
|
ci?: boolean;
|
|
307
|
+
stage?: string;
|
|
300
308
|
webBuild?: WebBuild;
|
|
301
309
|
}): Promise<void>;
|
|
302
310
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_cli = require("./cli-
|
|
2
|
+
const require_cli = require("./cli-DQcpvh2s.cjs");
|
|
3
3
|
let _moku_labs_common = require("@moku-labs/common");
|
|
4
4
|
//#region src/env-provider.ts
|
|
5
5
|
/**
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as WorkerConfig, c as WorkerPluginCtx, i as ResourceManifest, n as cliPlugin, o as WorkerEnv, r as ExternalManifest, s as WorkerEvents, t as deployPlugin } from "./index-
|
|
1
|
+
import { a as WorkerConfig, c as WorkerPluginCtx, i as ResourceManifest, n as cliPlugin, o as WorkerEnv, r as ExternalManifest, s as WorkerEvents, t as deployPlugin } from "./index-DCweBI9s.cjs";
|
|
2
2
|
import { envPlugin, logPlugin } from "@moku-labs/common";
|
|
3
3
|
import { PluginCtx, PluginCtx as PluginCtx$1, PluginInstance } from "@moku-labs/core";
|
|
4
4
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as WorkerConfig, c as WorkerPluginCtx, i as ResourceManifest, n as cliPlugin, o as WorkerEnv, r as ExternalManifest, s as WorkerEvents, t as deployPlugin } from "./index-
|
|
1
|
+
import { a as WorkerConfig, c as WorkerPluginCtx, i as ResourceManifest, n as cliPlugin, o as WorkerEnv, r as ExternalManifest, s as WorkerEvents, t as deployPlugin } from "./index-DCweBI9s.mjs";
|
|
2
2
|
import { envPlugin, logPlugin } from "@moku-labs/common";
|
|
3
3
|
import { PluginCtx, PluginCtx as PluginCtx$1, PluginInstance } from "@moku-labs/core";
|
|
4
4
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as kvPlugin, c as d1Plugin, d as createCore, f as createPlugin$1, i as queuesPlugin, l as bindingsPlugin, n as deployPlugin, o as durableObjectsPlugin, p as stagePlugin, r as storagePlugin, s as defineDurableObject, t as cliPlugin, u as coreConfig } from "./cli-
|
|
1
|
+
import { a as kvPlugin, c as d1Plugin, d as createCore, f as createPlugin$1, i as queuesPlugin, l as bindingsPlugin, n as deployPlugin, o as durableObjectsPlugin, p as stagePlugin, r as storagePlugin, s as defineDurableObject, t as cliPlugin, u as coreConfig } from "./cli-MICK1cvv.mjs";
|
|
2
2
|
import { envPlugin, logPlugin } from "@moku-labs/common";
|
|
3
3
|
//#region src/env-provider.ts
|
|
4
4
|
/**
|
package/package.json
CHANGED