wrangler 0.0.0-e7a0cd5b → 0.0.0-e7cf0caa

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 (237) hide show
  1. package/README.md +3 -3
  2. package/bin/wrangler.js +30 -10
  3. package/miniflare-dist/index.mjs +126 -74
  4. package/package.json +27 -19
  5. package/src/__tests__/api-dev.test.ts +65 -36
  6. package/src/__tests__/api-devregistry.test.ts +121 -0
  7. package/src/__tests__/api.test.ts +27 -5
  8. package/src/__tests__/configuration.test.ts +567 -86
  9. package/src/__tests__/d1/d1.test.ts +82 -0
  10. package/src/__tests__/d1/execute.test.ts +66 -0
  11. package/src/__tests__/d1/migrate.test.ts +157 -0
  12. package/src/__tests__/d1/splitter.test.ts +255 -0
  13. package/src/__tests__/delete.test.ts +91 -49
  14. package/src/__tests__/deployments.test.ts +330 -56
  15. package/src/__tests__/dev.test.tsx +198 -90
  16. package/src/__tests__/generate.test.ts +12 -10
  17. package/src/__tests__/guess-worker-format.test.ts +35 -0
  18. package/src/__tests__/helpers/end-event-loop.ts +6 -0
  19. package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
  20. package/src/__tests__/helpers/mock-console.ts +6 -0
  21. package/src/__tests__/helpers/mock-dialogs.ts +71 -85
  22. package/src/__tests__/helpers/mock-get-pages-upload-token.ts +25 -0
  23. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -5
  24. package/src/__tests__/helpers/mock-known-routes.ts +7 -2
  25. package/src/__tests__/helpers/mock-kv.ts +29 -16
  26. package/src/__tests__/helpers/mock-oauth-flow.ts +103 -92
  27. package/src/__tests__/helpers/mock-process.ts +8 -13
  28. package/src/__tests__/helpers/mock-set-timeout.ts +16 -0
  29. package/src/__tests__/helpers/msw/blob-worker.cjs +19 -0
  30. package/src/__tests__/helpers/msw/handlers/deployments.ts +128 -27
  31. package/src/__tests__/helpers/msw/handlers/namespaces.ts +18 -41
  32. package/src/__tests__/helpers/msw/handlers/oauth.ts +13 -18
  33. package/src/__tests__/helpers/msw/handlers/r2.ts +14 -34
  34. package/src/__tests__/helpers/msw/handlers/script.ts +9 -28
  35. package/src/__tests__/helpers/msw/handlers/user.ts +13 -24
  36. package/src/__tests__/helpers/msw/handlers/zones.ts +6 -8
  37. package/src/__tests__/helpers/msw/index.ts +32 -1
  38. package/src/__tests__/helpers/msw/read-file-sync.js +61 -0
  39. package/src/__tests__/helpers/string-dynamic-values-matcher.ts +28 -0
  40. package/src/__tests__/helpers/worker-scripts/parent-worker.js +4 -1
  41. package/src/__tests__/index.test.ts +90 -72
  42. package/src/__tests__/init.test.ts +927 -631
  43. package/src/__tests__/jest.setup.ts +19 -42
  44. package/src/__tests__/kv.test.ts +355 -231
  45. package/src/__tests__/logger.test.ts +68 -2
  46. package/src/__tests__/logout.test.ts +47 -0
  47. package/src/__tests__/metrics.test.ts +94 -51
  48. package/src/__tests__/middleware.scheduled.test.ts +42 -32
  49. package/src/__tests__/middleware.test.ts +212 -122
  50. package/src/__tests__/mtls-certificates.test.ts +588 -0
  51. package/src/__tests__/pages/deployment-list.test.ts +80 -0
  52. package/src/__tests__/pages/functions-build.test.ts +452 -0
  53. package/src/__tests__/pages/pages.test.ts +81 -0
  54. package/src/__tests__/pages/project-create.test.ts +63 -0
  55. package/src/__tests__/pages/project-list.test.ts +110 -0
  56. package/src/__tests__/pages/project-upload.test.ts +500 -0
  57. package/src/__tests__/pages/publish.test.ts +2864 -0
  58. package/src/__tests__/pages-deployment-tail.test.ts +955 -0
  59. package/src/__tests__/parse.test.ts +106 -0
  60. package/src/__tests__/publish.test.ts +1615 -852
  61. package/src/__tests__/pubsub.test.ts +226 -100
  62. package/src/__tests__/queues.test.ts +238 -77
  63. package/src/__tests__/r2.test.ts +55 -57
  64. package/src/__tests__/secret.test.ts +179 -130
  65. package/src/__tests__/tail.test.ts +267 -109
  66. package/src/__tests__/test-old-node-version.js +3 -3
  67. package/src/__tests__/traverse-module-graph.test.ts +220 -0
  68. package/src/__tests__/tsconfig-sanity.ts +12 -0
  69. package/src/__tests__/tsconfig.json +8 -0
  70. package/src/__tests__/tsconfig.tsbuildinfo +1 -0
  71. package/src/__tests__/type-generation.test.ts +43 -26
  72. package/src/__tests__/user.test.ts +35 -72
  73. package/src/__tests__/whoami.test.tsx +8 -114
  74. package/src/__tests__/worker-namespace.test.ts +83 -69
  75. package/src/api/dev.ts +168 -60
  76. package/src/api/index.ts +10 -1
  77. package/src/api/mtls-certificate.ts +148 -0
  78. package/src/api/pages/create-worker-bundle-contents.ts +76 -0
  79. package/src/api/pages/index.ts +5 -0
  80. package/src/api/pages/publish.tsx +355 -0
  81. package/src/bundle.ts +263 -140
  82. package/src/cfetch/index.ts +0 -2
  83. package/src/cfetch/internal.ts +16 -21
  84. package/src/cli.ts +4 -4
  85. package/src/config/config.ts +14 -7
  86. package/src/config/environment.ts +79 -24
  87. package/src/config/index.ts +99 -38
  88. package/src/config/validation-helpers.ts +1 -1
  89. package/src/config/validation.ts +248 -19
  90. package/src/create-worker-preview.ts +19 -8
  91. package/src/create-worker-upload-form.ts +60 -22
  92. package/src/d1/backups.tsx +43 -42
  93. package/src/d1/constants.ts +2 -0
  94. package/src/d1/create.tsx +44 -30
  95. package/src/d1/{delete.tsx → delete.ts} +11 -14
  96. package/src/d1/execute.tsx +209 -151
  97. package/src/d1/index.ts +31 -7
  98. package/src/d1/list.tsx +22 -10
  99. package/src/d1/migrations/apply.tsx +212 -0
  100. package/src/d1/migrations/create.tsx +79 -0
  101. package/src/d1/migrations/helpers.ts +172 -0
  102. package/src/d1/migrations/index.ts +3 -0
  103. package/src/d1/migrations/list.tsx +95 -0
  104. package/src/d1/migrations/options.ts +23 -0
  105. package/src/d1/options.ts +12 -2
  106. package/src/d1/splitter.ts +161 -0
  107. package/src/d1/{types.tsx → types.ts} +11 -0
  108. package/src/d1/utils.ts +12 -2
  109. package/src/delete.ts +8 -16
  110. package/src/deployments.ts +340 -46
  111. package/src/deprecated/index.ts +8 -302
  112. package/src/dev/dev.tsx +57 -44
  113. package/src/dev/local.tsx +294 -91
  114. package/src/dev/remote.tsx +32 -3
  115. package/src/dev/start-server.ts +89 -68
  116. package/src/dev/use-esbuild.ts +17 -18
  117. package/src/dev/validate-dev-props.ts +9 -0
  118. package/src/{dev-registry.tsx → dev-registry.ts} +2 -1
  119. package/src/dev.tsx +178 -118
  120. package/src/dialogs.ts +136 -0
  121. package/src/dispatch-namespace.ts +21 -17
  122. package/src/docs/index.ts +97 -0
  123. package/src/entry.ts +19 -11
  124. package/src/environment-variables/factory.ts +88 -0
  125. package/src/environment-variables/misc-variables.ts +30 -0
  126. package/src/generate/index.ts +298 -0
  127. package/src/git-client.ts +15 -4
  128. package/src/{index.tsx → index.ts} +137 -63
  129. package/src/init.ts +249 -187
  130. package/src/inspect.ts +16 -1
  131. package/src/jest.d.ts +4 -0
  132. package/src/kv/index.ts +15 -17
  133. package/src/logger.ts +32 -5
  134. package/src/metrics/metrics-config.ts +3 -3
  135. package/src/metrics/send-event.ts +6 -1
  136. package/src/miniflare-cli/assets.ts +64 -28
  137. package/src/miniflare-cli/index.ts +4 -7
  138. package/src/miniflare-cli/tsconfig.json +9 -0
  139. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
  140. package/src/miniflare-cli/types.ts +11 -0
  141. package/src/module-collection.ts +91 -25
  142. package/src/mtls-certificate/cli.ts +155 -0
  143. package/src/pages/build.ts +410 -0
  144. package/src/pages/buildFunctions.ts +140 -0
  145. package/src/pages/deployment-tails.ts +281 -0
  146. package/src/pages/deployments.tsx +11 -33
  147. package/src/pages/{dev.tsx → dev.ts} +147 -124
  148. package/src/pages/errors.ts +1 -0
  149. package/src/pages/functions/buildPlugin.ts +72 -69
  150. package/src/pages/functions/buildWorker.ts +249 -114
  151. package/src/pages/functions/tsconfig.json +8 -0
  152. package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
  153. package/src/pages/{functions.tsx → functions.ts} +8 -4
  154. package/src/pages/{index.tsx → index.ts} +11 -3
  155. package/src/pages/projects.tsx +12 -22
  156. package/src/pages/prompt-select-project.tsx +31 -0
  157. package/src/pages/publish.tsx +45 -214
  158. package/src/pages/types.ts +6 -9
  159. package/src/pages/upload.tsx +58 -14
  160. package/src/pages/utils.ts +14 -3
  161. package/src/parse.ts +23 -1
  162. package/src/paths.ts +1 -1
  163. package/src/proxy.ts +5 -0
  164. package/src/publish/index.ts +20 -16
  165. package/src/publish/publish.ts +72 -47
  166. package/src/pubsub/{pubsub-commands.tsx → pubsub-commands.ts} +19 -20
  167. package/src/queues/cli/commands/consumer/add.ts +24 -24
  168. package/src/queues/cli/commands/consumer/index.ts +3 -6
  169. package/src/queues/cli/commands/consumer/remove.ts +11 -18
  170. package/src/queues/cli/commands/create.ts +8 -8
  171. package/src/queues/cli/commands/delete.ts +8 -8
  172. package/src/queues/cli/commands/index.ts +6 -4
  173. package/src/queues/cli/commands/list.ts +8 -8
  174. package/src/queues/client.ts +1 -0
  175. package/src/queues/utils.ts +18 -0
  176. package/src/r2/constants.ts +4 -0
  177. package/src/r2/helpers.ts +1 -0
  178. package/src/r2/index.ts +40 -28
  179. package/src/secret/index.ts +14 -17
  180. package/src/{sites.tsx → sites.ts} +1 -1
  181. package/src/tail/createTail.ts +94 -3
  182. package/src/tail/filters.ts +1 -1
  183. package/src/tail/index.ts +8 -11
  184. package/src/tail/printing.ts +15 -0
  185. package/src/traverse-module-graph.ts +53 -0
  186. package/src/tsconfig-sanity.ts +16 -0
  187. package/src/type-generation.ts +79 -57
  188. package/src/user/access.ts +0 -1
  189. package/src/user/auth-variables.ts +113 -0
  190. package/src/user/choose-account.tsx +1 -31
  191. package/src/user/index.ts +0 -1
  192. package/src/user/{user.tsx → user.ts} +123 -82
  193. package/src/utils/render.ts +93 -0
  194. package/src/{whoami.tsx → whoami.ts} +37 -71
  195. package/src/worker.ts +35 -3
  196. package/src/yargs-types.ts +22 -5
  197. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  198. package/templates/__tests__/tsconfig.json +8 -0
  199. package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
  200. package/templates/checked-fetch.js +9 -3
  201. package/templates/d1-beta-facade.js +95 -25
  202. package/templates/facade.d.ts +14 -0
  203. package/templates/first-party-worker-module-facade.ts +4 -3
  204. package/templates/format-dev-errors.ts +8 -6
  205. package/templates/gitignore +1 -0
  206. package/templates/init-tests/test-jest-new-worker.js +3 -5
  207. package/templates/init-tests/test-vitest-new-worker.js +3 -5
  208. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  209. package/templates/middleware/loader-modules.ts +2 -2
  210. package/templates/middleware/loader-sw.ts +51 -31
  211. package/templates/middleware/middleware-miniflare3-json-error.ts +32 -0
  212. package/templates/new-worker.ts +3 -0
  213. package/templates/pages-dev-pipeline.ts +4 -1
  214. package/templates/pages-shim.ts +4 -1
  215. package/templates/pages-template-plugin.ts +19 -10
  216. package/templates/serve-static-assets.ts +17 -14
  217. package/templates/service-bindings-module-facade.js +1 -0
  218. package/templates/tsconfig-sanity.ts +11 -0
  219. package/templates/tsconfig.init.json +105 -0
  220. package/templates/tsconfig.json +5 -103
  221. package/templates/tsconfig.tsbuildinfo +1 -0
  222. package/wrangler-dist/cli.d.ts +826 -77
  223. package/wrangler-dist/cli.js +130734 -140838
  224. package/wrangler-dist/wasm-sync.wasm +0 -0
  225. package/src/__tests__/api-devregistry.test.js +0 -57
  226. package/src/__tests__/d1.test.ts +0 -72
  227. package/src/__tests__/dialogs.test.tsx +0 -40
  228. package/src/__tests__/helpers/mock-cfetch.ts +0 -333
  229. package/src/__tests__/pages.test.ts +0 -2223
  230. package/src/dialogs.tsx +0 -163
  231. package/src/environment-variables.ts +0 -50
  232. package/src/pages/build.tsx +0 -238
  233. package/src/user/env-vars.ts +0 -46
  234. package/templates/experimental-local-cache-stubs.js +0 -27
  235. /package/src/{bundle-reporter.tsx → bundle-reporter.ts} +0 -0
  236. /package/src/dev/{get-local-persistence-path.tsx → get-local-persistence-path.ts} +0 -0
  237. /package/src/pages/{hash.tsx → hash.ts} +0 -0
