devflare 1.0.0-next.22 → 1.0.0-next.23

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 (114) hide show
  1. package/LLM.md +144 -5
  2. package/dist/account-j8nfggg4.js +475 -0
  3. package/dist/account-qhe8vtds.js +475 -0
  4. package/dist/bridge/miniflare.d.ts +1 -1
  5. package/dist/bridge/miniflare.d.ts.map +1 -1
  6. package/dist/browser.d.ts +13 -13
  7. package/dist/browser.d.ts.map +1 -1
  8. package/dist/browser.js +4 -2
  9. package/dist/build-vy95gy3f.js +54 -0
  10. package/dist/build-yzx0gsaj.js +54 -0
  11. package/dist/cli/commands/build-artifacts.d.ts.map +1 -1
  12. package/dist/cli/commands/config.d.ts.map +1 -1
  13. package/dist/cli/commands/type-generation/generator.d.ts +4 -2
  14. package/dist/cli/commands/type-generation/generator.d.ts.map +1 -1
  15. package/dist/cli/commands/types.d.ts.map +1 -1
  16. package/dist/cli/index.js +1 -1
  17. package/dist/config/compiler/types.d.ts +1 -1
  18. package/dist/config/compiler/types.d.ts.map +1 -1
  19. package/dist/config/define.d.ts +7 -4
  20. package/dist/config/define.d.ts.map +1 -1
  21. package/dist/config/env-vars.d.ts +309 -0
  22. package/dist/config/env-vars.d.ts.map +1 -0
  23. package/dist/config/index.d.ts +2 -1
  24. package/dist/config/index.d.ts.map +1 -1
  25. package/dist/config/loader.d.ts.map +1 -1
  26. package/dist/config/local-dev-vars.d.ts +2 -2
  27. package/dist/config/local-dev-vars.d.ts.map +1 -1
  28. package/dist/config/schema-env.d.ts +6 -6
  29. package/dist/config/schema-types-bindings-platform.d.ts +378 -0
  30. package/dist/config/schema-types-bindings-platform.d.ts.map +1 -0
  31. package/dist/config/schema-types-bindings-resources.d.ts +551 -0
  32. package/dist/config/schema-types-bindings-resources.d.ts.map +1 -0
  33. package/dist/config/schema-types-bindings.d.ts +254 -0
  34. package/dist/config/schema-types-bindings.d.ts.map +1 -0
  35. package/dist/config/schema-types-build.d.ts +86 -0
  36. package/dist/config/schema-types-build.d.ts.map +1 -0
  37. package/dist/config/schema-types-runtime.d.ts +882 -0
  38. package/dist/config/schema-types-runtime.d.ts.map +1 -0
  39. package/dist/config/schema-types.d.ts +377 -0
  40. package/dist/config/schema-types.d.ts.map +1 -0
  41. package/dist/config/schema.d.ts +14 -15
  42. package/dist/config/schema.d.ts.map +1 -1
  43. package/dist/config-entry.d.ts +2 -0
  44. package/dist/config-entry.d.ts.map +1 -1
  45. package/dist/config-entry.js +3 -1
  46. package/dist/config-gq5jh4cx.js +105 -0
  47. package/dist/config-vec13050.js +105 -0
  48. package/dist/deploy-01j0ep5n.js +1055 -0
  49. package/dist/deploy-tjypkhg7.js +1055 -0
  50. package/dist/dev-bh581ew3.js +2597 -0
  51. package/dist/dev-gn5y93z9.js +2597 -0
  52. package/dist/dev-server/server.d.ts.map +1 -1
  53. package/dist/doctor-h5q28qt1.js +259 -0
  54. package/dist/doctor-khk550tw.js +259 -0
  55. package/dist/env.d.ts +10 -0
  56. package/dist/env.d.ts.map +1 -1
  57. package/dist/index-0bv2qjs1.js +1555 -0
  58. package/dist/index-3tkzn06q.js +413 -0
  59. package/dist/index-8fyz6gcm.js +699 -0
  60. package/dist/index-97z629zr.js +109 -0
  61. package/dist/index-b28c4yr4.js +1205 -0
  62. package/dist/index-c8p4njqy.js +479 -0
  63. package/dist/index-cr06zrgw.js +1033 -0
  64. package/dist/index-cwjjdtgn.js +74 -0
  65. package/dist/index-dref9ecb.js +476 -0
  66. package/dist/index-e151t4ge.js +895 -0
  67. package/dist/index-e7kakw0j.js +1033 -0
  68. package/dist/index-f1g5jdm8.js +1426 -0
  69. package/dist/index-f46984zs.js +1554 -0
  70. package/dist/index-grk8pzhr.js +185 -0
  71. package/dist/index-hzmpecq9.js +52 -0
  72. package/dist/index-j1csb7gb.js +581 -0
  73. package/dist/index-j7x7f72h.js +185 -0
  74. package/dist/index-jkqbjwt2.js +476 -0
  75. package/dist/index-mh5renra.js +895 -0
  76. package/dist/index-p9xq83p7.js +147 -0
  77. package/dist/index-q15nj71j.js +52 -0
  78. package/dist/index-qqp65pyv.js +699 -0
  79. package/dist/index-s0fmwxbk.js +74 -0
  80. package/dist/index-stzx8nc4.js +111 -0
  81. package/dist/index-th4vrnbk.js +1205 -0
  82. package/dist/index-vtcmsgaf.js +581 -0
  83. package/dist/index-x2k3awjs.js +147 -0
  84. package/dist/index-x8x547tz.js +1426 -0
  85. package/dist/index-xxxd0mvw.js +109 -0
  86. package/dist/index.d.ts +1 -1
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +8 -6
  89. package/dist/login-280p2cm9.js +77 -0
  90. package/dist/login-4n266whq.js +77 -0
  91. package/dist/previews-3m3ffpaw.js +1337 -0
  92. package/dist/previews-tr8sm03d.js +1337 -0
  93. package/dist/productions-62y489ff.js +505 -0
  94. package/dist/productions-cgn3fz7d.js +505 -0
  95. package/dist/runtime/exports.d.ts +23 -0
  96. package/dist/runtime/exports.d.ts.map +1 -1
  97. package/dist/runtime/index.d.ts +1 -1
  98. package/dist/runtime/index.d.ts.map +1 -1
  99. package/dist/runtime/index.js +5 -3
  100. package/dist/secrets-4050kqf5.js +91 -0
  101. package/dist/secrets-p112cajt.js +91 -0
  102. package/dist/sveltekit/index.js +4 -4
  103. package/dist/test/index.js +23 -11
  104. package/dist/test/resolve-service-bindings.d.ts +1 -1
  105. package/dist/test/resolve-service-bindings.d.ts.map +1 -1
  106. package/dist/test/simple-context-lifecycle.d.ts.map +1 -1
  107. package/dist/types-apmt10yj.js +705 -0
  108. package/dist/types-ttrrgdfj.js +705 -0
  109. package/dist/vite/index.js +5 -5
  110. package/dist/vite/plugin-context.d.ts.map +1 -1
  111. package/dist/vite/plugin-programmatic.d.ts.map +1 -1
  112. package/dist/worker-2k1jyr6p.js +513 -0
  113. package/dist/worker-jqgn6jyj.js +513 -0
  114. package/package.json +1 -1
