devflare 1.0.0-next.51 → 1.0.0-next.52

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.
@@ -712,13 +712,15 @@ const PRODUCTION_HELP_PAGES = [
712
712
  usage: [
713
713
  "devflare productions [--config <path>] [--env <name>] [--account <id>] [--worker <name>]",
714
714
  "devflare productions versions [--config <path>] [--env <name>] [--account <id>] [--worker <name>]",
715
+ "devflare productions deployments [--config <path>] [--env <name>] [--account <id>] [--worker <name>]",
715
716
  "devflare productions rollback [--config <path>] [--account <id>] [--worker <name>] [--version-id <id>] [--message <text>] [--apply]",
716
717
  "devflare productions delete [--config <path>] [--account <id>] [--worker <name>] [--apply]"
717
718
  ],
718
- description: ["The default view inspects live Cloudflare production deployment state for locally configured Workers, or for one explicitly selected Worker.", "Other subcommands list recent production versions or mutate a single Worker by rolling back or deleting its live production script."],
719
+ description: ["The default view inspects live Cloudflare production deployment state for locally configured Workers, or for one explicitly selected Worker.", "Other subcommands list recent production versions, show the full deployment history, or mutate a single Worker by rolling back or deleting its live production script."],
719
720
  subcommands: [
720
721
  entry("list", "List live production Workers and their active deployments (default)"),
721
722
  entry("versions", "Show recent stored production versions and which one is currently active"),
723
+ entry("deployments", "Show the full chronological production deployment history with traffic splits"),
722
724
  entry("rollback", "Roll a Worker back to the previous or specified production version"),
723
725
  entry("delete", "Delete a live production Worker script")
724
726
  ],
@@ -757,6 +759,12 @@ const PRODUCTION_HELP_PAGES = [
757
759
  entry("--account <id>", "Use a specific Cloudflare account"),
758
760
  entry("--worker <name>", "Target a specific Worker instead of the locally configured set")
759
761
  ], [entry("devflare productions versions", "Show recent stored production versions for the resolved Workers"), entry("devflare productions versions --worker my-worker", "Show recent stored production versions for `my-worker`")]),
