@moku-labs/worker 0.7.2 → 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.
@@ -2208,6 +2208,57 @@ const renderProvisionResult = (ui, result) => {
2208
2208
  }
2209
2209
  }
2210
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
+ };
2211
2262
  //#endregion
2212
2263
  //#region src/plugins/deploy/naming.ts
2213
2264
  /**
@@ -3088,29 +3139,31 @@ const guidedUpload = async (ctx, manifest, deps) => {
3088
3139
  };
3089
3140
  /**
3090
3141
  * The final deploy step: confirm the target (guided only), run `wrangler deploy` with interactive
3091
- * retry, then emit deploy:complete. Resolves false when the target gate or a deploy retry is declined.
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).
3092
3144
  *
3093
3145
  * @param ctx - The deploy plugin context.
3094
3146
  * @param manifest - The assembled (or caller-supplied) deploy manifest.
3095
3147
  * @param stage - The resolved deploy stage (for the confirm prompt).
3096
3148
  * @param deps - Interactivity + the confirm prompt.
3097
- * @returns True once deployed; false when the user declined the gate or a retry (abort).
3149
+ * @returns The deployed URL once live; undefined when the user declined the gate or a retry (abort).
3098
3150
  * @example
3099
3151
  * ```ts
3100
- * if (!(await guidedDeployStep(ctx, manifest, stage, deps))) return emitAborted(ctx);
3152
+ * const url = await guidedDeployStep(ctx, manifest, stage, deps);
3153
+ * if (url === undefined) return emitAborted(ctx);
3101
3154
  * ```
3102
3155
  */
3103
3156
  const guidedDeployStep = async (ctx, manifest, stage, deps) => {
3104
- if (!await deps.confirm(`Deploy "${manifest.name}" to ${stage}?`)) return false;
3157
+ if (!await deps.confirm(`Deploy "${manifest.name}" to ${stage}?`)) return void 0;
3105
3158
  ctx.emit("deploy:phase", { phase: "deploy" });
3106
3159
  const url = await guidedStep(() => runWrangler([
3107
3160
  "deploy",
3108
3161
  "--config",
3109
3162
  ctx.config.configFile
3110
3163
  ]), HINTS.deploy, deps);
3111
- if (url === ABORTED) return false;
3164
+ if (url === ABORTED) return void 0;
3112
3165
  ctx.emit("deploy:complete", { url });
3113
- return true;
3166
+ return url;
3114
3167
  };
3115
3168
  /**
3116
3169
  * Create the deploy api. Assembles the manifest from each resource plugin's own deployManifest(),
@@ -3158,6 +3211,7 @@ const createDeployApi = (ctx) => ({
3158
3211
  interactive,
3159
3212
  confirm: interactive ? (0, _moku_labs_common_cli.createBrandPrompts)().confirm : async (_question) => true
3160
3213
  };
3214
+ const startedAt = Date.now();
3161
3215
  ctx.emit("deploy:phase", { phase: "auth" });
3162
3216
  if (!await guidedAuth(ctx, deps)) return emitAborted(ctx);
3163
3217
  if (!await guidedWebBuild(ctx, opts?.webBuild ?? ctx.config.webBuild, deps)) return emitAborted(ctx);
@@ -3169,7 +3223,16 @@ const createDeployApi = (ctx) => ({
3169
3223
  ctx.emit("deploy:phase", { phase: "wrangler-config" });
3170
3224
  await writeWranglerConfig(ctx.config.configFile, manifest, provisioned.ids, wranglerExtra(ctx.config));
3171
3225
  if (!await guidedUpload(ctx, manifest, deps)) return emitAborted(ctx);
3172
- if (!await guidedDeployStep(ctx, manifest, stage, deps)) return emitAborted(ctx);
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
+ });
3173
3236
  },
3174
3237
  /**
3175
3238
  * Start a long-lived local dev session: cold-build the Moku site, spawn `wrangler dev
@@ -3654,7 +3717,7 @@ const SPINNER_CLEAR = `\r${" ".repeat(72)}\r`;
3654
3717
  * const hooks = createCliHooks(ctx);
3655
3718
  * hooks["deploy:phase"]({ phase: "detect" }); // logs "detect" → renders " › detect"
3656
3719
  * hooks["dev:phase"]({ phase: "serve", detail: "http://localhost:8787" }); // "serve · …"
3657
- * hooks["deploy:complete"]({ url: "https://x.workers.dev" }); // "deployed https://x.workers.dev"
3720
+ * hooks["deploy:complete"](); // settles the deploy spinner; the "Deployed" panel renders separately
3658
3721
  * ```
3659
3722
  */