@@ -0,0 +1,505 @@
1
+ import {
2
+ collectConfiguredWorkerFamilies
3
+ } from "./index-grk8pzhr.js";
4
+ import {
5
+ asOptionalString,
6
+ resolveCloudflareAccountId,
7
+ resolveNamedSelection
8
+ } from "./index-s0fmwxbk.js";
9
+ import {
10
+ account
11
+ } from "./index-0m6e4mxz.js";
12
+ import"./index-k7m5f1dg.js";
13
+ import"./index-3jme4hgw.js";
14
+ import {
15
+ getDependencies
16
+ } from "./index-z9gy8w6b.js";
17
+ import {
18
+ bold,
19
+ createCliTheme,
20
+ cyanBold,
21
+ dim,
22
+ formatLabelValue,
23
+ green,
24
+ logLine,
25
+ logTable,
26
+ red,
27
+ whiteDim,
28
+ yellow
29
+ } from "./index-stgn34cr.js";
30
+ import"./index-3t6rypgc.js";
31
+ import"./index-15fpa5tx.js";
32
+ import {
33
+ findFiles
34
+ } from "./index-qwgr4q7s.js";
35
+ import"./index-8fyz6gcm.js";
36
+ import {
37
+ ConfigNotFoundError,
38
+ loadConfig
39
+ } from "./index-0bv2qjs1.js";
40
+ import"./index-1d4jg11n.js";
41
+ import"./index-mg8vwqxf.js";
42
+ import"./index-c8p4njqy.js";
43
+ import"./index-q8f4kawk.js";
44
+ import"./index-37x76zdn.js";
45
+
46
+ // src/cli/commands/productions.ts
47
+ var CLI_API_OPTIONS = { timeout: 1e4 };
48
+ var PRODUCTION_SUBCOMMANDS = ["list", "versions", "rollback", "delete"];
49
+ var VERSION_LIST_LIMIT = 10;
50
+ function isProductionSubcommand(value) {
51
+ return PRODUCTION_SUBCOMMANDS.includes(value);
52
+ }
53
+ function shortenVersionId(versionId, length = 12) {
54
+ return versionId.length <= length ? versionId : `${versionId.slice(0, length)}…`;
55
+ }
56
+ function selectDeploymentVersionId(deployment) {
57
+ return deployment.versions.find((version) => version.percentage === 100)?.versionId ?? deployment.versions[0]?.versionId;
58
+ }
59
+ function getWorkerVersionTimestamp(version) {
60
+ return version.metadata.modifiedOn ?? version.metadata.createdOn;
61
+ }
62
+ function formatRecordDate(date) {
63
+ return date ? date.toISOString().slice(0, 19).replace("T", " ") : "N/A";
64
+ }
65
+ function formatWorkerStatus(status, theme) {
66
+ switch (status) {
67
+ case "active":
68
+ return green(status, theme);
69
+ case "undeployed":
70
+ return yellow(status, theme);
71
+ case "missing":
72
+ default:
73
+ return red(status, theme);
74
+ }
75
+ }
76
+ function formatVersionStatus(status, theme) {
77
+ switch (status) {
78
+ case "active":
79
+ return green(status, theme);
80
+ case "stored":
81
+ default:
82
+ return whiteDim(status, theme);
83
+ }
84
+ }
85
+ function shouldReplaceConfiguredWorkerFamily(existing, candidate) {
86
+ return !existing || candidate.role === "primary" && existing.role !== "primary";
87
+ }
88
+ function mergeConfiguredWorkerFamily(families, candidate) {
89
+ if (shouldReplaceConfiguredWorkerFamily(families.get(candidate.baseName), candidate)) {
90
+ families.set(candidate.baseName, candidate);
91
+ }
92
+ }
93
+ async function discoverProductionConfigs(cwd, configFile, environment) {
94
+ const families = new Map;
95
+ const primaryFamilyNames = new Set;
96
+ const accountIds = new Set;
97
+ let defaultWorkerName;
98
+ let defaultWorkerNameSource = "none";
99
+ const loadAndCollect = async (candidateConfigFile) => {
100
+ try {
101
+ const config = await loadConfig({ cwd, configFile: candidateConfigFile });
102
+ const resolvedFamilies = collectConfiguredWorkerFamilies(config, environment);
103
+ for (const family of resolvedFamilies) {
104
+ mergeConfiguredWorkerFamily(families, family);
105
+ if (family.role === "primary") {
106
+ primaryFamilyNames.add(family.baseName);
107
+ }
108
+ }
109
+ if (config.accountId?.trim()) {
110
+ accountIds.add(config.accountId.trim());
111
+ }
112
+ if (!defaultWorkerName) {
113
+ defaultWorkerName = resolvedFamilies.find((family) => family.role === "primary")?.baseName;
114
+ defaultWorkerNameSource = defaultWorkerName ? "config" : "none";
115
+ }
116
+ return true;
117
+ } catch (error) {
118
+ if (error instanceof ConfigNotFoundError) {
119
+ return false;
120
+ }
121
+ throw error;
122
+ }
123
+ };
124
+ if (configFile) {
125
+ await loadAndCollect(configFile);
126
+ } else {
127
+ const loadedDirectly = await loadAndCollect();
128
+ if (!loadedDirectly) {
129
+ const configPaths = (await findFiles("**/devflare.config.{ts,js,mjs,cjs}", {
130
+ cwd,
131
+ absolute: true
132
+ })).sort((left, right) => left.localeCompare(right));
133
+ for (const configPath of configPaths) {
134
+ await loadAndCollect(configPath);
135
+ }
136
+ }
137
+ }
138
+ if (accountIds.size > 1) {
139
+ throw new Error("Multiple Cloudflare account ids were discovered across local Devflare configs. Pass --account to select one account explicitly for `devflare productions`.");
140
+ }
141
+ return {
142
+ accountId: Array.from(accountIds)[0],
143
+ defaultWorkerName,
144
+ defaultWorkerNameSource,
145
+ families: Array.from(families.values()).sort((left, right) => {
146
+ if (left.role === "primary" && right.role !== "primary") {
147
+ return -1;
148
+ }
149
+ if (left.role !== "primary" && right.role === "primary") {
150
+ return 1;
151
+ }
152
+ return left.baseName.localeCompare(right.baseName);
153
+ }),
154
+ primaryFamilyNames: Array.from(primaryFamilyNames).sort((left, right) => left.localeCompare(right))
155
+ };
156
+ }
157
+ async function resolveAccountId(parsed, discovery) {
158
+ return resolveCloudflareAccountId({
159
+ explicitAccountId: asOptionalString(parsed.options.account),
160
+ configuredAccountId: discovery.accountId,
161
+ apiOptions: CLI_API_OPTIONS
162
+ });
163
+ }
164
+ function resolveWorkerName(parsed, discovery, fallbackArg) {
165
+ const selection = resolveNamedSelection({
166
+ explicitValue: asOptionalString(parsed.options.worker),
167
+ fallbackValue: fallbackArg,
168
+ configuredValue: discovery.defaultWorkerName
169
+ });
170
+ return {
171
+ workerName: selection.value,
172
+ source: selection.value === discovery.defaultWorkerName ? discovery.defaultWorkerNameSource : selection.source
173
+ };
174
+ }
175
+ async function resolveContext(parsed, options, subcommand, fallbackArg) {
176
+ const cwd = options.cwd ?? process.cwd();
177
+ const configFile = asOptionalString(parsed.options.config);
178
+ const environment = asOptionalString(parsed.options.env) ?? "production";
179
+ const explicitAccountId = asOptionalString(parsed.options.account);
180
+ const explicitWorkerName = asOptionalString(parsed.options.worker) ?? fallbackArg;
181
+ const shouldDiscoverConfigs = Boolean(configFile) || !explicitAccountId || !explicitWorkerName;
182
+ const discovery = shouldDiscoverConfigs ? await discoverProductionConfigs(cwd, configFile, environment) : {
183
+ accountId: undefined,
184
+ defaultWorkerName: undefined,
185
+ defaultWorkerNameSource: "none",
186
+ families: [],
187
+ primaryFamilyNames: []
188
+ };
189
+ const accountId = await resolveAccountId(parsed, discovery);
190
+ const workerSelection = resolveWorkerName(parsed, discovery, fallbackArg);
191
+ if (!accountId) {
192
+ throw new Error("No Cloudflare account could be resolved. Use --account or configure accountId in devflare.config.*.");
193
+ }
194
+ if ((subcommand === "rollback" || subcommand === "delete") && !workerSelection.workerName) {
195
+ throw new Error(`A worker name is required for productions ${subcommand}. Use --worker or run inside a configured package with a single primary worker.`);
196
+ }
197
+ return {
198
+ accountId,
199
+ workerName: workerSelection.workerName,
200
+ workerNameSource: workerSelection.source,
201
+ discovery
202
+ };
203
+ }
204
+ function getProductionUrl(workerName, workersSubdomain) {
205
+ if (!workersSubdomain) {
206
+ return;
207
+ }
208
+ const normalizedSubdomain = workersSubdomain.trim().replace(/^https?:\/\//i, "").replace(/\.workers\.dev\/?$/i, "");
209
+ return `https://${workerName}.${normalizedSubdomain}.workers.dev`;
210
+ }
211
+ async function buildProductionRows(accountId, families, apiOptions) {
212
+ const [liveWorkers, workersSubdomain] = await Promise.all([
213
+ account.workers(accountId, apiOptions),
214
+ account.workersSubdomain(accountId, apiOptions)
215
+ ]);
216
+ const workersByName = new Map(liveWorkers.map((worker) => [worker.name, worker]));
217
+ return Promise.all(families.map(async (family) => {
218
+ const worker = workersByName.get(family.baseName);
219
+ if (!worker) {
220
+ return {
221
+ workerName: family.baseName,
222
+ role: family.roleLabel,
223
+ status: "missing",
224
+ url: getProductionUrl(family.baseName, workersSubdomain)
225
+ };
226
+ }
227
+ const deployments = await account.workerDeployments(accountId, family.baseName, apiOptions);
228
+ const latestDeployment = [...deployments].sort((left, right) => {
229
+ return right.createdOn.getTime() - left.createdOn.getTime();
230
+ })[0];
231
+ const activeVersionId = latestDeployment ? selectDeploymentVersionId(latestDeployment) : undefined;
232
+ return {
233
+ workerName: family.baseName,
234
+ role: family.roleLabel,
235
+ status: latestDeployment ? "active" : "undeployed",
236
+ deployedAt: latestDeployment?.createdOn ?? worker.modifiedOn,
237
+ versionId: activeVersionId,
238
+ source: latestDeployment?.source,
239
+ url: getProductionUrl(family.baseName, workersSubdomain)
240
+ };
241
+ }));
242
+ }
243
+ function buildProductionColumns(theme) {
244
+ return [
245
+ {
246
+ label: "Worker",
247
+ width: 34,
248
+ value: (row) => row.workerName
249
+ },
250
+ {
251
+ label: "Role",
252
+ width: 18,
253
+ value: (row) => row.role
254
+ },
255
+ {
256
+ label: "Status",
257
+ width: 10,
258
+ value: (row) => formatWorkerStatus(row.status, theme)
259
+ },
260
+ {
261
+ label: "Deployed",
262
+ width: 19,
263
+ value: (row) => whiteDim(formatRecordDate(row.deployedAt), theme)
264
+ },
265
+ {
266
+ label: "Version",
267
+ width: 13,
268
+ value: (row) => row.versionId ? shortenVersionId(row.versionId) : dim("N/A", theme)
269
+ },
270
+ {
271
+ label: "Source",
272
+ width: 14,
273
+ value: (row) => row.source ?? dim("N/A", theme)
274
+ },
275
+ {
276
+ label: "URL",
277
+ value: (row) => row.url ?? "N/A"
278
+ }
279
+ ];
280
+ }
281
+ function buildVersionColumns(theme) {
282
+ return [
283
+ {
284
+ label: "Version",
285
+ width: 13,
286
+ value: (row) => shortenVersionId(row.versionId)
287
+ },
288
+ {
289
+ label: "Status",
290
+ width: 8,
291
+ value: (row) => formatVersionStatus(row.status, theme)
292
+ },
293
+ {
294
+ label: "Updated",
295
+ width: 19,
296
+ value: (row) => whiteDim(formatRecordDate(row.updatedAt), theme)
297
+ },
298
+ {
299
+ label: "Last deployed",
300
+ width: 19,
301
+ value: (row) => whiteDim(formatRecordDate(row.deployedAt), theme)
302
+ },
303
+ {
304
+ label: "Source",
305
+ value: (row) => row.source ?? dim("N/A", theme)
306
+ }
307
+ ];
308
+ }
309
+ async function loadWorkerVersionOverview(accountId, workerName, apiOptions) {
310
+ const [versions, deployments] = await Promise.all([
311
+ account.workerVersions(accountId, workerName, apiOptions),
312
+ account.workerDeployments(accountId, workerName, apiOptions)
313
+ ]);
314
+ const productionVersions = versions.filter((version) => version.id).filter((version) => version.metadata.hasPreview !== true).sort((left, right) => {
315
+ const leftTime = getWorkerVersionTimestamp(left)?.getTime() ?? 0;
316
+ const rightTime = getWorkerVersionTimestamp(right)?.getTime() ?? 0;
317
+ return rightTime - leftTime;
318
+ }).slice(0, VERSION_LIST_LIMIT);
319
+ const activeVersionIds = new Set((deployments[0]?.versions ?? []).map((version) => version.versionId));
320
+ const latestDeploymentByVersionId = new Map;
321
+ for (const deployment of deployments) {
322
+ for (const version of deployment.versions) {
323
+ const existing = latestDeploymentByVersionId.get(version.versionId);
324
+ if (!existing || deployment.createdOn.getTime() > existing.getTime()) {
325
+ latestDeploymentByVersionId.set(version.versionId, deployment.createdOn);
326
+ }
327
+ }
328
+ }
329
+ return {
330
+ workerName,
331
+ rows: productionVersions.map((version) => ({
332
+ versionId: version.id,
333
+ status: activeVersionIds.has(version.id) ? "active" : "stored",
334
+ updatedAt: getWorkerVersionTimestamp(version),
335
+ deployedAt: latestDeploymentByVersionId.get(version.id),
336
+ source: version.metadata.source
337
+ }))
338
+ };
339
+ }
340
+ function showProductionOverview(logger, context, rows, theme) {
341
+ logLine(logger);
342
+ if (context.discovery.primaryFamilyNames.length === 1) {
343
+ logLine(logger, formatLabelValue("worker family", green(context.discovery.primaryFamilyNames[0], theme), theme));
344
+ logLine(logger, formatLabelValue("related", whiteDim(String(Math.max(context.discovery.families.length - 1, 0)), theme), theme));
345
+ } else if (context.discovery.primaryFamilyNames.length > 1) {
346
+ logLine(logger, formatLabelValue("configured", whiteDim(`${context.discovery.primaryFamilyNames.length} primary workers`, theme), theme));
347
+ logLine(logger, formatLabelValue("tracked", whiteDim(`${context.discovery.families.length} workers`, theme), theme));
348
+ } else if (context.workerName) {
349
+ logLine(logger, formatLabelValue("worker", green(context.workerName, theme), theme));
350
+ }
351
+ if (rows.length === 0) {
352
+ logLine(logger);
353
+ logLine(logger, dim("No production Workers matched the current selection.", theme));
354
+ logLine(logger);
355
+ return;
356
+ }
357
+ logLine(logger);
358
+ logTable(logger, {
359
+ title: "Productions",
360
+ rows,
361
+ columns: buildProductionColumns(theme),
362
+ theme,
363
+ titleAccent: "green"
364
+ });
365
+ logLine(logger);
366
+ logLine(logger, dim("Use `devflare productions versions` for recent production versions, or `rollback` / `delete` to mutate one Worker.", theme));
367
+ logLine(logger);
368
+ }
369
+ function showWorkerVersions(logger, overviews, theme) {
370
+ logLine(logger);
371
+ if (overviews.length === 0) {
372
+ logLine(logger, dim("No production versions 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) {
378
+ logLine(logger);
379
+ }
380
+ logLine(logger, `${bold("worker", theme)} ${green(overview.workerName, theme)}`);
381
+ if (overview.rows.length === 0) {
382
+ logLine(logger, dim("No stored production versions were found for this Worker.", theme));
383
+ continue;
384
+ }
385
+ logTable(logger, {
386
+ title: "Versions",
387
+ rows: overview.rows,
388
+ columns: buildVersionColumns(theme),
389
+ theme,
390
+ titleAccent: "cyan"
391
+ });
392
+ }
393
+ logLine(logger);
394
+ }
395
+ async function runRollback(context, parsed, options, logger, theme) {
396
+ if (!context.workerName) {
397
+ logger.error("A worker name is required for production rollback.");
398
+ return { exitCode: 1 };
399
+ }
400
+ const versionId = asOptionalString(parsed.options.version) || asOptionalString(parsed.options["version-id"]);
401
+ const apply = parsed.options.apply === true;
402
+ if (!apply) {
403
+ logger.success(`Production rollback dry run complete for ${context.workerName}`);
404
+ logger.info(versionId ? `Would roll back ${context.workerName} to version ${versionId}` : `Would roll back ${context.workerName} to the previously deployed production version`);
405
+ return { exitCode: 0 };
406
+ }
407
+ const rollbackMessage = asOptionalString(parsed.options.message) ?? `Rolled back ${context.workerName} via devflare productions rollback`;
408
+ const rollbackArgs = ["wrangler", "rollback"];
409
+ if (versionId) {
410
+ rollbackArgs.push(versionId);
411
+ }
412
+ rollbackArgs.push("--name", context.workerName, "--message", rollbackMessage);
413
+ logLine(logger);
414
+ logLine(logger, `${cyanBold("productions rollback", theme)} ${dim(`Rolling back ${context.workerName}`, theme)}`);
415
+ const deps = await getDependencies();
416
+ const cwd = options.cwd ?? process.cwd();
417
+ const rollbackResult = await deps.exec.exec("bunx", rollbackArgs, {
418
+ cwd,
419
+ stdio: "inherit"
420
+ });
421
+ if (rollbackResult.exitCode !== 0) {
422
+ logger.error(`Rollback failed for ${context.workerName}`);
423
+ return { exitCode: 1 };
424
+ }
425
+ const deployments = await account.workerDeployments(context.accountId, context.workerName, CLI_API_OPTIONS);
426
+ const activeVersionId = deployments[0] ? selectDeploymentVersionId(deployments[0]) : undefined;
427
+ logger.success(`Rolled back production deployment for ${context.workerName}`);
428
+ if (activeVersionId) {
429
+ logger.info(`Active version: ${activeVersionId}`);
430
+ }
431
+ return { exitCode: 0 };
432
+ }
433
+ async function runDelete(context, parsed, logger) {
434
+ if (!context.workerName) {
435
+ logger.error("A worker name is required for production deletion.");
436
+ return { exitCode: 1 };
437
+ }
438
+ const apply = parsed.options.apply === true;
439
+ if (!apply) {
440
+ logger.success(`Production delete dry run complete for ${context.workerName}`);
441
+ logger.info(`Would delete Worker script ${context.workerName}`);
442
+ logger.warn("Deleting a production Worker script does not automatically delete KV, D1, R2, queue, or other account resources.");
443
+ return { exitCode: 0 };
444
+ }
445
+ await account.deleteWorker(context.accountId, context.workerName, CLI_API_OPTIONS);
446
+ logger.success(`Deleted production Worker script ${context.workerName}`);
447
+ logger.warn("Devflare deleted the Worker script only. Review any shared account resources separately before cleaning them up.");
448
+ return { exitCode: 0 };
449
+ }
450
+ async function runProductionsCommand(parsed, logger, options) {
451
+ const isAuth = await account.isAuthenticated();
452
+ if (!isAuth) {
453
+ logger.error("Not authenticated with Cloudflare");
454
+ logger.info("Run `devflare login` first.");
455
+ return { exitCode: 1 };
456
+ }
457
+ const rawSubcommand = parsed.args[0];
458
+ const fallbackWorkerArg = rawSubcommand && !isProductionSubcommand(rawSubcommand) ? rawSubcommand : parsed.args[1];
459
+ const subcommand = rawSubcommand && isProductionSubcommand(rawSubcommand) ? rawSubcommand : "list";
460
+ const theme = createCliTheme(parsed.options);
461
+ if (rawSubcommand && !isProductionSubcommand(rawSubcommand) && parsed.args.length > 2) {
462
+ logger.error(`Unknown productions subcommand: ${rawSubcommand}`);
463
+ logger.info(`Available productions subcommands: ${PRODUCTION_SUBCOMMANDS.join(", ")}`);
464
+ return { exitCode: 1 };
465
+ }
466
+ try {
467
+ const context = await resolveContext(parsed, options, subcommand, fallbackWorkerArg);
468
+ const selectedFamilies = context.discovery.families.length > 0 ? context.discovery.families : context.workerName ? [{ baseName: context.workerName, roleLabel: "selected worker", role: "primary" }] : [];
469
+ switch (subcommand) {
470
+ case "versions": {
471
+ const workerNames = Array.from(new Set(context.workerName ? [context.workerName] : selectedFamilies.map((family) => family.baseName))).sort((left, right) => left.localeCompare(right));
472
+ if (workerNames.length === 0) {
473
+ logger.error("No production Workers could be resolved. Use --worker or run inside a configured package.");
474
+ return { exitCode: 1 };
475
+ }
476
+ const overviews = await Promise.all(workerNames.map((workerName) => loadWorkerVersionOverview(context.accountId, workerName, CLI_API_OPTIONS)));
477
+ showWorkerVersions(logger, overviews, theme);
478
+ return { exitCode: 0 };
479
+ }
480
+ case "rollback":
481
+ return runRollback(context, parsed, options, logger, theme);
482
+ case "delete":
483
+ return runDelete(context, parsed, logger);
484
+ case "list":
485
+ default: {
486
+ if (selectedFamilies.length === 0) {
487
+ logger.error("No production Workers could be resolved. Use --worker, --config, or run inside a configured package.");
488
+ return { exitCode: 1 };
489
+ }
490
+ const rows = await buildProductionRows(context.accountId, selectedFamilies, CLI_API_OPTIONS);
491
+ showProductionOverview(logger, context, rows, theme);
492
+ return { exitCode: 0 };
493
+ }
494
+ }
495
+ } catch (error) {
496
+ if (error instanceof Error) {
497
+ logger.error(error.message);
498
+ return { exitCode: 1 };
499
+ }
500
+ throw error;
501
+ }
502
+ }
503
+ export {
504
+ runProductionsCommand
505
+ };