@@ -0,0 +1,161 @@
1
+ /**
2
+ * @module
3
+ * This code is inspired by that of https://www.atdatabases.org/docs/split-sql-query, which is published under MIT license,
4
+ * and is Copyright (c) 2019 Forbes Lindesay.
5
+ *
6
+ * See https://github.com/ForbesLindesay/atdatabases/blob/103c1e7/packages/split-sql-query/src/index.ts
7
+ * for the original code.
8
+ */
9
+
10
+ /**
11
+ * Is the given `sql` string likely to contain multiple statements.
12
+ *
13
+ * If `mayContainMultipleStatements()` returns `false` you can be confident that the sql
14
+ * does not contain multiple statements. Otherwise you have to check further.
15
+ */
16
+ export function mayContainMultipleStatements(sql: string): boolean {
17
+ const trimmed = sql.trimEnd();
18
+ const semiColonIndex = trimmed.indexOf(";");
19
+ return semiColonIndex !== -1 && semiColonIndex !== trimmed.length - 1;
20
+ }
21
+
22
+ /**
23
+ * Split an SQLQuery into an array of statements
24
+ */
25
+ export default function splitSqlQuery(sql: string): string[] {
26
+ if (!mayContainMultipleStatements(sql)) return [sql];
27
+ const split = splitSqlIntoStatements(sql);
28
+ if (split.length === 0) {
29
+ return [sql];
30
+ } else {
31
+ return split;
32
+ }
33
+ }
34
+
35
+ function splitSqlIntoStatements(sql: string): string[] {
36
+ const statements: string[] = [];
37
+ let str = "";
38
+ const compoundStatementStack: ((s: string) => boolean)[] = [];
39
+
40
+ const iterator = sql[Symbol.iterator]();
41
+ let next = iterator.next();
42
+ while (!next.done) {
43
+ const char = next.value;
44
+
45
+ if (compoundStatementStack[0]?.(str + char)) {
46
+ compoundStatementStack.shift();
47
+ }
48
+
49
+ switch (char) {
50
+ case `'`:
51
+ case `"`:
52
+ case "`":
53
+ str += char + consumeUntilMarker(iterator, char);
54
+ break;
55
+ case `$`: {
56
+ const dollarQuote =
57
+ "$" + consumeWhile(iterator, isDollarQuoteIdentifier);
58
+ str += dollarQuote;
59
+ if (dollarQuote.endsWith("$")) {
60
+ str += consumeUntilMarker(iterator, dollarQuote);
61
+ }
62
+ break;
63
+ }
64
+ case `-`:
65
+ str += char;
66
+ next = iterator.next();
67
+ if (!next.done && next.value === "-") {
68
+ str += next.value + consumeUntilMarker(iterator, "\n");
69
+ break;
70
+ } else {
71
+ continue;
72
+ }
73
+ case `/`:
74
+ str += char;
75
+ next = iterator.next();
76
+ if (!next.done && next.value === "*") {
77
+ str += next.value + consumeUntilMarker(iterator, "*/");
78
+ break;
79
+ } else {
80
+ continue;
81
+ }
82
+ case `;`:
83
+ if (compoundStatementStack.length === 0) {
84
+ statements.push(str);
85
+ str = "";
86
+ } else {
87
+ str += char;
88
+ }
89
+ break;
90
+ default:
91
+ str += char;
92
+ break;
93
+ }
94
+
95
+ if (isCompoundStatementStart(str)) {
96
+ compoundStatementStack.unshift(isCompoundStatementEnd);
97
+ }
98
+
99
+ next = iterator.next();
100
+ }
101
+ statements.push(str);
102
+
103
+ return statements
104
+ .map((statement) => statement.trim())
105
+ .filter((statement) => statement.length > 0);
106
+ }
107
+
108
+ /**
109
+ * Pulls characters from the string iterator while the predicate remains true.
110
+ */
111
+ function consumeWhile(
112
+ iterator: Iterator<string>,
113
+ predicate: (str: string) => boolean
114
+ ) {
115
+ let next = iterator.next();
116
+ let str = "";
117
+ while (!next.done) {
118
+ str += next.value;
119
+ if (!predicate(str)) {
120
+ break;
121
+ }
122
+ next = iterator.next();
123
+ }
124
+ return str;
125
+ }
126
+
127
+ /**
128
+ * Pulls characters from the string iterator until the `endMarker` is found.
129
+ */
130
+ function consumeUntilMarker(iterator: Iterator<string>, endMarker: string) {
131
+ return consumeWhile(iterator, (str) => !str.endsWith(endMarker));
132
+ }
133
+
134
+ /**
135
+ * Returns true if the `str` ends with a dollar-quoted string marker.
136
+ * See https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING.
137
+ */
138
+ function isDollarQuoteIdentifier(str: string) {
139
+ const lastChar = str.slice(-1);
140
+ return (
141
+ // The $ marks the end of the identifier
142
+ lastChar !== "$" &&
143
+ // we allow numbers, underscore and letters with diacritical marks
144
+ (/[0-9_]/i.test(lastChar) ||
145
+ lastChar.toLowerCase() !== lastChar.toUpperCase())
146
+ );
147
+ }
148
+
149
+ /**
150
+ * Returns true if the `str` ends with a compound statement `BEGIN` marker.
151
+ */
152
+ function isCompoundStatementStart(str: string) {
153
+ return /\sBEGIN\s$/.test(str);
154
+ }
155
+
156
+ /**
157
+ * Returns true if the `str` ends with a compound statement `END` marker.
158
+ */
159
+ function isCompoundStatementEnd(str: string) {
160
+ return /\sEND[;\s]$/.test(str);
161
+ }
@@ -1,6 +1,11 @@
1
1
  export type Database = {
2
2
  uuid: string;
3
+ previewDatabaseUuid?: string;
3
4
  name: string;
5
+ binding: string;
6
+ internal_env?: string;
7
+ migrationsTableName: string;
8
+ migrationsFolderPath: string;
4
9
  };