3660
3723
  const createCliHooks = (ctx) => {
@@ -3741,17 +3804,16 @@ const createCliHooks = (ctx) => {
3741
3804
  ctx.log.warn(p.message);
3742
3805
  },
3743
3806
  /**
3744
- * Log the terminal success line with the deployed URL.
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`.
3745
3809
  *
3746
- * @param p - The deploy:complete event payload.
3747
3810
  * @example
3748
3811
  * ```ts
3749
- * handler({ url: "https://my-worker.workers.dev" }); // "deployed https://my-worker.workers.dev"
3812
+ * handler(); // clears the `deploy` spinner; the "Deployed" panel follows from the deploy plugin
3750
3813
  * ```
3751
3814
  */
3752
- "deploy:complete"(p) {
3815
+ "deploy:complete"() {
3753
3816
  stopSpinner();
3754
- ctx.log.info(`deployed → ${p.url}`);
3755
3817
  }
3756
3818
  };
3757
3819
  };
@@ -2185,6 +2185,57 @@ const renderProvisionResult = (ui, result) => {
2185
2185
  }
2186
2186
  }
2187
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
+ };
2188
2239
  //#endregion
2189
2240
  //#region src/plugins/deploy/naming.ts
2190
2241
  /**
@@ -3065,29 +3116,31 @@ const guidedUpload = async (ctx, manifest, deps) => {
3065
3116
  };
3066
3117
  /**
3067
3118
  * The final deploy step: confirm the target (guided only), run `wrangler deploy` with interactive
3068
- * retry, then emit deploy:complete. Resolves false when the target gate or a deploy retry is declined.
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).
3069
3121
  *
3070
3122
  * @param ctx - The deploy plugin context.
3071
3123
  * @param manifest - The assembled (or caller-supplied) deploy manifest.
3072
3124
  * @param stage - The resolved deploy stage (for the confirm prompt).
3073
3125
  * @param deps - Interactivity + the confirm prompt.
3074
- * @returns True once deployed; false when the user declined the gate or a retry (abort).
3126
+ * @returns The deployed URL once live; undefined when the user declined the gate or a retry (abort).
3075
3127
  * @example
3076
3128
  * ```ts
3077
- * if (!(await guidedDeployStep(ctx, manifest, stage, deps))) return emitAborted(ctx);
3129
+ * const url = await guidedDeployStep(ctx, manifest, stage, deps);
3130
+ * if (url === undefined) return emitAborted(ctx);
3078
3131
  * ```
3079
3132
  */
3080
3133
  const guidedDeployStep = async (ctx, manifest, stage, deps) => {
3081
- if (!await deps.confirm(`Deploy "${manifest.name}" to ${stage}?`)) return false;
3134
+ if (!await deps.confirm(`Deploy "${manifest.name}" to ${stage}?`)) return void 0;
3082
3135
  ctx.emit("deploy:phase", { phase: "deploy" });
3083
3136
  const url = await guidedStep(() => runWrangler([
3084
3137
  "deploy",
3085
3138
  "--config",
3086
3139
  ctx.config.configFile
3087
3140
  ]), HINTS.deploy, deps);
3088
- if (url === ABORTED) return false;
3141
+ if (url === ABORTED) return void 0;
3089
3142
  ctx.emit("deploy:complete", { url });
3090
- return true;
3143
+ return url;
3091
3144
  };
