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
@@ -15,7 +15,7 @@ export async function generateTypes(
15
15
 
16
16
  if (configToDTS.kv_namespaces) {
17
17
  for (const kvNamespace of configToDTS.kv_namespaces) {
18
- envTypeStructure.push(` ${kvNamespace.binding}: KVNamespace;`);
18
+ envTypeStructure.push(`${kvNamespace.binding}: KVNamespace;`);
19
19
  }
20
20
  }
21
21
 
@@ -27,70 +27,78 @@ export async function generateTypes(
27
27
  typeof varValue === "number" ||
28
28
  typeof varValue === "boolean"
29
29
  ) {
30
- envTypeStructure.push(` ${varName}: "${varValue}";`);
30
+ envTypeStructure.push(`${varName}: "${varValue}";`);
31
31
  }
32
32
  if (typeof varValue === "object" && varValue !== null) {
33
- envTypeStructure.push(` ${varName}: ${JSON.stringify(varValue)};`);
33
+ envTypeStructure.push(`${varName}: ${JSON.stringify(varValue)};`);
34
34
  }
35
35
  }
36
36
  }
37
37
 
38
38
  if (configToDTS.durable_objects?.bindings) {
39
39
  for (const durableObject of configToDTS.durable_objects.bindings) {
40
- envTypeStructure.push(` ${durableObject.name}: DurableObjectNamespace;`);
40
+ envTypeStructure.push(`${durableObject.name}: DurableObjectNamespace;`);
41
41
  }
42
42
  }
43
43
 
44
44
  if (configToDTS.r2_buckets) {
45
45
  for (const R2Bucket of configToDTS.r2_buckets) {
46
- envTypeStructure.push(` ${R2Bucket.binding}: R2Bucket;`);
46
+ envTypeStructure.push(`${R2Bucket.binding}: R2Bucket;`);
47
47
  }
48
48
  }
49
49
 
50
50
  if (configToDTS.d1_databases) {
51
51
  for (const d1 of configToDTS.d1_databases) {
52
- envTypeStructure.push(` ${d1.binding}: D1Database;`);
52
+ envTypeStructure.push(`${d1.binding}: D1Database;`);
53
53
  }
54
54
  }
55
55
 
56
56
  if (configToDTS.services) {
57
57
  for (const service of configToDTS.services) {
58
- envTypeStructure.push(` ${service.binding}: Fetcher;`);
58
+ envTypeStructure.push(`${service.binding}: Fetcher;`);
59
+ }
60
+ }
61
+
62
+ if (configToDTS.analytics_engine_datasets) {
63
+ for (const analyticsEngine of configToDTS.analytics_engine_datasets) {
64
+ envTypeStructure.push(
65
+ `${analyticsEngine.binding}: AnalyticsEngineDataset;`
66
+ );
59
67
  }
60
68
  }
61
69
 
62
70
  if (configToDTS.dispatch_namespaces) {
63
71
  for (const namespace of configToDTS.dispatch_namespaces) {
64
- envTypeStructure.push(` ${namespace.binding}: any;`);
72
+ envTypeStructure.push(`${namespace.binding}: any;`);
65
73
  }
66
74
  }
67
75
 
68
76
  if (configToDTS.logfwdr?.schema) {
69
- envTypeStructure.push(` LOGFWDR_SCHEMA: any;`);
77
+ envTypeStructure.push(`LOGFWDR_SCHEMA: any;`);
70
78
  }
71
79
 
72
80
  if (configToDTS.data_blobs) {
73
81
  for (const dataBlobs in configToDTS.data_blobs) {
74
- envTypeStructure.push(` ${dataBlobs}: ArrayBuffer;`);
82
+ envTypeStructure.push(`${dataBlobs}: ArrayBuffer;`);
75
83
  }
76
84
  }
77
85
 