5
10
 
6
11
  export type Backup = {
@@ -12,3 +17,9 @@ export type Backup = {
12
17
  file_size: number;
13
18
  size?: string;
14
19
  };
20
+
21
+ export type Migration = {
22
+ id: string;
23
+ name: string;
24
+ applied_at: string;
25
+ };
package/src/d1/utils.ts CHANGED
@@ -1,8 +1,12 @@
1
+ import { DEFAULT_MIGRATION_PATH, DEFAULT_MIGRATION_TABLE } from "./constants";
1
2
  import { listDatabases } from "./list";
2
3
  import type { Config } from "../config";
3
4
  import type { Database } from "./types";
4
5
 
5
- export function getDatabaseInfoFromConfig(config: Config, name: string) {
6
+ export function getDatabaseInfoFromConfig(
7
+ config: Config,
8
+ name: string
9
+ ): Database | null {
6
10
  for (const d1Database of config.d1_databases) {
7
11
  if (
8
12
  d1Database.database_id &&
@@ -10,8 +14,14 @@ export function getDatabaseInfoFromConfig(config: Config, name: string) {
10
14
  ) {
11
15
  return {
12
16
  uuid: d1Database.database_id,
17
+ previewDatabaseUuid: d1Database.preview_database_id,
13
18
  binding: d1Database.binding,
14
19
  name: d1Database.database_name,
20
+ migrationsTableName:
21
+ d1Database.migrations_table || DEFAULT_MIGRATION_TABLE,
22
+ migrationsFolderPath:
23
+ d1Database.migrations_dir || DEFAULT_MIGRATION_PATH,
24
+ internal_env: d1Database.database_internal_env,
15
25
  };
16
26
  }
17
27
  }
@@ -36,4 +46,4 @@ export const getDatabaseByNameOrBinding = async (
36
46
 
37
47
  export const d1BetaWarning = process.env.NO_D1_WARNING
38
48
  ? ""
39
- : "🚧 'wrangler d1 <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose";
49
+ : "--------------------\n🚧 D1 is currently in open alpha and is not recommended for production data and traffic\n🚧 Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose\n🚧 To request features, visit https://community.cloudflare.com/c/developers/d1\n🚧 To give feedback, visit https://discord.gg/cloudflaredev\n--------------------\n";
package/src/delete.ts CHANGED
@@ -3,21 +3,17 @@ import path from "path";
3
3
  import { fetchResult } from "./cfetch";
4
4
  import { findWranglerToml, readConfig } from "./config";
5
5
  import { confirm } from "./dialogs";
6
- import { CI } from "./is-ci";
7
- import isInteractive from "./is-interactive";
8
6
  import { deleteKVNamespace, listKVNamespaces } from "./kv/helpers";
9
7
  import { logger } from "./logger";
10
8
  import * as metrics from "./metrics";
11
9
  import { requireAuth } from "./user";
12
10
  import { getScriptName, printWranglerBanner } from "./index";
13
- import type { ConfigPath } from "./index";
14
11
  import type {
15
- CommonYargsOptions,
16
- YargsOptionsToInterface,
12
+ CommonYargsArgv,
13
+ StrictYargsOptionsToInterface,
17
14
  } from "./yargs-types";
18
- import type { Argv } from "yargs";
19
15
 
20
- export function deleteOptions(yargs: Argv<CommonYargsOptions>) {
16
+ export function deleteOptions(yargs: CommonYargsArgv) {
21
17
  return yargs
22
18
  .positional("script", {
23
19
  describe: "The path to an entry point for your worker",
@@ -40,14 +36,13 @@ export function deleteOptions(yargs: Argv<CommonYargsOptions>) {
40
36
  });
41
37
  }
42
38
 
43
- type DeleteArgs = YargsOptionsToInterface<typeof deleteOptions>;
39
+ type DeleteArgs = StrictYargsOptionsToInterface<typeof deleteOptions>;
44
40
 
45
41
  export async function deleteHandler(args: DeleteArgs) {
46
42
  await printWranglerBanner();
47
43
 
48
44
  const configPath =
49
- (args.config as ConfigPath) ||
50
- (args.script && findWranglerToml(path.dirname(args.script)));
45
+ args.config || (args.script && findWranglerToml(path.dirname(args.script)));
51
46
  const config = readConfig(configPath, args);
52
47
  await metrics.sendMetricsEvent(
53
48
  "delete worker script",
@@ -71,12 +66,9 @@ export async function deleteHandler(args: DeleteArgs) {
71
66
 
72
67
  assert(accountId, "Missing accountId");
73
68
 
74
- let confirmed = true;
75
- if (isInteractive() || !CI.isCI()) {
76
- confirmed = await confirm(
77
- `Are you sure you want to delete ${scriptName}? This action cannot be undone.`
78
- );
79
- }
69
+ const confirmed = await confirm(
70
+ `Are you sure you want to delete ${scriptName}? This action cannot be undone.`
71
+ );
80
72
 
81
73
  if (confirmed) {
82
74
  await fetchResult(
@@ -1,74 +1,368 @@
1
+ import { URLSearchParams } from "url";
2
+ import TOML from "@iarna/toml";
3
+ import chalk from "chalk";
4
+ import { FormData } from "undici";
1
5
  import { fetchResult } from "./cfetch";
6
+ import { readConfig } from "./config";
7
+ import { confirm, prompt } from "./dialogs";
8
+ import { mapBindings } from "./init";
2
9
  import { logger } from "./logger";
10
+ import * as metrics from "./metrics";
11
+ import { requireAuth } from "./user";
12
+ import { getScriptName, printWranglerBanner } from ".";
13
+
14
+ import type { Config } from "./config";
15
+ import type { WorkerMetadataBinding } from "./create-worker-upload-form";
3
16
  import type { ServiceMetadataRes } from "./init";
17
+ import type { CommonYargsOptions } from "./yargs-types";
18
+ import type { ArgumentsCamelCase } from "yargs";
4
19
 
5
- export type DeploymentListRes = {
6
- latest: {
7
- id: string;
8
- number: string;
9
- metadata: {
10
- author_id: string;
11
- author_email: string;
12
- source: "api" | "dash" | "wrangler" | "terraform" | "other";
13
- created_on: string;
14
- modified_on: string;
20
+ type DeploymentDetails = {
21
+ id: string;
22
+ number: string;
23
+ annotations: {
24
+ "workers/triggered_by": string;
25
+ "workers/rollback_from": string;
26
+ "workers/message": string;
27
+ };
28
+ metadata: {
29
+ author_id: string;
30
+ author_email: string;
31
+ source: "api" | "dash" | "wrangler" | "terraform" | "other";
32
+ created_on: string;
33
+ modified_on: string;
34
+ };
35
+ resources: {
36
+ script: {
37
+ handlers: string[];
15
38
  };
16
- resources: {
17
- script: string;
18
- bindings: unknown[];
39
+ bindings: WorkerMetadataBinding[];
40
+ script_runtime: {
41
+ compatibility_date: string | undefined;
42
+ compatibility_flags: string[] | undefined;
43
+ usage_model: string | undefined;
19
44
  };
20
45
  };
21
- items: {
22
- id: string;
23
- number: string;
24
- metadata: {
25
- author_id: string;
26
- author_email: string;
27
- source: "api" | "dash" | "wrangler" | "terraform" | "other";
28
- created_on: string;
29
- modified_on: string;
30
- };
31
- }[];
46
+ };
47
+
48
+ export type DeploymentListResult = {
49
+ latest: DeploymentDetails;
50
+ items: DeploymentDetails[];
32
51
  };
33
52
 
34
53
  export async function deployments(
35
54
  accountId: string,
36
- scriptName: string | undefined
55
+ scriptName: string | undefined,
56
+ { send_metrics: sendMetrics }: { send_metrics?: Config["send_metrics"] } = {}
37
57
  ) {
38
- const scriptMetadata = await fetchResult<ServiceMetadataRes>(
39
- `/accounts/${accountId}/workers/services/${scriptName}`
40
- );
58
+ if (!scriptName) {
59
+ throw new Error(
60
+ "Required Worker name missing. Please specify the Worker name in wrangler.toml, or pass it as an argument with `--name`"
61
+ );
62
+ }
41
63
 
42
- const scriptTag = scriptMetadata.default_environment.script.tag;
43
- const { items: deploys } = await fetchResult<DeploymentListRes>(
44
- `/accounts/${accountId}/workers/versions/by-script/${scriptTag}`
64
+ await metrics.sendMetricsEvent(
65
+ "view deployments",
66
+ { view: scriptName ? "single" : "all" },
67
+ {
68
+ sendMetrics,
69
+ }
45
70
  );
46
71
 
47
- const versionMessages = deploys.map(
48
- (versions) =>
49
- `\nDeployment ID: ${versions.id}
50
- Deployment number: ${versions.number}
51
- Created on: ${versions.metadata.created_on}
52
- Author: ${versions.metadata.author_email}
53
- Source: ${sourceStr(versions.metadata.source)}\n`
72
+ const scriptTag = (
73
+ await fetchResult<ServiceMetadataRes>(
74
+ `/accounts/${accountId}/workers/services/${scriptName}`
75
+ )
76
+ ).default_environment.script.tag;
77
+
78
+ const params = new URLSearchParams({ order: "asc" });
79
+ const { items: deploys } = await fetchResult<DeploymentListResult>(
80
+ `/accounts/${accountId}/workers/deployments/by-script/${scriptTag}`,
81
+ undefined,
82
+ params
54
83
  );
55
84
 
56
- versionMessages[0] += "🟩Active";
57
- logger.log(...versionMessages.reverse());
85
+ const versionMessages = deploys.map((versions) => {
86
+ const triggerStr = versions.annotations?.["workers/triggered_by"]
87
+ ? `${formatTrigger(
88
+ versions.annotations["workers/triggered_by"]
89
+ )} from ${formatSource(versions.metadata.source)}`
90
+ : `${formatSource(versions.metadata.source)}`;
91
+
92
+ let version = `
93
+ Deployment ID: ${versions.id}
94
+ Created on: ${versions.metadata.created_on}
95
+ Author: ${versions.metadata.author_email}
96
+ Source: ${triggerStr}`;
97
+
98
+ if (versions.annotations?.["workers/rollback_from"]) {
99
+ version += `\nRollback from: ${versions.annotations["workers/rollback_from"]}`;
100
+ }
101
+
102
+ if (versions.annotations?.["workers/message"]) {
103
+ version += `\nMessage: ${versions.annotations["workers/message"]}`;
104
+ }
105
+
106
+ return version + `\n`;
107
+ });
108
+
109
+ versionMessages[versionMessages.length - 1] += "🟩 Active";
110
+ logger.log(...versionMessages);
58
111
  }
59
112
 
60
- // TODO Include emoji/icon for each source
61
- function sourceStr(source: string): string {
113
+ function formatSource(source: string): string {
62
114
  switch (source) {
63
115
  case "api":
64
- return "API";
116
+ return "API 📡";
65
117
  case "dash":
66
- return "Dashboard";
118
+ return "Dashboard 🖥️";
67
119
  case "wrangler":
68
- return "Wrangler";
120
+ return "Wrangler 🤠";
69
121
  case "terraform":
70
- return "Terraform";
122
+ return "Terraform 🏗️";
71
123
  default:
72
124
  return "Other";
73
125
  }
74
126
  }
127
+ function formatTrigger(trigger: string): string {
128
+ switch (trigger) {
129
+ case "upload":
130
+ return "Upload";
131
+ case "secret":
132
+ return "Secret Change";
133
+ case "rollback":
134
+ return "Rollback";
135
+ case "promotion":
136
+ return "Promotion";
137
+ default:
138
+ return "Unknown";
139
+ }
140
+ }
141
+
142
+ export async function rollbackDeployment(
143
+ accountId: string,
144
+ scriptName: string | undefined,
145
+ { send_metrics: sendMetrics }: { send_metrics?: Config["send_metrics"] } = {},
146
+ deploymentId: string | undefined,
147
+ message: string | undefined
148
+ ) {
149
+ if (deploymentId === undefined) {
150
+ const scriptTag = (
151
+ await fetchResult<ServiceMetadataRes>(
152
+ `/accounts/${accountId}/workers/services/${scriptName}`
153
+ )
154
+ ).default_environment.script.tag;
155
+
156
+ const params = new URLSearchParams({ order: "asc" });
157
+ const { items: deploys } = await fetchResult<DeploymentListResult>(
158
+ `/accounts/${accountId}/workers/deployments/by-script/${scriptTag}`,
159
+ undefined,
160
+ params
161
+ );
162
+
163
+ if (deploys.length < 2) {
164
+ throw new Error(
165
+ "Cannot rollback to previous deployment since there are less than 2 deployemnts"
166
+ );
167
+ }
168
+
169
+ deploymentId = deploys.at(-2)?.id;
170
+ if (deploymentId === undefined) {
171
+ throw new Error("Cannot find previous deployment");
172
+ }
173
+ }
174
+
175
+ const firstHash = deploymentId.substring(0, deploymentId.indexOf("-"));
176
+
177
+ let rollbackMessage = "";
178
+ if (message !== undefined) {
179
+ rollbackMessage = message;
180
+ } else {
181
+ if (
182
+ !(await confirm(
183
+ `This deployment ${chalk.underline(
184
+ firstHash
185
+ )} will immediately replace the current deployment and become the active deployment across all your deployed routes and domains. However, your local development environment will not be affected by this rollback. ${chalk.blue.bold(
186
+ "Note:"
187
+ )} Rolling back to a previous deployment will not rollback any of the bound resources (Durable Object, R2, KV, etc.).`
188
+ ))
189
+ ) {
190
+ return;
191
+ }
192
+
193
+ rollbackMessage = await prompt(
194
+ "Please provide a message for this rollback (120 characters max)",
195
+ { defaultValue: "" }
196
+ );
197
+ }
198
+
199
+ let deployment_id = await rollbackRequest(
200
+ accountId,
201
+ scriptName,
202
+ deploymentId,
203
+ rollbackMessage
204
+ );
205
+
206
+ await metrics.sendMetricsEvent(
207
+ "rollback deployments",
208
+ { view: scriptName ? "single" : "all" },
209
+ {
210
+ sendMetrics,
211
+ }
212
+ );
213
+
214
+ deploymentId = addHyphens(deploymentId) ?? deploymentId;
215
+ deployment_id = addHyphens(deployment_id) ?? deployment_id;
216
+
217
+ logger.log(`\nSuccessfully rolled back to Deployment ID: ${deploymentId}`);
218
+ logger.log("Current Deployment ID:", deployment_id);
219
+ }
220
+
221
+ async function rollbackRequest(
222
+ accountId: string,
223
+ scriptName: string | undefined,
224
+ deploymentId: string,
225
+ rollbackReason: string
226
+ ): Promise<string | null> {
227
+ const body = new FormData();
228
+ body.set("message", rollbackReason);
229
+
230
+ const { deployment_id } = await fetchResult<{
231
+ deployment_id: string | null;
232
+ }>(
233
+ `/accounts/${accountId}/workers/scripts/${scriptName}?rollback_to=${deploymentId}`,
234
+ {
235
+ method: "PUT",
236
+ body,
237
+ }
238
+ );
239
+
240
+ return deployment_id;
241
+ }
242
+
243
+ export async function viewDeployment(
244
+ accountId: string,
245
+ scriptName: string | undefined,
246
+ { send_metrics: sendMetrics }: { send_metrics?: Config["send_metrics"] } = {},
247
+ deploymentId: string | undefined
248
+ ) {
249
+ await metrics.sendMetricsEvent(
250
+ "view deployments",
251
+ { view: scriptName ? "single" : "all" },
252
+ {
253
+ sendMetrics,
254
+ }
255
+ );
256
+
257
+ const scriptTag = (
258
+ await fetchResult<ServiceMetadataRes>(
259
+ `/accounts/${accountId}/workers/services/${scriptName}`
260
+ )
261
+ ).default_environment.script.tag;
262
+
263
+ if (deploymentId === undefined) {
264
+ const params = new URLSearchParams({ order: "asc" });
265
+ const { latest } = await fetchResult<DeploymentListResult>(
266
+ `/accounts/${accountId}/workers/deployments/by-script/${scriptTag}`,
267
+ undefined,
268
+ params
269
+ );
270
+
271
+ deploymentId = latest.id;
272
+ if (deploymentId === undefined) {
273
+ throw new Error("Cannot find previous deployment");
274
+ }
275
+ }
276
+
277
+ const deploymentDetails = await fetchResult<DeploymentListResult["latest"]>(
278
+ `/accounts/${accountId}/workers/deployments/by-script/${scriptTag}/detail/${deploymentId}`
279
+ );
280
+
281
+ const triggerStr = deploymentDetails.annotations?.["workers/triggered_by"]
282
+ ? `${formatTrigger(
283
+ deploymentDetails.annotations["workers/triggered_by"]
284
+ )} from ${formatSource(deploymentDetails.metadata.source)}`
285
+ : `${formatSource(deploymentDetails.metadata.source)}`;
286
+
287
+ const rollbackStr = deploymentDetails.annotations?.["workers/rollback_from"]
288
+ ? `\nRollback from: ${deploymentDetails.annotations["workers/rollback_from"]}`
289
+ : ``;
290
+
291
+ const reasonStr = deploymentDetails.annotations?.["workers/message"]
292
+ ? `\nMessage: ${deploymentDetails.annotations["workers/message"]}`
293
+ : ``;
294
+
295
+ const compatDateStr = deploymentDetails.resources.script_runtime
296
+ ?.compatibility_date
297
+ ? `\nCompatibility Date: ${deploymentDetails.resources.script_runtime?.compatibility_date}`
298
+ : ``;
299
+ const compatFlagsStr = deploymentDetails.resources.script_runtime
300
+ ?.compatibility_flags
301
+ ? `\nCompatibility Flags: ${deploymentDetails.resources.script_runtime?.compatibility_flags}`
302
+ : ``;
303
+
304
+ const bindings = deploymentDetails.resources.bindings;
305
+
306
+ const version = `
307
+ Deployment ID: ${deploymentDetails.id}
308
+ Created on: ${deploymentDetails.metadata.created_on}
309
+ Author: ${deploymentDetails.metadata.author_email}
310
+ Source: ${triggerStr}${rollbackStr}${reasonStr}
311
+ ------------------------------------------------------------
312
+ Author ID: ${deploymentDetails.metadata.author_id}
313
+ Usage Model: ${deploymentDetails.resources.script_runtime.usage_model}
314
+ Handlers: ${
315
+ deploymentDetails.resources.script.handlers
316
+ }${compatDateStr}${compatFlagsStr}
317
+ --------------------------bindings--------------------------
318
+ ${
319
+ bindings.length > 0
320
+ ? TOML.stringify(mapBindings(bindings) as TOML.JsonMap)
321
+ : `None`
322
+ }
323
+ `;
324
+
325
+ logger.log(version);
326
+
327
+ // early return to skip the deployments listings
328
+ return;
329
+ }
330
+
331
+ export async function commonDeploymentCMDSetup(
332
+ yargs: ArgumentsCamelCase<CommonYargsOptions>,
333
+ deploymentsWarning: string
334
+ ) {
335
+ await printWranglerBanner();
336
+ const config = readConfig(yargs.config, yargs);
337
+ const accountId = await requireAuth(config);
338
+ const scriptName = getScriptName(
339
+ { name: yargs.name as string, env: undefined },
340
+ config
341
+ );
342
+
343
+ logger.log(`${deploymentsWarning}\n`);
344
+
345
+ return { accountId, scriptName, config };
346
+ }
347
+
348
+ export function addHyphens(uuid: string | null): string | null {
349
+ if (uuid == null) {
350
+ return uuid;
351
+ }
352
+
353
+ if (uuid.length != 32) {
354
+ return null;
355
+ }
356
+
357
+ const uuid_parts: string[] = [];
358
+ uuid_parts.push(uuid.slice(0, 8));
359
+ uuid_parts.push(uuid.slice(8, 12));
360
+ uuid_parts.push(uuid.slice(12, 16));
361
+ uuid_parts.push(uuid.slice(16, 20));
362
+ uuid_parts.push(uuid.slice(20));
363
+
364
+ let hyphenated = "";
365
+ uuid_parts.forEach((part) => (hyphenated += part + "-"));
366
+
367
+ return hyphenated.slice(0, 36);
368
+ }