3092
3145
  /**
3093
3146
  * Create the deploy api. Assembles the manifest from each resource plugin's own deployManifest(),
@@ -3135,6 +3188,7 @@ const createDeployApi = (ctx) => ({
3135
3188
  interactive,
3136
3189
  confirm: interactive ? createBrandPrompts().confirm : async (_question) => true
3137
3190
  };
3191
+ const startedAt = Date.now();
3138
3192
  ctx.emit("deploy:phase", { phase: "auth" });
3139
3193
  if (!await guidedAuth(ctx, deps)) return emitAborted(ctx);
3140
3194
  if (!await guidedWebBuild(ctx, opts?.webBuild ?? ctx.config.webBuild, deps)) return emitAborted(ctx);
@@ -3146,7 +3200,16 @@ const createDeployApi = (ctx) => ({
3146
3200
  ctx.emit("deploy:phase", { phase: "wrangler-config" });
3147
3201
  await writeWranglerConfig(ctx.config.configFile, manifest, provisioned.ids, wranglerExtra(ctx.config));
3148
3202
  if (!await guidedUpload(ctx, manifest, deps)) return emitAborted(ctx);
3149
- if (!await guidedDeployStep(ctx, manifest, stage, deps)) return emitAborted(ctx);
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
+ });
3150
3213
  },
3151
3214
  /**
3152
3215
  * Start a long-lived local dev session: cold-build the Moku site, spawn `wrangler dev
@@ -3631,7 +3694,7 @@ const SPINNER_CLEAR = `\r${" ".repeat(72)}\r`;
3631
3694
  * const hooks = createCliHooks(ctx);
3632
3695
  * hooks["deploy:phase"]({ phase: "detect" }); // logs "detect" → renders " › detect"
3633
3696
  * hooks["dev:phase"]({ phase: "serve", detail: "http://localhost:8787" }); // "serve · …"
3634
- * hooks["deploy:complete"]({ url: "https://x.workers.dev" }); // "deployed https://x.workers.dev"
3697
+ * hooks["deploy:complete"](); // settles the deploy spinner; the "Deployed" panel renders separately
3635
3698
  * ```
3636
3699
  */
3637
3700
  const createCliHooks = (ctx) => {
@@ -3718,17 +3781,16 @@ const createCliHooks = (ctx) => {
3718
3781
  ctx.log.warn(p.message);
3719
3782
  },
3720
3783
  /**
3721
- * Log the terminal success line with the deployed URL.
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`.
3722
3786
  *
3723
- * @param p - The deploy:complete event payload.
3724
3787
  * @example
3725
3788
  * ```ts
3726
- * handler({ url: "https://my-worker.workers.dev" }); // "deployed https://my-worker.workers.dev"
3789
+ * handler(); // clears the `deploy` spinner; the "Deployed" panel follows from the deploy plugin
3727
3790
  * ```
3728
3791
  */
3729
- "deploy:complete"(p) {
3792
+ "deploy:complete"() {
3730
3793
  stopSpinner();
3731
- ctx.log.info(`deployed → ${p.url}`);
3732
3794
  }
3733
3795
  };
3734
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-BPnG_JGR.cjs");
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.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { n as deployPlugin, t as cliPlugin } from "./cli-D8UmSqh4.mjs";
1
+ import { n as deployPlugin, t as cliPlugin } from "./cli-MICK1cvv.mjs";
2
2
  export { cliPlugin, deployPlugin };
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_cli = require("./cli-BPnG_JGR.cjs");
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.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-D8UmSqh4.mjs";
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moku-labs/worker",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "Cloudflare Worker framework for Moku — Durable Objects, Queues, R2, D1, and KV plugins that compose with Moku Web.",
5
5
  "repository": {
6
6
  "type": "git",