wrangler 0.0.0-e30d1013 → 0.0.0-e311bbbf

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 (236) 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 +26 -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 -39
  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 -52
  15. package/src/__tests__/dev.test.tsx +198 -90
  16. package/src/__tests__/generate.test.ts +8 -5
  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 +127 -26
  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 +1620 -830
  61. package/src/__tests__/pubsub.test.ts +226 -100
  62. package/src/__tests__/queues.test.ts +237 -76
  63. package/src/__tests__/r2.test.ts +37 -56
  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 +11 -2
  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 +221 -128
  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 +73 -16
  87. package/src/config/index.ts +99 -30
  88. package/src/config/validation-helpers.ts +1 -1
  89. package/src/config/validation.ts +248 -9
  90. package/src/create-worker-preview.ts +19 -8
  91. package/src/create-worker-upload-form.ts +48 -5
  92. package/src/d1/backups.tsx +43 -42
  93. package/src/d1/create.tsx +26 -21
  94. package/src/d1/{delete.tsx → delete.ts} +11 -14
  95. package/src/d1/execute.tsx +183 -170
  96. package/src/d1/index.ts +7 -6
  97. package/src/d1/list.tsx +22 -10
  98. package/src/d1/migrations/apply.tsx +212 -0
  99. package/src/d1/migrations/create.tsx +79 -0
  100. package/src/d1/migrations/helpers.ts +172 -0
  101. package/src/d1/migrations/index.ts +3 -0
  102. package/src/d1/migrations/list.tsx +95 -0
  103. package/src/d1/migrations/options.ts +23 -0
  104. package/src/d1/options.ts +3 -3
  105. package/src/d1/splitter.ts +161 -0
  106. package/src/d1/{types.tsx → types.ts} +1 -0
  107. package/src/d1/utils.ts +2 -1
  108. package/src/delete.ts +8 -16
  109. package/src/deployments.ts +333 -42
  110. package/src/deprecated/index.ts +8 -302
  111. package/src/dev/dev.tsx +57 -44
  112. package/src/dev/local.tsx +248 -74
  113. package/src/dev/remote.tsx +32 -3
  114. package/src/dev/start-server.ts +81 -66
  115. package/src/dev/use-esbuild.ts +17 -18
  116. package/src/dev/validate-dev-props.ts +9 -0
  117. package/src/{dev-registry.tsx → dev-registry.ts} +2 -1
  118. package/src/dev.tsx +178 -117
  119. package/src/dialogs.ts +136 -0
  120. package/src/dispatch-namespace.ts +21 -17
  121. package/src/docs/index.ts +97 -0
  122. package/src/entry.ts +19 -11
  123. package/src/environment-variables/factory.ts +88 -0
  124. package/src/environment-variables/misc-variables.ts +30 -0
  125. package/src/generate/index.ts +298 -0
  126. package/src/git-client.ts +15 -4
  127. package/src/{index.tsx → index.ts} +134 -59
  128. package/src/init.ts +249 -187
  129. package/src/inspect.ts +16 -1
  130. package/src/jest.d.ts +4 -0
  131. package/src/kv/index.ts +15 -17
  132. package/src/logger.ts +32 -5
  133. package/src/metrics/metrics-config.ts +3 -3
  134. package/src/metrics/send-event.ts +6 -1
  135. package/src/miniflare-cli/assets.ts +64 -28
  136. package/src/miniflare-cli/index.ts +4 -7
  137. package/src/miniflare-cli/tsconfig.json +9 -0
  138. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
  139. package/src/miniflare-cli/types.ts +11 -0
  140. package/src/module-collection.ts +91 -25
  141. package/src/mtls-certificate/cli.ts +155 -0
  142. package/src/pages/build.ts +410 -0
  143. package/src/pages/buildFunctions.ts +140 -0
  144. package/src/pages/deployment-tails.ts +281 -0
  145. package/src/pages/deployments.tsx +11 -33
  146. package/src/pages/{dev.tsx → dev.ts} +147 -139
  147. package/src/pages/errors.ts +1 -0
  148. package/src/pages/functions/buildPlugin.ts +61 -54
  149. package/src/pages/functions/buildWorker.ts +159 -33
  150. package/src/pages/functions/tsconfig.json +8 -0
  151. package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
  152. package/src/pages/{functions.tsx → functions.ts} +8 -4
  153. package/src/pages/{index.tsx → index.ts} +11 -3
  154. package/src/pages/projects.tsx +12 -22
  155. package/src/pages/prompt-select-project.tsx +31 -0
  156. package/src/pages/publish.tsx +46 -225
  157. package/src/pages/types.ts +6 -9
  158. package/src/pages/upload.tsx +58 -14
  159. package/src/pages/utils.ts +12 -1
  160. package/src/parse.ts +23 -1
  161. package/src/paths.ts +1 -1
  162. package/src/proxy.ts +5 -0
  163. package/src/publish/index.ts +20 -16
  164. package/src/publish/publish.ts +71 -46
  165. package/src/pubsub/{pubsub-commands.tsx → pubsub-commands.ts} +19 -20
  166. package/src/queues/cli/commands/consumer/add.ts +24 -24
  167. package/src/queues/cli/commands/consumer/index.ts +3 -6
  168. package/src/queues/cli/commands/consumer/remove.ts +11 -18
  169. package/src/queues/cli/commands/create.ts +8 -8
  170. package/src/queues/cli/commands/delete.ts +8 -8
  171. package/src/queues/cli/commands/index.ts +6 -4
  172. package/src/queues/cli/commands/list.ts +8 -8
  173. package/src/queues/client.ts +1 -0
  174. package/src/queues/utils.ts +18 -0
  175. package/src/r2/helpers.ts +1 -0
  176. package/src/r2/index.ts +28 -28
  177. package/src/secret/index.ts +14 -16
  178. package/src/{sites.tsx → sites.ts} +1 -1
  179. package/src/tail/createTail.ts +94 -3
  180. package/src/tail/filters.ts +1 -1
  181. package/src/tail/index.ts +8 -11
  182. package/src/tail/printing.ts +15 -0
  183. package/src/traverse-module-graph.ts +53 -0
  184. package/src/tsconfig-sanity.ts +16 -0
  185. package/src/type-generation.ts +28 -20
  186. package/src/user/access.ts +0 -1
  187. package/src/user/auth-variables.ts +113 -0
  188. package/src/user/choose-account.tsx +1 -31
  189. package/src/user/index.ts +0 -1
  190. package/src/user/{user.tsx → user.ts} +123 -82
  191. package/src/utils/render.ts +93 -0
  192. package/src/{whoami.tsx → whoami.ts} +37 -71
  193. package/src/worker.ts +30 -1
  194. package/src/yargs-types.ts +22 -5
  195. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  196. package/templates/__tests__/tsconfig.json +8 -0
  197. package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
  198. package/templates/checked-fetch.js +9 -3
  199. package/templates/d1-beta-facade.js +51 -3
  200. package/templates/facade.d.ts +14 -0
  201. package/templates/first-party-worker-module-facade.ts +4 -3
  202. package/templates/format-dev-errors.ts +8 -6
  203. package/templates/gitignore +1 -0
  204. package/templates/init-tests/test-jest-new-worker.js +3 -5
  205. package/templates/init-tests/test-vitest-new-worker.js +3 -5
  206. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  207. package/templates/middleware/loader-modules.ts +2 -2
  208. package/templates/middleware/loader-sw.ts +51 -31
  209. package/templates/middleware/middleware-miniflare3-json-error.ts +32 -0
  210. package/templates/new-worker.ts +3 -0
  211. package/templates/pages-dev-pipeline.ts +4 -1
  212. package/templates/pages-shim.ts +4 -1
  213. package/templates/pages-template-plugin.ts +19 -10
  214. package/templates/serve-static-assets.ts +17 -14
  215. package/templates/service-bindings-module-facade.js +1 -0
  216. package/templates/tsconfig-sanity.ts +11 -0
  217. package/templates/tsconfig.init.json +105 -0
  218. package/templates/tsconfig.json +5 -103
  219. package/templates/tsconfig.tsbuildinfo +1 -0
  220. package/wrangler-dist/cli.d.ts +820 -70
  221. package/wrangler-dist/cli.js +68161 -78780
  222. package/wrangler-dist/wasm-sync.wasm +0 -0
  223. package/src/__tests__/api-devregistry.test.js +0 -56
  224. package/src/__tests__/d1.test.ts +0 -74
  225. package/src/__tests__/dialogs.test.tsx +0 -40
  226. package/src/__tests__/helpers/mock-cfetch.ts +0 -333
  227. package/src/__tests__/pages.test.ts +0 -2387
  228. package/src/d1/migrations.tsx +0 -446
  229. package/src/dialogs.tsx +0 -169
  230. package/src/environment-variables.ts +0 -50
  231. package/src/pages/build.tsx +0 -270
  232. package/src/user/env-vars.ts +0 -46
  233. package/templates/experimental-local-cache-stubs.js +0 -27
  234. /package/src/{bundle-reporter.tsx → bundle-reporter.ts} +0 -0
  235. /package/src/dev/{get-local-persistence-path.tsx → get-local-persistence-path.ts} +0 -0
  236. /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,5 +1,6 @@