762
+ createProductionsSubcommandPage("deployments", "Show the full chronological production deployment history", ["devflare productions deployments [--config <path>] [--env <name>] [--account <id>] [--worker <name>]"], ["Lists every production deployment for the selected Worker set in reverse-chronological order, including each deployment id, strategy, per-version traffic split, source, who triggered it, and the deployment message."], [
763
+ entry("--config <path>", "Use a specific devflare config file"),
764
+ entry("--env <name>", "Resolve `config.env[name]` while discovering related production Workers (defaults to `production`)"),
765
+ entry("--account <id>", "Use a specific Cloudflare account"),
766
+ entry("--worker <name>", "Target a specific Worker instead of the locally configured set")
767
+ ], [entry("devflare productions deployments", "Show the full production deployment history for the resolved Workers"), entry("devflare productions deployments --worker my-worker", "Show the full production deployment history for `my-worker`")], ["This view is read-only and is backed by live Cloudflare deployment history."]),
760
768
  createProductionsSubcommandPage("rollback", "Roll a Worker back to the previous or specified production version", ["devflare productions rollback [--config <path>] [--account <id>] [--worker <name>] [--version-id <id>] [--message <text>] [--apply]"], ["Uses Wrangler rollback to create a fresh production deployment that points at the previous or explicitly selected version."], [
761
769
  entry("--config <path>", "Use a specific devflare config file"),
762
770
  entry("--account <id>", "Use a specific Cloudflare account"),
@@ -1132,7 +1140,7 @@ async function runPreviews(parsed, logger, options) {
1132
1140
  return runPreviewsCommand(parsed, logger, options);
1133
1141
  }
1134
1142
  async function runProductions(parsed, logger, options) {
1135
- const { runProductionsCommand } = await import("./productions-DK7xwbEs.js");
1143
+ const { runProductionsCommand } = await import("./productions-DXQ045cq.js");
1136
1144
  return runProductionsCommand(parsed, logger, options);
1137
1145
  }
1138
1146
  async function runWorker(parsed, logger, options) {
@@ -10,6 +10,7 @@ const CLI_API_OPTIONS = { timeout: 1e4 };
10
10
  const PRODUCTION_SUBCOMMANDS = [
11
11
  "list",
12
12
  "versions",
13
+ "deployments",
13
14
  "rollback",
14
15
  "delete"
15
16
  ];
@@ -23,6 +24,10 @@ function shortenVersionId(versionId, length = 12) {
23
24
  function selectDeploymentVersionId(deployment) {
24
25
  return deployment.versions.find((version) => version.percentage === 100)?.versionId ?? deployment.versions[0]?.versionId;
25
26
  }
27
+ function formatDeploymentSplit(deployment) {
28
+ if (deployment.versions.length === 0) return "N/A";
29
+ return deployment.versions.map((version) => `${version.percentage}% → ${shortenVersionId(version.versionId, 8)}`).join(", ");
30
+ }
26
31
  function getWorkerVersionTimestamp(version) {
27
32
  return version.metadata.modifiedOn ?? version.metadata.createdOn;
28
33
  }
@@ -282,7 +287,7 @@ function showProductionOverview(logger, context, rows, theme) {
282
287
  titleAccent: "green"
283
288
  });
284
289
  logLine(logger);
285
- logLine(logger, dim("Use `devflare productions versions` for recent production versions, or `rollback` / `delete` to mutate one Worker.", theme));
290
+ logLine(logger, dim("Use `devflare productions versions` for recent production versions, `deployments` for the full deployment history, or `rollback` / `delete` to mutate one Worker.", theme));
286
291
  logLine(logger);
287
292
  }
288
293
  function showWorkerVersions(logger, overviews, theme) {
@@ -309,6 +314,82 @@ function showWorkerVersions(logger, overviews, theme) {
309
314
  }
310
315
  logLine(logger);
311
316
  }
317
+ function buildDeploymentColumns(theme) {
318
+ return [
319
+ {
320
+ label: "Deployed",
321
+ width: 19,
322
+ value: (row) => whiteDim(formatRecordDate(row.createdOn), theme)
323
+ },
324
+ {
325
+ label: "Deployment",
326
+ width: 12,
327
+ value: (row) => shortenVersionId(row.deploymentId, 11)
328
+ },
329
+ {
330
+ label: "Strategy",
331
+ width: 12,
332
+ value: (row) => row.strategy || dim("N/A", theme)
333
+ },
334
+ {
335
+ label: "Traffic split",
336
+ width: 28,
337
+ value: (row) => row.split
338
+ },
339
+ {
340
+ label: "Source",
341
+ width: 12,
342
+ value: (row) => row.source || dim("N/A", theme)
343
+ },
344
+ {
345
+ label: "Triggered by",
346
+ width: 18,
347
+ value: (row) => row.triggeredBy ? whiteDim(row.triggeredBy, theme) : dim("N/A", theme)
348
+ },
349
+ {
350
+ label: "Message",
351
+ value: (row) => row.message ? row.message : dim("N/A", theme)
352
+ }
353
+ ];
354
+ }
355
+ async function loadWorkerDeploymentHistory(accountId, workerName, apiOptions) {
356
+ return {
357
+ workerName,
358
+ rows: [...await account.workerDeployments(accountId, workerName, apiOptions)].sort((left, right) => right.createdOn.getTime() - left.createdOn.getTime()).map((deployment) => ({
359
+ createdOn: deployment.createdOn,
360
+ deploymentId: deployment.id,
361
+ strategy: deployment.strategy,
362
+ split: formatDeploymentSplit(deployment),
363
+ source: deployment.source,
364
+ message: deployment.message,
365
+ triggeredBy: deployment.triggeredBy ?? deployment.authorEmail
366
+ }))
367
+ };
368
+ }
369
+ function showWorkerDeployments(logger, overviews, theme) {
370
+ logLine(logger);
371
+ if (overviews.length === 0) {
372
+ logLine(logger, dim("No production deployments were found for the current selection.", theme));
373
+ logLine(logger);
374
+ return;
375
+ }
376
+ for (const [index, overview] of overviews.entries()) {
377
+ if (index > 0) logLine(logger);
378
+ logLine(logger, `${bold("worker", theme)} ${green(overview.workerName, theme)}`);
379
+ if (overview.rows.length === 0) {
380
+ logLine(logger, dim("No production deployments were found for this Worker.", theme));
381
+ continue;
382
+ }
383
+ logTable(logger, {
384
+ title: "Deployments",
385
+ rows: overview.rows,
386
+ columns: buildDeploymentColumns(theme),
387
+ theme,
388
+ titleAccent: "cyan"
389
+ });
390
+ }
391
+ logLine(logger);
392
+ }
312
393
  async function runRollback(context, parsed, options, logger, theme) {
313
394
  if (!context.workerName) {
314
395
  logger.error("A worker name is required for production rollback.");
@@ -357,6 +438,9 @@ async function runDelete(context, parsed, logger) {
357
438
  logger.warn("Devflare deleted the Worker script only. Review any shared account resources separately before cleaning them up.");
358
439
  return { exitCode: 0 };
359
440
  }
441
+ function resolveSelectedWorkerNames(context, selectedFamilies) {
442
+ return Array.from(new Set(context.workerName ? [context.workerName] : selectedFamilies.map((family) => family.baseName))).sort((left, right) => left.localeCompare(right));
443
+ }
360
444
  async function runProductionsCommand(parsed, logger, options) {
361
445
  if (!await account.isAuthenticated()) {
362
446
  logger.error("Not authenticated with Cloudflare");
@@ -381,7 +465,7 @@ async function runProductionsCommand(parsed, logger, options) {
381
465
  }] : [];
382
466
  switch (subcommand) {
383
467
  case "versions": {
384
- const workerNames = Array.from(new Set(context.workerName ? [context.workerName] : selectedFamilies.map((family) => family.baseName))).sort((left, right) => left.localeCompare(right));
468
+ const workerNames = resolveSelectedWorkerNames(context, selectedFamilies);
385
469
  if (workerNames.length === 0) {
386
470
  logger.error("No production Workers could be resolved. Use --worker or run inside a configured package.");
387
471
  return { exitCode: 1 };
@@ -389,6 +473,15 @@ async function runProductionsCommand(parsed, logger, options) {
389
473
  showWorkerVersions(logger, await Promise.all(workerNames.map((workerName) => loadWorkerVersionOverview(context.accountId, workerName, CLI_API_OPTIONS))), theme);
390
474
  return { exitCode: 0 };
391
475
  }
476
+ case "deployments": {
477
+ const workerNames = resolveSelectedWorkerNames(context, selectedFamilies);
478
+ if (workerNames.length === 0) {
479
+ logger.error("No production Workers could be resolved. Use --worker or run inside a configured package.");
480
+ return { exitCode: 1 };
481
+ }
482
+ showWorkerDeployments(logger, await Promise.all(workerNames.map((workerName) => loadWorkerDeploymentHistory(context.accountId, workerName, CLI_API_OPTIONS))), theme);
483
+ return { exitCode: 0 };
484
+ }
392
485
  case "rollback": return runRollback(context, parsed, options, logger, theme);
393
486
  case "delete": return runDelete(context, parsed, logger);
394
487
  default:
@@ -1 +1 @@
1
- {"version":3,"file":"productions.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/productions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAgB9C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAipBjE,wBAAsB,qBAAqB,CAC1C,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,UAAU,GACjB,OAAO,CAAC,SAAS,CAAC,CAyFpB"}
1
+ {"version":3,"file":"productions.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/productions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAgB9C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAwxBjE,wBAAsB,qBAAqB,CAC1C,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,UAAU,GACjB,OAAO,CAAC,SAAS,CAAC,CAoGpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"productions.d.ts","sourceRoot":"","sources":["../../../../src/cli/help-pages/pages/productions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,eAAO,MAAM,qBAAqB,EAAE,QAAQ,EA0L3C,CAAA"}
1
+ {"version":3,"file":"productions.d.ts","sourceRoot":"","sources":["../../../../src/cli/help-pages/pages/productions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,eAAO,MAAM,qBAAqB,EAAE,QAAQ,EA6N3C,CAAA"}
package/dist/cli/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { n as runCli, t as parseArgs } from "../_chunks/cli-CU7wSG1-.js";
1
+ import { n as runCli, t as parseArgs } from "../_chunks/cli-CqIDn-Hy.js";
2
2
  export { parseArgs, runCli };
package/dist/index.js CHANGED
@@ -4,6 +4,6 @@ import { a as ConfigResourceResolutionError, d as configSchema, n as ConfigValid
4
4
  import { n as compileConfig, s as stringifyConfig } from "./_chunks/compiler-BtLp9T9N.js";
5
5
  import { t as workerName } from "./_chunks/workerName-CFJsLZA-.js";
6
6
  import { n as getDurableObjectOptions, t as durableObject } from "./_chunks/decorators-QmV57ixr.js";
7
- import { n as runCli, t as parseArgs } from "./_chunks/cli-CU7wSG1-.js";
7
+ import { n as runCli, t as parseArgs } from "./_chunks/cli-CqIDn-Hy.js";
8
8
  import { i as vars, r as env } from "./_chunks/env-S0_nMVz1.js";
9
9
  export { ConfigNotFoundError, ConfigResourceResolutionError, ConfigValidationError, compileConfig, configSchema, defineConfig as default, defineConfig, durableObject, env, getDurableObjectOptions, loadConfig, loadResolvedConfig, parseArgs, preview, ref, runCli, stringifyConfig, vars, workerName };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devflare",
3
- "version": "1.0.0-next.51",
3
+ "version": "1.0.0-next.52",
4
4
  "description": "Devflare is a developer-first toolkit for Cloudflare Workers that sits on top of Miniflare and Wrangler-compatible config",
5
5
  "repository": {
6
6
  "type": "git",