devflare 1.0.0-next.47 → 1.0.0-next.49

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.
Files changed (61) hide show
  1. package/README.md +1 -0
  2. package/dist/_chunks/{account-Cdo_cRNv.js → account-BI3WZMDy.js} +1 -1
  3. package/dist/_chunks/{build-artifacts-CaSTDXLE.js → build-artifacts-DU5V0J0Z.js} +3 -3
  4. package/dist/_chunks/{build-B6vCBDdQ.js → build-e0KR38-4.js} +1 -1
  5. package/dist/_chunks/{cli-Ba6JBLOz.js → cli-DuUz10Mn.js} +49 -14
  6. package/dist/_chunks/{command-utils-C48hJMln.js → command-utils-DA0Qx9_K.js} +1 -1
  7. package/dist/_chunks/{compiler-Dc97FkBg.js → compiler-Zw16C9Pi.js} +1 -1
  8. package/dist/_chunks/{config-DQ_uWv37.js → config-Brju62xy.js} +2 -2
  9. package/dist/_chunks/{config-path-ePwIvHNX.js → config-path-DaL1ylZ_.js} +1 -1
  10. package/dist/_chunks/{deploy-0w_38g8h.js → deploy-B-Kku1Vk.js} +127 -10
  11. package/dist/_chunks/{dev-DaREvpZf.js → dev-D4e_RRZn.js} +3 -3
  12. package/dist/_chunks/{doctor-lFlh-olK.js → doctor-jm_K4dxL.js} +2 -2
  13. package/dist/_chunks/{family-Dfb9VR9g.js → family-_9-mGSfO.js} +1 -1
  14. package/dist/_chunks/{loader-RZhqzsRJ.js → loader-Cr0_OWPy.js} +137 -2
  15. package/dist/_chunks/{login-DnyfffOC.js → login-FjTAAQbi.js} +1 -1
  16. package/dist/_chunks/{preview-resources-xziKCynb.js → preview-resources-CGMBjsYB.js} +1 -1
  17. package/dist/_chunks/{previews-wI-pW6HM.js → previews-C7hs9-BT.js} +6 -6
  18. package/dist/_chunks/{productions-BpROdhLN.js → productions-T9Als4fE.js} +3 -3
  19. package/dist/_chunks/{routes-C4S8x2HU.js → routes-BFYCqHb-.js} +1 -1
  20. package/dist/_chunks/{runtime-FvXvfuZ2.js → runtime-DL-Nz3k8.js} +1 -1
  21. package/dist/_chunks/tail-IY-ijYmv.js +239 -0
  22. package/dist/_chunks/{types-Zn9vyUGA.js → types-DoKsMYfm.js} +2 -2
  23. package/dist/_chunks/{vite-D5dfVb6G.js → vite-CGtVNf5E.js} +35 -3
  24. package/dist/_chunks/{worker-rL5udcl9.js → worker-BEZI4od1.js} +3 -3
  25. package/dist/browser.d.ts +10 -2
  26. package/dist/browser.d.ts.map +1 -1
  27. package/dist/cli/commands/deploy.d.ts.map +1 -1
  28. package/dist/cli/commands/tail.d.ts +44 -0
  29. package/dist/cli/commands/tail.d.ts.map +1 -0
  30. package/dist/cli/gradual-deploy.d.ts +49 -0
  31. package/dist/cli/gradual-deploy.d.ts.map +1 -0
  32. package/dist/cli/help-pages/pages/core.d.ts +1 -1
  33. package/dist/cli/help-pages/pages/core.d.ts.map +1 -1
  34. package/dist/cli/help-pages/pages/misc.d.ts.map +1 -1
  35. package/dist/cli/help-pages/shared.d.ts +1 -1
  36. package/dist/cli/help-pages/shared.d.ts.map +1 -1
  37. package/dist/cli/index.d.ts.map +1 -1
  38. package/dist/cli/index.js +1 -1
  39. package/dist/config/cron.d.ts +19 -0
  40. package/dist/config/cron.d.ts.map +1 -0
  41. package/dist/config/schema-env.d.ts +10 -2
  42. package/dist/config/schema-env.d.ts.map +1 -1
  43. package/dist/config/schema-runtime.d.ts +9 -1
  44. package/dist/config/schema-runtime.d.ts.map +1 -1
  45. package/dist/config/schema.d.ts +15 -3
  46. package/dist/config/schema.d.ts.map +1 -1
  47. package/dist/index.js +3 -3
  48. package/dist/runtime/index.d.ts +1 -1
  49. package/dist/runtime/index.d.ts.map +1 -1
  50. package/dist/runtime/index.js +2 -2
  51. package/dist/runtime/middleware.d.ts +10 -0
  52. package/dist/runtime/middleware.d.ts.map +1 -1
  53. package/dist/sveltekit/index.js +1 -1
  54. package/dist/test/index.js +4 -3
  55. package/dist/test/scheduled.d.ts.map +1 -1
  56. package/dist/vite/index.js +1 -1
  57. package/dist/worker-entry/composed-worker.d.ts.map +1 -1
  58. package/dist/worker-entry/validate-fetch-style.d.ts +12 -0
  59. package/dist/worker-entry/validate-fetch-style.d.ts.map +1 -0
  60. package/package.json +1 -1
  61. /package/dist/_chunks/{token-kguIDmej.js → token-Dmi0KXyX.js} +0 -0
package/README.md CHANGED
@@ -188,6 +188,7 @@ for examples with file paths.
188
188
  | `devflare productions` | inspect or manage production Worker versions |
189
189
  | `devflare remote` | manage remote test mode |
190
190
  | `devflare secrets` | manage local Secrets Store values |
191
+ | `devflare tail` | stream live logs from a deployed Worker |
191
192
  | `devflare tokens` | create and manage Devflare-scoped API tokens |
192
193
  | `devflare types` | generate `env.d.ts` |
193
194
  | `devflare version` | print the installed version |