1
1
  export type Database = {
2
2
  uuid: string;
3
+ previewDatabaseUuid?: string;
3
4
  name: string;
4
5
  binding: string;
5
6
  internal_env?: string;
package/src/d1/utils.ts CHANGED
@@ -14,6 +14,7 @@ export function getDatabaseInfoFromConfig(
14
14
  ) {
15
15
  return {
16
16
  uuid: d1Database.database_id,
17
+ previewDatabaseUuid: d1Database.preview_database_id,
17
18
  binding: d1Database.binding,
18
19
  name: d1Database.database_name,
19
20
  migrationsTableName:
@@ -45,4 +46,4 @@ export const getDatabaseByNameOrBinding = async (
45
46
 
46
47
  export const d1BetaWarning = process.env.NO_D1_WARNING
47
48
  ? ""
48
- : "🚧 '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,77 +1,368 @@
1
1
  import { URLSearchParams } from "url";
2
+ import TOML from "@iarna/toml";
3
+ import chalk from "chalk";
4
+ import { FormData } from "undici";
2
5
  import { fetchResult } from "./cfetch";
6
+ import { readConfig } from "./config";
7
+ import { confirm, prompt } from "./dialogs";
8
+ import { mapBindings } from "./init";
3
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";
4
16
  import type { ServiceMetadataRes } from "./init";
17
+ import type { CommonYargsOptions } from "./yargs-types";
18
+ import type { ArgumentsCamelCase } from "yargs";
5
19
 
6
- export type DeploymentListRes = {
7
- latest: {
8
- id: string;
9
- number: string;
10
- metadata: {
11
- author_id: string;
12
- author_email: string;
13
- source: "api" | "dash" | "wrangler" | "terraform" | "other";
14
- created_on: string;
15
- 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[];
16
38
  };
17
- resources: {
18
- script: string;
19
- bindings: unknown[];
39
+ bindings: WorkerMetadataBinding[];
40
+ script_runtime: {
41
+ compatibility_date: string | undefined;
42
+ compatibility_flags: string[] | undefined;
43
+ usage_model: string | undefined;
20
44
  };
21
45
  };
22
- items: {
23
- id: string;
24
- number: string;
25
- metadata: {
26
- author_id: string;
27
- author_email: string;
28
- source: "api" | "dash" | "wrangler" | "terraform" | "other";
29
- created_on: string;
30
- modified_on: string;
31
- };
32
- }[];
46
+ };
47
+
48
+ export type DeploymentListResult = {
49
+ latest: DeploymentDetails;
50
+ items: DeploymentDetails[];
33
51
  };
34
52
 
35
53
  export async function deployments(
36
54
  accountId: string,
37
- scriptName: string | undefined
55
+ scriptName: string | undefined,
56
+ { send_metrics: sendMetrics }: { send_metrics?: Config["send_metrics"] } = {}
38
57
  ) {
39
- const scriptMetadata = await fetchResult<ServiceMetadataRes>(
40
- `/accounts/${accountId}/workers/services/${scriptName}`
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
+ }
63
+
64
+ await metrics.sendMetricsEvent(
65
+ "view deployments",
66
+ { view: scriptName ? "single" : "all" },
67
+ {
68
+ sendMetrics,
69
+ }
41
70
  );
42
71
 
43
- const scriptTag = scriptMetadata.default_environment.script.tag;
72
+ const scriptTag = (
73
+ await fetchResult<ServiceMetadataRes>(
74
+ `/accounts/${accountId}/workers/services/${scriptName}`
75
+ )
76
+ ).default_environment.script.tag;
77
+
44
78
  const params = new URLSearchParams({ order: "asc" });
45
- const { items: deploys } = await fetchResult<DeploymentListRes>(
79
+ const { items: deploys } = await fetchResult<DeploymentListResult>(
46
80
  `/accounts/${accountId}/workers/deployments/by-script/${scriptTag}`,
47
81
  undefined,
48
82
  params
49
83
  );
50
84
 
51
- const versionMessages = deploys.map(
52
- (versions) =>
53
- `\nDeployment ID: ${versions.id}
54
- Created on: ${versions.metadata.created_on}
55
- Author: ${versions.metadata.author_email}
56
- Source: ${sourceStr(versions.metadata.source)}\n`
57
- );
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
+ });
58
108
 
59
109
  versionMessages[versionMessages.length - 1] += "🟩 Active";
60
110
  logger.log(...versionMessages);
61
111
  }
62
112
 
63
- // TODO Include emoji/icon for each source
64
- function sourceStr(source: string): string {
113
+ function formatSource(source: string): string {
65
114
  switch (source) {
66
115
  case "api":
67
- return "API";
116
+ return "API 📡";
68
117
  case "dash":
69
- return "Dashboard";
118
+ return "Dashboard 🖥️";
70
119
  case "wrangler":
71
- return "Wrangler";
120
+ return "Wrangler 🤠";
72
121
  case "terraform":
73
- return "Terraform";
122
+ return "Terraform 🏗️";
74
123
  default:
75
124
  return "Other";
76
125
  }
77
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
+ }