78
86
  if (configToDTS.text_blobs) {
79
87
  for (const textBlobs in configToDTS.text_blobs) {
80
- envTypeStructure.push(` ${textBlobs}: string;`);
88
+ envTypeStructure.push(`${textBlobs}: string;`);
81
89
  }
82
90
  }
83
91
 
84
- if (configToDTS.unsafe) {
92
+ if (configToDTS.unsafe?.bindings) {
85
93
  for (const unsafe of configToDTS.unsafe.bindings) {
86
- envTypeStructure.push(` ${unsafe.name}: any;`);
94
+ envTypeStructure.push(`${unsafe.name}: any;`);
87
95
  }
88
96
  }
89
97
 
90
98
  if (configToDTS.queues) {
91
99
  if (configToDTS.queues.producers) {
92
100
  for (const queue of configToDTS.queues.producers) {
93
- envTypeStructure.push(` ${queue.binding}: Queue;`);
101
+ envTypeStructure.push(`${queue.binding}: Queue;`);
94
102
  }
95
103
  }
96
104
  }
@@ -154,13 +162,13 @@ function writeDTSFile({
154
162
 
155
163
  let combinedTypeStrings = "";
156
164
  if (formatType === "modules") {
157
- combinedTypeStrings += `interface Env {\n${envTypeStructure.join(
158
- "\n"
159
- )} \n}\n${modulesTypeStructure.join("\n")}`;
165
+ combinedTypeStrings += `interface Env {\n${envTypeStructure
166
+ .map((value) => `\t${value}`)
167
+ .join("\n")}\n}\n${modulesTypeStructure.join("\n")}`;
160
168
  } else {
161
- combinedTypeStrings += `declare global {\n${envTypeStructure.join(
162
- "\n"
163
- )} \n}\n${modulesTypeStructure.join("\n")}`;
169
+ combinedTypeStrings += `export {};\ndeclare global {\n${envTypeStructure
170
+ .map((value) => `\tconst ${value}`)
171
+ .join("\n")}\n}\n${modulesTypeStructure.join("\n")}`;
164
172
  }
165
173
 
166
174
  if (envTypeStructure.length || modulesTypeStructure.length) {
@@ -21,7 +21,6 @@ export async function domainUsesAccess(domain: string): Promise<boolean> {
21
21
  try {
22
22
  const controller = new AbortController();
23
23
  const cancel = setTimeout(() => {
24
- logger.debug("Timed out");
25
24
  controller.abort();
26
25
  }, 1000);
27
26
 
@@ -0,0 +1,113 @@
1
+ import { getEnvironmentVariableFactory } from "../environment-variables/factory";
2
+ import { getCloudflareApiEnvironmentFromEnv } from "../environment-variables/misc-variables";
3
+ import { getAccessToken } from "./access";
4
+
5
+ /**
6
+ * `CLOUDFLARE_ACCOUNT_ID` overrides the account inferred from the current user.
7
+ */
8
+ export const getCloudflareAccountIdFromEnv = getEnvironmentVariableFactory({
9
+ variableName: "CLOUDFLARE_ACCOUNT_ID",
10
+ deprecatedName: "CF_ACCOUNT_ID",
11
+ });
12
+
13
+ export const getCloudflareAPITokenFromEnv = getEnvironmentVariableFactory({
14
+ variableName: "CLOUDFLARE_API_TOKEN",
15
+ deprecatedName: "CF_API_TOKEN",
16
+ });
17
+ export const getCloudflareGlobalAuthKeyFromEnv = getEnvironmentVariableFactory({
18
+ variableName: "CLOUDFLARE_API_KEY",
19
+ deprecatedName: "CF_API_KEY",
20
+ });
21
+ export const getCloudflareGlobalAuthEmailFromEnv =
22
+ getEnvironmentVariableFactory({
23
+ variableName: "CLOUDFLARE_EMAIL",
24
+ deprecatedName: "CF_EMAIL",
25
+ });
26
+
27
+ /**
28
+ * `WRANGLER_CLIENT_ID` is a UUID that is used to identify Wrangler
29
+ * to the Cloudflare APIs.
30
+ *
31
+ * Normally you should not need to set this explicitly.
32
+ * If you want to switch to the staging environment set the
33
+ * `WRANGLER_USE_STAGING` environment variable instead.
34
+ */
35
+ export const getClientIdFromEnv = getEnvironmentVariableFactory({
36
+ variableName: "WRANGLER_CLIENT_ID",
37
+ defaultValue: () =>
38
+ getCloudflareApiEnvironmentFromEnv() === "staging"
39
+ ? "4b2ea6cc-9421-4761-874b-ce550e0e3def"
40
+ : "54d11594-84e4-41aa-b438-e81b8fa78ee7",
41
+ });
42
+
43
+ /**
44
+ * `WRANGLER_AUTH_DOMAIN` is the URL base domain that is used
45
+ * to access OAuth URLs for the Cloudflare APIs.
46
+ *
47
+ * Normally you should not need to set this explicitly.
48
+ * If you want to switch to the staging environment set the
49
+ * `WRANGLER_USE_STAGING` environment variable instead.
50
+ */
51
+ export const getAuthDomainFromEnv = getEnvironmentVariableFactory({
52
+ variableName: "WRANGLER_AUTH_DOMAIN",
53
+ defaultValue: () =>
54
+ getCloudflareApiEnvironmentFromEnv() === "staging"
55
+ ? "dash.staging.cloudflare.com"
56
+ : "dash.cloudflare.com",
57
+ });
58
+
59
+ /**
60
+ * `WRANGLER_AUTH_URL` is the path that is used to access OAuth
61
+ * for the Cloudflare APIs.
62
+ *
63
+ * Normally you should not need to set this explicitly.
64
+ * If you want to switch to the staging environment set the
65
+ * `WRANGLER_USE_STAGING` environment variable instead.
66
+ */
67
+ export const getAuthUrlFromEnv = getEnvironmentVariableFactory({
68
+ variableName: "WRANGLER_AUTH_URL",
69
+ defaultValue: () => `https://${getAuthDomainFromEnv()}/oauth2/auth`,
70
+ });
71
+
72
+ /**
73
+ * `WRANGLER_TOKEN_URL` is the path that is used to exchange an OAuth
74
+ * token for an API token.
75
+ *
76
+ * Normally you should not need to set this explicitly.
77
+ * If you want to switch to the staging environment set the
78
+ * `WRANGLER_USE_STAGING` environment variable instead.
79
+ */
80
+ export const getTokenUrlFromEnv = getEnvironmentVariableFactory({
81
+ variableName: "WRANGLER_TOKEN_URL",
82
+ defaultValue: () => `https://${getAuthDomainFromEnv()}/oauth2/token`,
83
+ });
84
+
85
+ /**
86
+ * `WRANGLER_REVOKE_URL` is the path that is used to exchange an OAuth
87
+ * refresh token for a new OAuth token.
88
+ *
89
+ * Normally you should not need to set this explicitly.
90
+ * If you want to switch to the staging environment set the
91
+ * `WRANGLER_USE_STAGING` environment variable instead.
92
+ */
93
+ export const getRevokeUrlFromEnv = getEnvironmentVariableFactory({
94
+ variableName: "WRANGLER_REVOKE_URL",
95
+ defaultValue: () => `https://${getAuthDomainFromEnv()}/oauth2/revoke`,
96
+ });
97
+
98
+ /**
99
+ * Set the `WRANGLER_CF_AUTHORIZATION_TOKEN` to the CF_Authorization token found at https://dash.staging.cloudflare.com/bypass-limits
100
+ * if you want to access the staging environment, triggered by `WRANGLER_API_ENVIRONMENT=staging`.
101
+ */
102
+ export const getCloudflareAccessToken = async () => {
103
+ const env = getEnvironmentVariableFactory({
104
+ variableName: "WRANGLER_CF_AUTHORIZATION_TOKEN",
105
+ })();
106
+
107
+ // If the environment variable is defined, go ahead and use it.
108
+ if (env !== undefined) {
109
+ return env;
110
+ }
111
+
112
+ return getAccessToken(getAuthDomainFromEnv());
113
+ };
@@ -1,41 +1,11 @@
1
- import { Text } from "ink";
2
- import SelectInput from "ink-select-input";
3
- import React from "react";
4
1
  import { fetchListResult } from "../cfetch";
5
- import { logger } from "../logger";
6
- import { getCloudflareAccountIdFromEnv } from "./env-vars";
2
+ import { getCloudflareAccountIdFromEnv } from "./auth-variables";
7
3
 
8
4
  export type ChooseAccountItem = {
9
5
  id: string;
10
6
  name: string;
11
7
  };
12
8
 
13
- /**
14
- * A component that allows the user to select from a list of available accounts.
15
- */
16
- export function ChooseAccount(props: {
17
- accounts: ChooseAccountItem[];
18
- onSelect: (account: { name: string; id: string }) => void;
19
- onError: (error: Error) => void;
20
- }) {
21
- return (
22
- <>
23
- <Text bold>Select an account from below:</Text>
24
- <SelectInput
25
- items={props.accounts.map((item) => ({
26
- key: item.id,
27
- label: item.name,
28
- value: item,
29
- }))}
30
- onSelect={(item) => {
31
- logger.log(`Using account: "${item.value.name} - ${item.value.id}"`);
32
- props.onSelect({ id: item.value.id, name: item.value.name });
33
- }}
34
- />
35
- </>
36
- );
37
- }
38
-
39
9
  /**
40
10
  * Infer a list of available accounts for the current user.
41
11
  */
package/src/user/index.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  export * from "./user";
2
- export * from "./env-vars";
3
2
  export * from "./choose-account";
@@ -214,28 +214,61 @@ import url from "node:url";
214
214
  import { TextEncoder } from "node:util";
215
215
  import TOML from "@iarna/toml";
216
216
  import { HostURL } from "@webcontainer/env";
217
- import { render } from "ink";
218
- import Table from "ink-table";
219
- import React from "react";
220
217
  import { fetch } from "undici";
221
218
  import {
222
219
  getConfigCache,
223
220
  purgeConfigCaches,
224
221
  saveToConfigCache,
225
222
  } from "../config-cache";
223
+ import { NoDefaultValueProvided, select } from "../dialogs";
226
224
  import { getGlobalWranglerConfigPath } from "../global-wrangler-config-path";
227
225
  import { CI } from "../is-ci";
228
226
  import isInteractive from "../is-interactive";
229
227
  import { logger } from "../logger";
230
228
  import openInBrowser from "../open-in-browser";
231
229
  import { parseTOML, readFileSync } from "../parse";
232
- import { ChooseAccount, getAccountChoices } from "./choose-account";
233
- import { getAuthFromEnv } from "./env-vars";
230
+ import { domainUsesAccess } from "./access";
231
+ import {
232
+ getAuthDomainFromEnv,
233
+ getAuthUrlFromEnv,
234
+ getClientIdFromEnv,
235
+ getCloudflareAccessToken,
236
+ getCloudflareAPITokenFromEnv,
237
+ getCloudflareGlobalAuthEmailFromEnv,
238
+ getCloudflareGlobalAuthKeyFromEnv,
239
+ getRevokeUrlFromEnv,
240
+ getTokenUrlFromEnv,
241
+ } from "./auth-variables";
242
+ import { getAccountChoices } from "./choose-account";
234
243
  import { generateAuthUrl } from "./generate-auth-url";
235
244
  import { generateRandomState } from "./generate-random-state";
236
- import type { ApiCredentials } from "./env-vars";
245
+ import type { ChooseAccountItem } from "./choose-account";
237
246
  import type { ParsedUrlQuery } from "node:querystring";
238
247
 
248
+ export type ApiCredentials =
249
+ | {
250
+ apiToken: string;
251
+ }
252
+ | {
253
+ authKey: string;
254
+ authEmail: string;
255
+ };
256
+
257
+ /**
258
+ * Try to read an API token or Global Auth from the environment.
259
+ */
260
+ export function getAuthFromEnv(): ApiCredentials | undefined {
261
+ const globalApiKey = getCloudflareGlobalAuthKeyFromEnv();
262
+ const globalApiEmail = getCloudflareGlobalAuthEmailFromEnv();
263
+ const apiToken = getCloudflareAPITokenFromEnv();
264
+
265
+ if (globalApiKey && globalApiEmail) {
266
+ return { authKey: globalApiKey, authEmail: globalApiEmail };
267
+ } else if (apiToken) {
268
+ return { apiToken };
269
+ }
270
+ }
271
+
239
272
  /**
240
273
  * An implementation of rfc6749#section-4.1 and rfc7636.
241
274
  */
@@ -264,7 +297,7 @@ interface AuthTokens {
264
297
  accessToken?: AccessToken;
265
298
  refreshToken?: RefreshToken;
266
299
  scopes?: Scope[];
267
- /** @deprecated - this field was only provided by the deprecated `wrangler1 config` command. */
300
+ /** @deprecated - this field was only provided by the deprecated v1 `wrangler config` command. */
268
301
  apiToken?: string;
269
302
  }
270
303
 
@@ -282,7 +315,7 @@ export interface UserAuthConfig {
282
315
  refresh_token?: string;
283
316
  expiration_time?: string;
284
317
  scopes?: string[];
285
- /** @deprecated - this field was only provided by the deprecated `wrangler1 config` command. */
318
+ /** @deprecated - this field was only provided by the deprecated v1 `wrangler config` command. */
286
319
  api_token?: string;
287
320
  }
288
321
 
@@ -313,6 +346,7 @@ const Scopes = {
313
346
  "pages:write":
314
347
  "See and change Cloudflare Pages projects, settings and deployments.",
315
348
  "zone:read": "Grants read level access to account zone.",
349
+ "ssl_certs:write": "See and manage mTLS certificates for your account",
316
350
  } as const;
317
351
 
318
352
  /**
@@ -330,11 +364,6 @@ export function validateScopeKeys(
330
364
  return scopes.every((scope) => scope in Scopes);
331
365
  }
332
366
 
333
- const CLIENT_ID = "54d11594-84e4-41aa-b438-e81b8fa78ee7";
334
- const AUTH_URL = "https://dash.cloudflare.com/oauth2/auth";
335
- const TOKEN_URL = "https://dash.cloudflare.com/oauth2/token";
336
- const REVOKE_URL = "https://dash.cloudflare.com/oauth2/revoke";
337
-
338
367
  /**
339
368
  * To allow OAuth callbacks in environments such as WebContainer we need to
340
369
  * create a host URL which only resolves `localhost` to a WebContainer
@@ -374,7 +403,7 @@ function getAuthTokens(config?: UserAuthConfig): AuthTokens | undefined {
374
403
  };
375
404
  } else if (api_token) {
376
405
  logger.warn(
377
- "It looks like you have used Wrangler 1's `config` command to login with an API token.\n" +
406
+ "It looks like you have used Wrangler v1's `config` command to login with an API token.\n" +
378
407
  "This is no longer supported in the current version of Wrangler.\n" +
379
408
  "If you wish to authenticate via an API token then please set the `CLOUDFLARE_API_TOKEN` environment variable."
380
409
  );
@@ -386,7 +415,7 @@ function getAuthTokens(config?: UserAuthConfig): AuthTokens | undefined {
386
415
  }
387
416
 
388
417
  /**
389
- * Run the initialisation of the auth state, in the case that something changed.
418
+ * Run the initialization of the auth state, in the case that something changed.
390
419
  *
391
420
  * This runs automatically whenever `writeAuthConfigFile` is run, so generally
392
421
  * you won't need to call it yourself.
@@ -625,8 +654,8 @@ export async function getAuthURL(scopes = ScopeKeys): Promise<string> {
625
654
  });
626
655
 
627
656
  return generateAuthUrl({
628
- authUrl: AUTH_URL,
629
- clientId: CLIENT_ID,
657
+ authUrl: getAuthUrlFromEnv(),
658
+ clientId: getClientIdFromEnv(),
630
659
  callbackUrl: CALLBACK_URL,
631
660
  scopes,
632
661
  stateQueryParam,
@@ -653,19 +682,14 @@ async function exchangeRefreshTokenForAccessToken(): Promise<AccessContext> {
653
682
  logger.warn("No refresh token is present.");
654
683
  }
655
684
 
656
- const body =
657
- `grant_type=refresh_token&` +
658
- `refresh_token=${LocalState.refreshToken?.value}&` +
659
- `client_id=${CLIENT_ID}`;
660
-
661
- const response = await fetch(TOKEN_URL, {
662
- method: "POST",
663
- body,
664
- headers: {
665
- "Content-Type": "application/x-www-form-urlencoded",
666
- },
685
+ const params = new URLSearchParams({
686
+ grant_type: "refresh_token",
687
+ refresh_token: LocalState.refreshToken?.value ?? "",
688
+ client_id: getClientIdFromEnv(),
667
689
  });
668
690
 
691
+ const response = await fetchAuthToken(params);
692
+
669
693
  if (response.status >= 400) {
670
694
  let tokenExchangeResErr = undefined;
671
695
 
@@ -743,20 +767,15 @@ async function exchangeAuthCodeForAccessToken(): Promise<AccessContext> {
743
767
  logger.warn("No authorization grant code is being passed.");
744
768
  }
745
769
 
746
- const body =
747
- `grant_type=authorization_code&` +
748
- `code=${encodeURIComponent(authorizationCode || "")}&` +
749
- `redirect_uri=${encodeURIComponent(CALLBACK_URL)}&` +
750
- `client_id=${encodeURIComponent(CLIENT_ID)}&` +
751
- `code_verifier=${codeVerifier}`;
752
-
753
- const response = await fetch(TOKEN_URL, {
754
- method: "POST",
755
- body,
756
- headers: {
757
- "Content-Type": "application/x-www-form-urlencoded",
758
- },
770
+ const params = new URLSearchParams({
771
+ grant_type: `authorization_code`,
772
+ code: authorizationCode ?? "",
773
+ redirect_uri: CALLBACK_URL,
774
+ client_id: getClientIdFromEnv(),
775
+ code_verifier: codeVerifier,
759
776
  });
777
+
778
+ const response = await fetchAuthToken(params);
760
779
  if (!response.ok) {
761
780
  const { error } = (await response.json()) as { error: string };
762
781
  // .catch((_) => ({ error: "invalid_json" }));
@@ -875,6 +894,7 @@ export function readAuthConfigFile(): UserAuthConfig {
875
894
 
876
895
  type LoginProps = {
877
896
  scopes?: Scope[];
897
+ browser: boolean;
878
898
  };
879
899
 
880
900
  export async function loginOrRefreshIfRequired(): Promise<boolean> {
@@ -901,7 +921,9 @@ export async function loginOrRefreshIfRequired(): Promise<boolean> {
901
921
  }
902
922
  }
903
923
 
904
- export async function login(props?: LoginProps): Promise<boolean> {
924
+ export async function login(
925
+ props: LoginProps = { browser: true }
926
+ ): Promise<boolean> {
905
927
  logger.log("Attempting to login via OAuth...");
906
928
  const urlToOpen = await getAuthURL(props?.scopes);
907
929
  let server: http.Server;
@@ -914,7 +936,7 @@ export async function login(props?: LoginProps): Promise<boolean> {
914
936
  server.close();
915
937
  clearTimeout(loginTimeoutHandle);
916
938
  resolve(false);
917
- }, 60000); // wait for 60 seconds for the user to authorize
939
+ }, 120000); // wait for 120 seconds for the user to authorize
918
940
  });
919
941
 
920
942
  const loginPromise = new Promise<boolean>((resolve, reject) => {
@@ -986,9 +1008,12 @@ export async function login(props?: LoginProps): Promise<boolean> {
986
1008
 
987
1009
  server.listen(8976);
988
1010
  });
989
-
990
- logger.log(`Opening a link in your default browser: ${urlToOpen}`);
991
- await openInBrowser(urlToOpen);
1011
+ if (props?.browser) {
1012
+ logger.log(`Opening a link in your default browser: ${urlToOpen}`);
1013
+ await openInBrowser(urlToOpen);
1014
+ } else {
1015
+ logger.log(`Visit this link to authenticate: ${urlToOpen}`);
1016
+ }
992
1017
 
993
1018
  return Promise.race([timerPromise, loginPromise]);
994
1019
  }
@@ -1032,11 +1057,11 @@ export async function logout(): Promise<void> {
1032
1057
  }
1033
1058
 
1034
1059
  const body =
1035
- `client_id=${encodeURIComponent(CLIENT_ID)}&` +
1060
+ `client_id=${encodeURIComponent(getClientIdFromEnv())}&` +
1036
1061
  `token_type_hint=refresh_token&` +
1037
1062
  `token=${encodeURIComponent(LocalState.refreshToken?.value || "")}`;
1038
1063
 
1039
- const response = await fetch(REVOKE_URL, {
1064
+ const response = await fetch(getRevokeUrlFromEnv(), {
1040
1065
  method: "POST",
1041
1066
  body,
1042
1067
  headers: {
@@ -1049,11 +1074,11 @@ export async function logout(): Promise<void> {
1049
1074
  );
1050
1075
  }
1051
1076
  const body =
1052
- `client_id=${encodeURIComponent(CLIENT_ID)}&` +
1077
+ `client_id=${encodeURIComponent(getClientIdFromEnv())}&` +
1053
1078
  `token_type_hint=refresh_token&` +
1054
1079
  `token=${encodeURIComponent(LocalState.refreshToken?.value || "")}`;
1055
1080
 
1056
- const response = await fetch(REVOKE_URL, {
1081
+ const response = await fetch(getRevokeUrlFromEnv(), {
1057
1082
  method: "POST",
1058
1083
  body,
1059
1084
  headers: {
@@ -1071,8 +1096,7 @@ export function listScopes(message = "💁 Available scopes:"): void {
1071
1096
  Scope: scope,
1072
1097
  Description: Scopes[scope],
1073
1098
  }));
1074
- const { unmount } = render(<Table data={data} />);
1075
- unmount();
1099
+ logger.table(data);
1076
1100
  // TODO: maybe a good idea to show usage here
1077
1101
  }
1078
1102
 
@@ -1091,36 +1115,32 @@ export async function getAccountId(): Promise<string | undefined> {
1091
1115
  return accounts[0].id;
1092
1116
  }
1093
1117
 
1094
- if (isInteractive() && !CI.isCI()) {
1095
- const account = await new Promise<{ id: string; name: string }>(
1096
- (resolve, reject) => {
1097
- const { unmount } = render(
1098
- <ChooseAccount
1099
- accounts={accounts}
1100
- onSelect={async (selected) => {
1101
- saveAccountToCache(selected);
1102
- resolve(selected);
1103
- unmount();
1104
- }}
1105
- onError={(err) => {
1106
- reject(err);
1107
- unmount();
1108
- }}
1109
- />
1110
- );
1111
- }
1112
- );
1113
- return account.id;
1118
+ try {
1119
+ const accountID = await select("Select an account", {
1120
+ choices: accounts.map((account) => ({
1121
+ title: account.name,
1122
+ value: account.id,
1123
+ })),
1124
+ });
1125
+ const account = accounts.find(
1126
+ (a) => a.id === accountID
1127
+ ) as ChooseAccountItem;
1128
+ saveAccountToCache({ id: account.id, name: account.name });
1129
+ return accountID;
1130
+ } catch (e) {
1131
+ // Did we try to select an account in CI or a non-interactive terminal?
1132
+ if (e instanceof NoDefaultValueProvided) {
1133
+ throw new Error(
1134
+ `More than one account available but unable to select one in non-interactive mode.
1135
+ Please set the appropriate \`account_id\` in your \`wrangler.toml\` file.
1136
+ Available accounts are (\`<name>\`: \`<account_id>\`):
1137
+ ${accounts
1138
+ .map((account) => ` \`${account.name}\`: \`${account.id}\``)
1139
+ .join("\n")}`
1140
+ );
1141
+ }
1142
+ throw e;
1114
1143
  }
1115
-
1116
- throw new Error(
1117
- "More than one account available but unable to select one in non-interactive mode.\n" +
1118
- `Please set the appropriate \`account_id\` in your \`wrangler.toml\` file.\n` +
1119
- `Available accounts are ("<name>" - "<id>"):\n` +
1120
- accounts
1121
- .map((account) => ` "${account.name}" - "${account.id}")`)
1122
- .join("\n")
1123
- );
1124
1144
  }
1125
1145
 
1126
1146
  /**
@@ -1133,7 +1153,7 @@ export async function requireAuth(config: {
1133
1153
  if (!loggedIn) {
1134
1154
  if (!isInteractive() || CI.isCI()) {
1135
1155
  throw new Error(
1136
- "In a non-interactive environment, it's necessary to set a CLOUDFLARE_API_TOKEN environment variable for wrangler to work. Please go to https://developers.cloudflare.com/api/tokens/create/ for instructions on how to create an api token, and assign its value to CLOUDFLARE_API_TOKEN."
1156
+ "In a non-interactive environment, it's necessary to set a CLOUDFLARE_API_TOKEN environment variable for wrangler to work. Please go to https://developers.cloudflare.com/fundamentals/api/get-started/create-token/ for instructions on how to create an api token, and assign its value to CLOUDFLARE_API_TOKEN."
1137
1157
  );
1138
1158
  } else {
1139
1159
  // didn't login, let's just quit
@@ -1190,3 +1210,24 @@ export function getAccountFromCache():
1190
1210
  export function getScopes(): Scope[] | undefined {
1191
1211
  return LocalState.scopes;
1192
1212
  }
1213
+
1214
+ /**
1215
+ * Make a request to the Cloudflare OAuth endpoint to get a token.
1216
+ *
1217
+ * Note that the `body` of the POST request is form-urlencoded so
1218
+ * can be represented by a URLSearchParams object.
1219
+ */
1220
+ async function fetchAuthToken(body: URLSearchParams) {
1221
+ const headers: Record<string, string> = {
1222
+ "Content-Type": "application/x-www-form-urlencoded",
1223
+ };
1224
+ if (await domainUsesAccess(getAuthDomainFromEnv())) {
1225
+ // We are trying to access the staging API so we need an "access token".
1226
+ headers["Cookie"] = `CF_Authorization=${await getCloudflareAccessToken()}`;
1227
+ }
1228
+ return await fetch(getTokenUrlFromEnv(), {
1229
+ method: "POST",
1230
+ body: body.toString(),
1231
+ headers,
1232
+ });
1233
+ }