@@ -3,7 +3,7 @@ import { a as setGlobalDefaultAccountId, i as getWorkspaceAccountId, o as setWor
3
3
  import { t as account } from "./cloudflare-BaloqI3H.js";
4
4
  import { a as DIM, c as RESET, i as CYAN_BOLD, r as CYAN } from "./colors-DiK6wPJ5.js";
5
5
  import { c as formatCommand, d as green, f as logLine, g as yellow, h as whiteDim, l as formatLabelValue, n as bold, o as dim, p as logTable, r as createCliTheme } from "./ui-BUoZApvE.js";
6
- import { n as getConfiguredAccountId } from "./command-utils-C48hJMln.js";
6
+ import { n as getConfiguredAccountId } from "./command-utils-DA0Qx9_K.js";
7
7
  //#region src/cli/commands/account.ts
8
8
  const ACCOUNT_SUBCOMMANDS = [
9
9
  "info",
@@ -1,10 +1,10 @@
1
1
  import { d as resolveConfigEnvVars } from "./preview-C3Cdr8an.js";
2
- import { r as loadConfig, u as resolveConfigForEnvironment } from "./loader-RZhqzsRJ.js";
3
- import { c as writeWranglerConfig, i as isolateViteBuildOutputPaths$1, o as rebaseWranglerConfigPaths, t as compileBuildConfig } from "./compiler-Dc97FkBg.js";
2
+ import { r as loadConfig, u as resolveConfigForEnvironment } from "./loader-Cr0_OWPy.js";
3
+ import { c as writeWranglerConfig, i as isolateViteBuildOutputPaths$1, o as rebaseWranglerConfigPaths, t as compileBuildConfig } from "./compiler-Zw16C9Pi.js";
4
4
  import { f as logLine } from "./ui-BUoZApvE.js";
5
5
  import { n as getPackageVersion } from "./package-metadata-DjHBLB-z.js";
6
6
  import { t as resolvePackageSpecifier } from "./resolve-package-qizBfCIm.js";
7
- import { i as writeGeneratedViteConfig, l as prepareComposedWorkerEntrypoint, n as resolveEffectiveViteProject } from "./vite-D5dfVb6G.js";
7
+ import { i as writeGeneratedViteConfig, l as prepareComposedWorkerEntrypoint, n as resolveEffectiveViteProject } from "./vite-CGtVNf5E.js";
8
8
  import { t as bundleWorkerEntry } from "./worker-bundler-dTTnYU3n.js";
9
9
  import { t as detectViteProject } from "./vite-utils-OVLMV605.js";
10
10
  import { t as getDependencies } from "./dependencies-C2oxFjU_.js";
@@ -1,5 +1,5 @@
1
1
  import { a as cyanBold, f as logLine, o as dim, r as createCliTheme } from "./ui-BUoZApvE.js";
2
- import { t as prepareBuildArtifacts } from "./build-artifacts-CaSTDXLE.js";
2
+ import { t as prepareBuildArtifacts } from "./build-artifacts-DU5V0J0Z.js";
3
3
  //#region src/cli/commands/build.ts
4
4
  async function runBuildCommand(parsed, logger, options) {
5
5
  const theme = createCliTheme(parsed.options);
@@ -20,6 +20,7 @@ const COMMANDS = [
20
20
  "worker",
21
21
  "tokens",
22
22
  "secrets",
23
+ "tail",
23
24
  "ai",
24
25
  "remote",
25
26
  "help",
@@ -260,6 +261,7 @@ const CORE_HELP_PAGES = [
260
261
  entry("worker", "Rename and manage Worker control-plane operations"),
261
262
  entry("tokens", "Manage Devflare-managed Cloudflare API tokens"),
262
263
  entry("secrets", "Manage local Secrets Store values"),
264
+ entry("tail", "Stream live logs from a deployed Worker"),
263
265
  entry("ai", "View Workers AI pricing information"),
264
266
  entry("remote", "Manage remote test mode for paid Cloudflare features"),
265
267
  entry("help", "Show command overview or a command-specific help page"),
@@ -346,6 +348,7 @@ const CORE_HELP_PAGES = [
346
348
  "devflare deploy --production [--config <path>] [--build <path>] [--message <text>] [--tag <text>] [--debug]",
347
349
  "devflare deploy --preview <name> [--config <path>] [--build <path>] [--message <text>] [--tag <text>]",
348
350
  "devflare deploy --preview [--config <path>] [--build <path>] [--branch-name <branch>] [--message <text>] [--tag <text>]",
351
+ "devflare deploy --prod --percentage <n> [--version <current-version-id>] [--config <path>] [--message <text>]",
349
352
  "devflare deploy --prod --dry-run [--config <path>]",
350
353
  "devflare deploy --preview <name> --dry-run [--config <path>]",
351
354
  "devflare deploy --preview --dry-run [--config <path>]"
@@ -367,6 +370,8 @@ const CORE_HELP_PAGES = [
367
370
  entry("--branch-name <branch>", "Provide explicit branch metadata for preview-aware naming when your workflow needs it"),
368
371
  entry("--message <text>", "Attach an explicit Wrangler deployment/version message"),
369
372
  entry("--tag <text>", "Attach an explicit Wrangler version tag"),
373
+ entry("--percentage <n>", "Production gradual rollout: upload a new version and route n% (0-100) of traffic to it via `wrangler versions deploy`"),
374
+ entry("--version <id>", "With --percentage, the currently-live version id that keeps the remaining traffic (otherwise Wrangler distributes it)"),
370
375
  entry("--debug", "Print stack traces when deployment orchestration fails")
371
376
  ],
372
377
  examples: [
@@ -376,10 +381,12 @@ const CORE_HELP_PAGES = [
376
381
  entry("devflare deploy --preview next", "Deploy the named `next` preview scope and provision preview-scoped resources automatically"),
377
382
  entry("devflare deploy --preview pr-1", "Deploy the named `pr-1` preview scope directly"),
378
383
  entry("devflare deploy --preview --branch-name feature-branch", "Upload a same-worker preview version with explicit branch metadata"),
379
- entry("devflare deploy --preview next --dry-run", "Inspect the generated named-preview Wrangler config without deploying")
384
+ entry("devflare deploy --preview next --dry-run", "Inspect the generated named-preview Wrangler config without deploying"),
385
+ entry("devflare deploy --prod --percentage 10", "Upload a new version and route 10% of production traffic to it (canary)")
380
386
  ],
381
387
  notes: [
382
388
  "`devflare deploy` without an explicit target is rejected from the CLI so production and preview destinations stay unmistakable.",
389
+ "`--percentage <n>` performs a Cloudflare gradual deployment: Devflare runs `wrangler versions upload` (no traffic shift) and then `wrangler versions deploy <new-version-id>@<n> --yes`, routing n% of production traffic to the new version. Pass `--version <id>` to keep the remaining traffic on a specific currently-live version; otherwise Wrangler distributes the rest. To advance an existing rollout (e.g. 10% → 50% → 100%) without re-uploading, drive `wrangler versions deploy` directly. `--percentage` is production-only and rejected with `--preview`.",
383
390
  "`--prod` / `--production` clear preview-scope environment overrides such as `DEVFLARE_PREVIEW_BRANCH` so production deploys stay pointed at stable Worker names.",
384
391
  "Named preview deploys automatically provision preview-scoped resources before building and deploying.",
385
392
  "When a build artifact still contains name-based bindings, deploy resolves or provisions the concrete Cloudflare resources and rewrites the generated Wrangler config with the IDs Wrangler requires.",
@@ -408,7 +415,11 @@ const CORE_HELP_PAGES = [
408
415
  entry("devflare secrets --local --store store-123 --list", "List names in one local store"),
409
416
  entry("devflare secrets --local --store store-123 --name api-token --delete", "Delete one local secret value")
410
417
  ],
411
- notes: ["Local values are stored in `.devflare/secrets.local.json`, which is ignored by the repository template.", "Command output prints store/name references only; it does not echo secret values."]
418
+ notes: [
419
+ "Local values are stored in `.devflare/secrets.local.json`, which is ignored by the repository template.",
420
+ "Command output prints store/name references only; it does not echo secret values.",
421
+ "Runtime secrets are local-only here: set production secret values with `wrangler secret put` or the Cloudflare dashboard. Devflare never sends secret values to Cloudflare — deploy emits Secrets Store references only."
422
+ ]
412
423
  },
413
424
  {
414
425
  path: ["types"],
@@ -563,6 +574,25 @@ const MISC_HELP_PAGES = [
563
574
  ],
564
575
  notes: ["Created tokens include the selected account resource and all zones in that account so deploys can manage Worker routes and custom-domain route state.", "Cloudflare only returns token secrets once for create and roll operations, so store them immediately."]
565
576
  },
577
+ {
578
+ path: ["tail"],
579
+ summary: "Stream live logs from a deployed Worker",
580
+ usage: ["devflare tail [worker] [--worker <name>] [--format <pretty|json>] [--account <id>] [--config <path>]"],
581
+ description: ["Streams live request logs and exceptions from a Worker that is already deployed to Cloudflare, using Cloudflare’s Workers Trace (tail) API.", "This command is inherently remote: it opens a real tail session against your live Worker. There is no local emulation of deployed traffic — use `devflare dev` and `cf.tail.trigger()` for local/offline tail-handler testing."],
582
+ arguments: [entry("[worker]", "Worker name to tail (defaults to --worker, then the config `name`)")],
583
+ options: [
584
+ entry("--worker <name>", "Worker name to tail instead of the configured `name`"),
585
+ entry("--format <pretty|json>", "Output format: human-readable lines (default) or raw JSON events"),
586
+ entry("--account <id>", "Use a specific Cloudflare account instead of the resolved default"),
587
+ entry("--config <path>", "Use a specific devflare config file to resolve the Worker name/account")
588
+ ],
589
+ examples: [
590
+ entry("devflare tail", "Stream logs from the Worker named in the current config"),
591
+ entry("devflare tail my-worker", "Stream logs from an explicitly named Worker"),
592
+ entry("devflare tail --format json", "Stream raw JSON tail events for piping into other tools")
593
+ ],
594
+ notes: ["Requires Cloudflare authentication (`devflare login` or CLOUDFLARE_API_TOKEN) and a resolvable account id.", "Press Ctrl-C to stop; Devflare deletes the tail session and closes the WebSocket on exit. Cloudflare also expires idle tail sessions on its own."]
595
+ },
566
596
  {
567
597
  path: ["ai"],
568
598
  summary: "Show Workers AI pricing information",
@@ -1050,6 +1080,7 @@ async function runCli(argv, options = {}) {
1050
1080
  case "worker": return runWorker(parsed, logger, options);
1051
1081
  case "tokens": return runToken(parsed, logger, options);
1052
1082
  case "secrets": return runSecrets(parsed, logger, options);
1083
+ case "tail": return runTail(parsed, logger, options);
1053
1084
  case "ai": return runAI();
1054
1085
  case "remote": return runRemote(parsed, logger, options);
1055
1086
  default:
@@ -1062,60 +1093,64 @@ async function runInit(parsed, logger, options) {
1062
1093
  return runInitCommand(parsed, logger, options);
1063
1094
  }
1064
1095
  async function runDev(parsed, logger, options) {
1065
- const { runDevCommand } = await import("./dev-DaREvpZf.js");
1096
+ const { runDevCommand } = await import("./dev-D4e_RRZn.js");
1066
1097
  return runDevCommand(parsed, logger, options);
1067
1098
  }
1068
1099
  async function runBuild(parsed, logger, options) {
1069
- const { runBuildCommand } = await import("./build-B6vCBDdQ.js");
1100
+ const { runBuildCommand } = await import("./build-e0KR38-4.js");
1070
1101
  return runBuildCommand(parsed, logger, options);
1071
1102
  }
1072
1103
  async function runDeploy(parsed, logger, options) {
1073
- const { runDeployCommand } = await import("./deploy-0w_38g8h.js");
1104
+ const { runDeployCommand } = await import("./deploy-B-Kku1Vk.js");
1074
1105
  return runDeployCommand(parsed, logger, {
1075
1106
  ...options,
1076
1107
  requireExplicitDeployTarget: true
1077
1108
  });
1078
1109
  }
1079
1110
  async function runTypes(parsed, logger, options) {
1080
- const { runTypesCommand } = await import("./types-Zn9vyUGA.js");
1111
+ const { runTypesCommand } = await import("./types-DoKsMYfm.js");
1081
1112
  return runTypesCommand(parsed, logger, options);
1082
1113
  }
1083
1114
  async function runDoctor(parsed, logger, options) {
1084
- const { runDoctorCommand } = await import("./doctor-lFlh-olK.js");
1115
+ const { runDoctorCommand } = await import("./doctor-jm_K4dxL.js");
1085
1116
  return runDoctorCommand(parsed, logger, options);
1086
1117
  }
1087
1118
  async function runConfig(parsed, logger, options) {
1088
- const { runConfigCommand } = await import("./config-DQ_uWv37.js");
1119
+ const { runConfigCommand } = await import("./config-Brju62xy.js");
1089
1120
  return runConfigCommand(parsed, logger, options);
1090
1121
  }
1091
1122
  async function runAccount(parsed, logger, options) {
1092
- const { runAccountCommand } = await import("./account-Cdo_cRNv.js");
1123
+ const { runAccountCommand } = await import("./account-BI3WZMDy.js");
1093
1124
  return runAccountCommand(parsed, logger, options);
1094
1125
  }
1095
1126
  async function runLogin(parsed, logger, options) {
1096
- const { runLoginCommand } = await import("./login-DnyfffOC.js");
1127
+ const { runLoginCommand } = await import("./login-FjTAAQbi.js");
1097
1128
  return runLoginCommand(parsed, logger, options);
1098
1129
  }
1099
1130
  async function runPreviews(parsed, logger, options) {
1100
- const { runPreviewsCommand } = await import("./previews-wI-pW6HM.js");
1131
+ const { runPreviewsCommand } = await import("./previews-C7hs9-BT.js");
1101
1132
  return runPreviewsCommand(parsed, logger, options);
1102
1133
  }
1103
1134
  async function runProductions(parsed, logger, options) {
1104
- const { runProductionsCommand } = await import("./productions-BpROdhLN.js");
1135
+ const { runProductionsCommand } = await import("./productions-T9Als4fE.js");
1105
1136
  return runProductionsCommand(parsed, logger, options);
1106
1137
  }
1107
1138
  async function runWorker(parsed, logger, options) {
1108
- const { runWorkerCommand } = await import("./worker-rL5udcl9.js");
1139
+ const { runWorkerCommand } = await import("./worker-BEZI4od1.js");
1109
1140
  return runWorkerCommand(parsed, logger, options);
1110
1141
  }
1111
1142
  async function runToken(parsed, logger, options) {
1112
- const { runTokenCommand } = await import("./token-kguIDmej.js");
1143
+ const { runTokenCommand } = await import("./token-Dmi0KXyX.js");
1113
1144
  return runTokenCommand(parsed, logger, options);
1114
1145
  }
1115
1146
  async function runSecrets(parsed, logger, options) {
1116
1147
  const { runSecretsCommand } = await import("./secrets-DIpJGe6C.js");
1117
1148
  return runSecretsCommand(parsed, logger, options);
1118
1149
  }
1150
+ async function runTail(parsed, logger, options) {
1151
+ const { runTailCommand } = await import("./tail-IY-ijYmv.js");
1152
+ return runTailCommand(parsed, logger, options);
1153
+ }
1119
1154
  async function runAI() {
1120
1155
  const { runAICommand } = await import("./ai-CBEuLdoP.js");
1121
1156
  return runAICommand();
@@ -1,4 +1,4 @@
1
- import { i as resolveConfigPath, r as loadConfig } from "./loader-RZhqzsRJ.js";
1
+ import { i as resolveConfigPath, r as loadConfig } from "./loader-Cr0_OWPy.js";
2
2
  import { d as getPrimaryAccount, i as getWorkspaceAccountId, n as getEffectiveAccountId } from "./preferences-BKp_7XJx.js";
3
3
  //#region src/cli/command-utils.ts
4
4
  function asOptionalString(value) {
@@ -1,4 +1,4 @@
1
- import { f as normalizeCompatibilityFlags, u as resolveConfigForEnvironment } from "./loader-RZhqzsRJ.js";
1
+ import { p as normalizeCompatibilityFlags, u as resolveConfigForEnvironment } from "./loader-Cr0_OWPy.js";
2
2
  import { C as browserBindingSchema, _ as normalizeSecretsStoreBinding, a as normalizeD1Binding, b as normalizeVpcServiceBinding, c as normalizeFlagshipBinding, d as normalizeKVBinding, f as normalizeMediaBinding, g as normalizeR2Binding, h as normalizeQueueProducer, i as normalizeArtifactsBinding, l as normalizeHyperdriveBinding, m as normalizePipelineBinding, o as normalizeDOBinding, p as normalizeMtlsCertificateBinding, r as getSingleBrowserBindingName, s as normalizeDispatchNamespaceBinding, u as normalizeImagesBinding, v as normalizeStreamBinding, x as normalizeWorkflowBinding, y as normalizeVpcNetworkBinding } from "./schema-normalization-BCwTLTGp.js";
3
3
  import { n as toWranglerSecretsConfig } from "./local-dev-vars-CTSa-wvF.js";
4
4
  import { basename, isAbsolute, relative, resolve } from "pathe";
@@ -1,6 +1,6 @@
1
1
  import { d as resolveConfigEnvVars } from "./preview-C3Cdr8an.js";
2
- import { a as ConfigResourceResolutionError, o as loadResolvedConfig, r as loadConfig, s as resolveResources } from "./loader-RZhqzsRJ.js";
3
- import { n as compileConfig, t as compileBuildConfig } from "./compiler-Dc97FkBg.js";
2
+ import { a as ConfigResourceResolutionError, o as loadResolvedConfig, r as loadConfig, s as resolveResources } from "./loader-Cr0_OWPy.js";
3
+ import { n as compileConfig, t as compileBuildConfig } from "./compiler-Zw16C9Pi.js";
4
4
  //#region src/cli/commands/config.ts
5
5
  function isSupportedFormat(value) {
6
6
  return value === "devflare" || value === "wrangler";
@@ -1,4 +1,4 @@
1
- import { i as resolveConfigPath } from "./loader-RZhqzsRJ.js";
1
+ import { i as resolveConfigPath } from "./loader-Cr0_OWPy.js";
2
2
  import { i as findFiles } from "./glob-CmQOvunB.js";
3
3
  import { stat } from "node:fs/promises";
4
4
  //#region src/cli/config-path.ts
@@ -1,15 +1,15 @@
1
1
  import { a as resolvePreviewIdentifier, d as resolveConfigEnvVars } from "./preview-C3Cdr8an.js";
2
- import { c as prepareConfigResourcesForDeploy, r as loadConfig, u as resolveConfigForEnvironment } from "./loader-RZhqzsRJ.js";
3
- import { a as readWranglerConfig, c as writeWranglerConfig, n as compileConfig, o as rebaseWranglerConfigPaths, s as stringifyConfig, t as compileBuildConfig } from "./compiler-Dc97FkBg.js";
2
+ import { c as prepareConfigResourcesForDeploy, r as loadConfig, u as resolveConfigForEnvironment } from "./loader-Cr0_OWPy.js";
3
+ import { a as readWranglerConfig, c as writeWranglerConfig, n as compileConfig, o as rebaseWranglerConfigPaths, s as stringifyConfig, t as compileBuildConfig } from "./compiler-Zw16C9Pi.js";
4
4
  import { d as getPrimaryAccount, n as getEffectiveAccountId } from "./preferences-BKp_7XJx.js";
5
5
  import { D as listWorkerVersions, E as listWorkerDeployments, O as listWorkers, T as getWorkersSubdomain, c as reconcilePreviewRegistry, w as getWorkerVersionDetail, x as formatWorkersDevUrl } from "./preview-registry-ClAbLTHH.js";
6
6
  import { _ as yellowBold, d as green, f as logLine, g as yellow, o as dim, r as createCliTheme } from "./ui-BUoZApvE.js";
7
7
  import { n as getPackageVersion } from "./package-metadata-DjHBLB-z.js";
8
8
  import { t as resolvePackageSpecifier } from "./resolve-package-qizBfCIm.js";
9
- import { t as asOptionalString } from "./command-utils-C48hJMln.js";
10
- import { a as createBuildManifest, i as compareManifests, n as applyDeploymentStrategy, o as formatDriftWarning, r as describeDeploymentStrategy, s as readBuildManifest, t as prepareBuildArtifacts } from "./build-artifacts-CaSTDXLE.js";
9
+ import { t as asOptionalString } from "./command-utils-DA0Qx9_K.js";
10
+ import { a as createBuildManifest, i as compareManifests, n as applyDeploymentStrategy, o as formatDriftWarning, r as describeDeploymentStrategy, s as readBuildManifest, t as prepareBuildArtifacts } from "./build-artifacts-DU5V0J0Z.js";
11
11
  import { t as getDependencies } from "./dependencies-C2oxFjU_.js";
12
- import { n as preparePreviewScopedResourcesForDeploy } from "./preview-resources-xziKCynb.js";
12
+ import { n as preparePreviewScopedResourcesForDeploy } from "./preview-resources-CGMBjsYB.js";
13
13
  import { mkdir, open, readFile, rm, writeFile } from "node:fs/promises";
14
14
  import { basename, dirname, isAbsolute, join, resolve } from "pathe";
15
15
  //#region src/config/service-bindings-validation.ts
@@ -147,6 +147,68 @@ async function withTemporaryEnvironment(overrides, operation) {
147
147
  }
148
148
  }
149
149
  //#endregion
150
+ //#region src/cli/gradual-deploy.ts
151
+ /**
152
+ * Parse and validate the `--percentage` CLI option.
153
+ *
154
+ * Returns `undefined` when the flag is absent (a normal full deploy). Throws a
155
+ * clear error when the value is present but not an integer in `[0, 100]` — the
156
+ * same bounds Wrangler enforces — so a typo never silently becomes a full
157
+ * deploy.
158
+ */
159
+ function parseDeployPercentage(value) {
160
+ if (value === void 0) return;
161
+ if (value === true || value === false) throw new Error("--percentage requires a value between 0 and 100, e.g. `--percentage 10`.");
162
+ const trimmed = value.trim();
163
+ if (!/^\d+$/.test(trimmed)) throw new Error(`--percentage must be a whole number between 0 and 100, received "${value}".`);
164
+ const parsed = Number.parseInt(trimmed, 10);
165
+ if (!Number.isInteger(parsed) || parsed < 0 || parsed > 100) throw new Error(`--percentage must be a whole number between 0 and 100, received "${value}".`);
166
+ return parsed;
167
+ }
168
+ /**
169
+ * Build the positional `<version-id>@<percentage>` version specs for a rollout.
170
+ *
171
+ * Wrangler's `versions deploy` consumes traffic splits as positional specs (see
172
+ * `wrangler versions deploy --help`: "Shorthand notation to deploy Worker
173
+ * Version(s) [<version-id>@<percentage>..]"). When a distinct previous version
174
+ * id is provided, the remaining percentage is routed to it so the split is
175
+ * fully specified and Wrangler never has to prompt; otherwise only the new
176
+ * version is named and Wrangler distributes the rest.
177
+ */
178
+ function buildVersionSpecs(spec) {
179
+ const specs = [`${spec.versionId}@${spec.percentage}`];
180
+ const remaining = 100 - spec.percentage;
181
+ if (spec.previousVersionId && spec.previousVersionId !== spec.versionId && remaining > 0) specs.push(`${spec.previousVersionId}@${remaining}`);
182
+ return specs;
183
+ }
184
+ /**
185
+ * Build the full `wrangler versions deploy` invocation for a gradual rollout.
186
+ *
187
+ * `localWranglerExecutable` mirrors the deploy command's resolution: when a
188
+ * local `wrangler/bin/wrangler.js` exists it is run under `node`; otherwise the
189
+ * invocation falls back to `bunx wrangler …`.
190
+ */
191
+ function buildGradualDeployInvocation(spec, localWranglerExecutable) {
192
+ const command = localWranglerExecutable ? "node" : "bunx";
193
+ const args = localWranglerExecutable ? [
194
+ localWranglerExecutable,
195
+ "versions",
196
+ "deploy"
197
+ ] : [
198
+ "wrangler",
199
+ "versions",
200
+ "deploy"
201
+ ];
202
+ args.push(...buildVersionSpecs(spec));
203
+ args.push("--name", spec.workerName);
204
+ if (spec.message?.trim()) args.push("--message", spec.message.trim());
205
+ args.push("--yes");
206
+ return {
207
+ command,
208
+ args
209
+ };
210
+ }
211
+ //#endregion
150
212
  //#region src/cli/preview.ts
151
213
  function matchNamedValue(output, patterns) {
152
214
  for (const pattern of patterns) {
@@ -555,6 +617,8 @@ async function runDeployCommand(parsed, logger, options) {
555
617
  let deployMessage;
556
618
  let deployTag;
557
619
  let previewScopeName;
620
+ let rolloutPercentage;
621
+ let rolloutPreviousVersionId;
558
622
  let requireFreshProductionDeployment = false;
559
623
  let resolvedPreviewScopeName = process.env.DEVFLARE_PREVIEW_BRANCH?.trim() || void 0;
560
624
  const theme = createCliTheme(parsed.options);
@@ -570,6 +634,9 @@ async function runDeployCommand(parsed, logger, options) {
570
634
  branchName = resolvedParsed.options["branch-name"];
571
635
  deployMessage = resolvedParsed.options.message;
572
636
  deployTag = resolvedParsed.options.tag;
637
+ rolloutPercentage = parseDeployPercentage(resolvedParsed.options.percentage);
638
+ rolloutPreviousVersionId = typeof resolvedParsed.options.version === "string" ? resolvedParsed.options.version.trim() || void 0 : void 0;
639
+ if (rolloutPercentage !== void 0 && deployTarget.mode !== "production") throw new Error("--percentage is a production gradual rollout and is only valid with an explicit production target. Run `devflare deploy --prod --percentage <n>` (it cannot be combined with --preview or a named/branch preview deploy).");
573
640
  previewScopeName = branchName?.trim() || deployTarget.previewScopeRaw || void 0;
574
641
  resolvedPreviewScopeName = previewScopeName || process.env.DEVFLARE_PREVIEW_BRANCH?.trim() || void 0;
575
642
  requireFreshProductionDeployment = !preview && shouldRequireFreshProductionDeployment();
@@ -591,6 +658,7 @@ async function runDeployCommand(parsed, logger, options) {
591
658
  });
592
659
  const wranglerConfig = compileBuildConfig(deploymentStrategy.config, void 0, { alreadyResolved: true });
593
660
  logLine(logger, `${yellow("dry run", theme)} ${dim("Skipping actual deployment", theme)}`);
661
+ if (rolloutPercentage !== void 0) logLine(logger, dim(`Would upload a new Worker version and route ${rolloutPercentage}% of production traffic to it via \`wrangler versions deploy\`${rolloutPreviousVersionId ? `, keeping ${100 - rolloutPercentage}% on version ${rolloutPreviousVersionId}` : ""}.`, theme));
594
662
  const deploymentStrategyMessage = describeDeploymentStrategy(deploymentStrategy);
595
663
  if (deploymentStrategyMessage) logLine(logger, dim(deploymentStrategyMessage, theme));
596
664
  logLine(logger, dim("Would deploy with wrangler config:", theme));
@@ -647,13 +715,15 @@ async function runDeployCommand(parsed, logger, options) {
647
715
  if (prepared.config.bindings?.durableObjects && Object.keys(prepared.config.bindings.durableObjects).length > 0) logger.warn("Cloudflare does not currently generate preview URLs for Workers that implement Durable Objects.");
648
716
  if (prepared.config.migrations && prepared.config.migrations.length > 0) logger.warn("Cloudflare versions upload does not currently support Durable Object migrations.");
649
717
  }
650
- logLine(logger, dim(preview ? "Uploading preview version with Wrangler…" : "Deploying with Wrangler…", theme));
718
+ const usePercentageRollout = !preview && !isBranchScopedPreviewDeployment && rolloutPercentage !== void 0;
719
+ const uploadVersionOnly = preview || usePercentageRollout;
720
+ logLine(logger, dim(preview ? "Uploading preview version with Wrangler…" : usePercentageRollout ? "Uploading new Worker version with Wrangler…" : "Deploying with Wrangler…", theme));
651
721
  const deployStartedAt = /* @__PURE__ */ new Date();
652
722
  const wranglerOutputDirectory = join(cwd, ".devflare");
653
723
  const wranglerOutputFilePath = join(wranglerOutputDirectory, `wrangler-output-${Date.now()}-${process.pid}.ndjson`);
654
724
  await deps.fs.mkdir(wranglerOutputDirectory, { recursive: true });
655
725
  const wranglerCommand = localWranglerExecutable ? "node" : "bunx";
656
- const wranglerArgs = preview ? localWranglerExecutable ? [
726
+ const wranglerArgs = uploadVersionOnly ? localWranglerExecutable ? [
657
727
  localWranglerExecutable,
658
728
  "versions",
659
729
  "upload"
@@ -766,7 +836,7 @@ async function runDeployCommand(parsed, logger, options) {
766
836
  const message = error instanceof Error ? error.message : String(error);
767
837
  versionRecoveryDiagnostics.push(`deployment lookup: ${message}`);
768
838
  }
769
- if (!preview && !isBranchScopedPreviewDeployment && !resolvedVersionId && resolvedAccountId) try {
839
+ if (!preview && !isBranchScopedPreviewDeployment && !usePercentageRollout && !resolvedVersionId && resolvedAccountId) try {
770
840
  const fallbackDeployment = await resolveVersionIdFromLatestProductionDeployment({
771
841
  accountId: resolvedAccountId,
772
842
  workerName: prepared.config.name,
@@ -780,7 +850,7 @@ async function runDeployCommand(parsed, logger, options) {
780
850
  const message = error instanceof Error ? error.message : String(error);
781
851
  versionRecoveryDiagnostics.push(`deployment lookup: ${message}`);
782
852
  }
783
- if (!preview && !isBranchScopedPreviewDeployment && !resolvedVersionId && resolvedAccountId) try {
853
+ if (!preview && !isBranchScopedPreviewDeployment && !usePercentageRollout && !resolvedVersionId && resolvedAccountId) try {
784
854
  const currentDeployment = await resolveVersionIdFromCurrentProductionDeployment({
785
855
  accountId: resolvedAccountId,
786
856
  workerName: prepared.config.name
@@ -845,7 +915,7 @@ async function runDeployCommand(parsed, logger, options) {
845
915
  accountId: resolvedAccountId,
846
916
  workerName: prepared.config.name,
847
917
  versionId: resolvedVersionId,
848
- preview,
918
+ preview: preview || usePercentageRollout,
849
919
  logger,
850
920
  theme
851
921
  });
@@ -863,6 +933,52 @@ async function runDeployCommand(parsed, logger, options) {
863
933
  };
864
934
  }
865
935
  }
936
+ if (usePercentageRollout) {
937
+ if (!resolvedVersionId) {
938
+ const recoveryDetails = versionRecoveryDiagnostics.length > 0 ? ` Cloudflare fallback checks also failed: ${versionRecoveryDiagnostics.join(" | ")}` : "";
939
+ const rolloutError = `A new Worker version was uploaded, but Devflare could not resolve its version id, so it could not start the ${rolloutPercentage}% gradual rollout. Re-run \`devflare deploy --prod --percentage ${rolloutPercentage}\`, or split traffic manually with \`wrangler versions deploy\`.${recoveryDetails}`;
940
+ await persistDeployMetadata({
941
+ status: "failure",
942
+ exitCode: 1,
943
+ error: rolloutError
944
+ });
945
+ logger.error(rolloutError);
946
+ return {
947
+ exitCode: 1,
948
+ output: structuredOutput
949
+ };
950
+ }
951
+ const rolloutInvocation = buildGradualDeployInvocation({
952
+ versionId: resolvedVersionId,
953
+ percentage: rolloutPercentage,
954
+ previousVersionId: rolloutPreviousVersionId,
955
+ workerName: prepared.config.name,
956
+ message: deployMessage?.trim() || void 0
957
+ }, localWranglerExecutable);
958
+ logLine(logger, dim(`Routing ${rolloutPercentage}% of production traffic to the new version with Wrangler…`, theme));
959
+ const rolloutProc = await deps.exec.exec(rolloutInvocation.command, rolloutInvocation.args, {
960
+ cwd,
961
+ stdio: "inherit",
962
+ env: {
963
+ ...process.env,
964
+ FORCE_COLOR: process.env.FORCE_COLOR ?? "0"
965
+ }
966
+ });
967
+ if (rolloutProc.exitCode !== 0) {
968
+ const rolloutError = `The new Worker version ${resolvedVersionId} was uploaded, but \`wrangler versions deploy\` failed to route ${rolloutPercentage}% of production traffic to it. Re-run the rollout, or split traffic manually with \`wrangler versions deploy\`.`;
969
+ await persistDeployMetadata({
970
+ status: "failure",
971
+ exitCode: 1,
972
+ error: rolloutProc.stderr || rolloutProc.stdout || rolloutError
973
+ });
974
+ logger.error(rolloutError);
975
+ return {
976
+ exitCode: 1,
977
+ output: structuredOutput
978
+ };
979
+ }
980
+ logger.success(`Routed ${rolloutPercentage}% of production traffic to version ${resolvedVersionId}`);
981
+ }
866
982
  if (resolvedAccountId) {
867
983
  const previewRegistryScope = isBranchScopedPreviewDeployment ? deployTarget.previewScope : void 0;
868
984
  const previewRegistryUrl = preview || isBranchScopedPreviewDeployment ? resolvedPreviewUrl : void 0;
@@ -889,6 +1005,7 @@ async function runDeployCommand(parsed, logger, options) {
889
1005
  exitCode: 0
890
1006
  });
891
1007
  logger.success("Deployed successfully!");
1008
+ if (!preview && !isBranchScopedPreviewDeployment) logLine(logger, dim("Runtime secrets: set production secret values with `wrangler secret put` or the Cloudflare dashboard. Devflare manages local secret values (`devflare secrets --local`) and emits Secrets Store references only — it never sends secret values to Cloudflare.", theme));
892
1009
  return {
893
1010
  exitCode: 0,
894
1011
  output: structuredOutput
@@ -1,13 +1,13 @@
1
1
  import { c as getDevflareDotenvPaths, d as resolveConfigEnvVars, o as EnvVarResolutionError } from "./preview-C3Cdr8an.js";
2
- import { i as resolveConfigPath, r as loadConfig } from "./loader-RZhqzsRJ.js";
2
+ import { i as resolveConfigPath, r as loadConfig } from "./loader-Cr0_OWPy.js";
3
3
  import { g as normalizeR2Binding, n as getLocalKVNamespaceIdentifier, r as getSingleBrowserBindingName, t as getLocalD1DatabaseIdentifier } from "./schema-normalization-BCwTLTGp.js";
4
4
  import { t as applyLocalDevVarsToConfig } from "./local-dev-vars-CTSa-wvF.js";
5
5
  import { a as cyanBold, f as logLine, g as yellow, o as dim, r as createCliTheme } from "./ui-BUoZApvE.js";
6
6
  import { clearLocalSendEmailBindings, setLocalSendEmailBindings } from "../utils/send-email.js";
7
- import { C as buildSendEmailConfig, D as buildWorkerLoadersConfig, E as buildVersionMetadataConfig, O as buildWorkflowsConfig, S as buildSecretsStoreConfig, T as buildTailConsumersConfig, _ as buildMtlsCertificatesConfig, b as buildQueueProducers, c as buildAiSearchInstancesConfig, d as buildArtifactsConfig, f as buildDispatchNamespacesConfig, g as buildMediaConfig, h as buildImagesConfig, l as buildAiSearchNamespacesConfig, m as buildHyperdrivesConfig, n as getRouteDirectoryCandidate, p as buildFlagshipConfig, s as resolveServiceBindings, t as discoverRoutes, u as buildAnalyticsEngineConfig, v as buildPipelinesConfig, w as buildStreamConfig, x as buildRateLimitsConfig, y as buildQueueConsumers } from "./routes-C4S8x2HU.js";
7
+ import { C as buildSendEmailConfig, D as buildWorkerLoadersConfig, E as buildVersionMetadataConfig, O as buildWorkflowsConfig, S as buildSecretsStoreConfig, T as buildTailConsumersConfig, _ as buildMtlsCertificatesConfig, b as buildQueueProducers, c as buildAiSearchInstancesConfig, d as buildArtifactsConfig, f as buildDispatchNamespacesConfig, g as buildMediaConfig, h as buildImagesConfig, l as buildAiSearchNamespacesConfig, m as buildHyperdrivesConfig, n as getRouteDirectoryCandidate, p as buildFlagshipConfig, s as resolveServiceBindings, t as discoverRoutes, u as buildAnalyticsEngineConfig, v as buildPipelinesConfig, w as buildStreamConfig, x as buildRateLimitsConfig, y as buildQueueConsumers } from "./routes-BFYCqHb-.js";
8
8
  import { r as transformDurableObject } from "./durable-object-DMtH0XYX.js";
9
9
  import { i as findFiles } from "./glob-CmQOvunB.js";
10
- import { d as DEFAULT_FETCH_ENTRY_FILES, f as DEFAULT_QUEUE_ENTRY_FILES, g as discoverDurableObjectFiles, h as resolveWorkerSurfacePaths, i as writeGeneratedViteConfig, l as prepareComposedWorkerEntrypoint, m as hasWorkerSurfacePaths, n as resolveEffectiveViteProject, p as DEFAULT_SCHEDULED_ENTRY_FILES, u as DEFAULT_EMAIL_ENTRY_FILES } from "./vite-D5dfVb6G.js";
10
+ import { d as DEFAULT_FETCH_ENTRY_FILES, f as DEFAULT_QUEUE_ENTRY_FILES, g as discoverDurableObjectFiles, h as resolveWorkerSurfacePaths, i as writeGeneratedViteConfig, l as prepareComposedWorkerEntrypoint, m as hasWorkerSurfacePaths, n as resolveEffectiveViteProject, p as DEFAULT_SCHEDULED_ENTRY_FILES, u as DEFAULT_EMAIL_ENTRY_FILES } from "./vite-CGtVNf5E.js";
11
11
  import { a as createWorkerdBundlerDefaults, i as writeWorkerCompatibleBundle, n as ensureDebugShim, r as resolveWorkerCompatibleRolldownConfig, t as bundleWorkerEntry } from "./worker-bundler-dTTnYU3n.js";
12
12
  import { t as bundleWorkflowEntrypointScript } from "./local-workflow-entrypoints-Cq_WJajd.js";
13
13
  import { n as buildLocalSecretWrappedBindingConfig } from "./local-secrets-DMPkmOn3.js";
@@ -1,10 +1,10 @@
1
- import { r as loadConfig } from "./loader-RZhqzsRJ.js";
1
+ import { r as loadConfig } from "./loader-Cr0_OWPy.js";
2
2
  import { d as green, f as logLine, g as yellow, m as red, n as bold, o as dim, r as createCliTheme } from "./ui-BUoZApvE.js";
3
3
  import { n as getPackageVersion } from "./package-metadata-DjHBLB-z.js";
4
4
  import { t as detectViteProject } from "./vite-utils-OVLMV605.js";
5
5
  import { t as getDependencies } from "./dependencies-C2oxFjU_.js";
6
6
  import { n as getGeneratedArtifactPaths } from "./generated-artifacts-dMJY4KAt.js";
7
- import { n as formatSupportedConfigFilenames, r as resolveConfigCandidatePath } from "./config-path-ePwIvHNX.js";
7
+ import { n as formatSupportedConfigFilenames, r as resolveConfigCandidatePath } from "./config-path-DaL1ylZ_.js";
8
8
  import { basename, dirname, relative, resolve } from "pathe";
9
9
  //#region src/cli/commands/doctor.ts
10
10
  async function runDoctorCommand(parsed, logger, options) {
@@ -1,4 +1,4 @@
1
- import { u as resolveConfigForEnvironment } from "./loader-RZhqzsRJ.js";
1
+ import { u as resolveConfigForEnvironment } from "./loader-Cr0_OWPy.js";
2
2
  //#region src/cli/commands/previews-support/family.ts
3
3
  function compareConfiguredWorkerFamilies(left, right) {
4
4
  if (left.role === "primary" && right.role !== "primary") return -1;