wrangler 0.0.0-e178d6fb → 0.0.0-e1c2f5b9

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 (239) hide show
  1. package/README.md +16 -2
  2. package/bin/wrangler.js +31 -11
  3. package/miniflare-dist/index.mjs +1340 -330
  4. package/package.json +40 -13
  5. package/src/__tests__/access.test.ts +25 -0
  6. package/src/__tests__/api-dev.test.ts +238 -0
  7. package/src/__tests__/api-devregistry.test.js +64 -0
  8. package/src/__tests__/api.test.ts +80 -0
  9. package/src/__tests__/configuration.test.ts +683 -470
  10. package/src/__tests__/d1.test.ts +123 -0
  11. package/src/__tests__/delete.test.ts +263 -0
  12. package/src/__tests__/deployments.test.ts +105 -0
  13. package/src/__tests__/dev.test.tsx +453 -70
  14. package/src/__tests__/dialogs.test.tsx +40 -0
  15. package/src/__tests__/generate.test.ts +235 -0
  16. package/src/__tests__/get-host-from-url.test.ts +16 -0
  17. package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
  18. package/src/__tests__/helpers/mock-cfetch.ts +92 -26
  19. package/src/__tests__/helpers/mock-console.ts +11 -2
  20. package/src/__tests__/helpers/mock-dialogs.ts +1 -1
  21. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
  22. package/src/__tests__/helpers/mock-known-routes.ts +7 -0
  23. package/src/__tests__/helpers/mock-kv.ts +1 -1
  24. package/src/__tests__/helpers/mock-oauth-flow.ts +74 -53
  25. package/src/__tests__/helpers/mock-process.ts +8 -13
  26. package/src/__tests__/helpers/msw/handlers/access.ts +13 -0
  27. package/src/__tests__/helpers/msw/handlers/deployments.ts +59 -0
  28. package/src/__tests__/helpers/msw/handlers/namespaces.ts +104 -0
  29. package/src/__tests__/helpers/msw/handlers/oauth.ts +31 -0
  30. package/src/__tests__/helpers/msw/handlers/r2.ts +80 -0
  31. package/src/__tests__/helpers/msw/handlers/script.ts +75 -0
  32. package/src/__tests__/helpers/msw/handlers/user.ts +63 -0
  33. package/src/__tests__/helpers/msw/handlers/zones.ts +22 -0
  34. package/src/__tests__/helpers/msw/index.ts +21 -0
  35. package/src/__tests__/helpers/worker-scripts/child-wrangler.toml +1 -0
  36. package/src/__tests__/helpers/worker-scripts/hello-world-worker.js +5 -0
  37. package/src/__tests__/helpers/worker-scripts/hello-world-wrangler.toml +1 -0
  38. package/src/__tests__/helpers/worker-scripts/parent-worker.js +8 -0
  39. package/src/__tests__/helpers/worker-scripts/parent-wrangler.toml +5 -0
  40. package/src/__tests__/index.test.ts +103 -97
  41. package/src/__tests__/init.test.ts +1484 -382
  42. package/src/__tests__/jest.setup.ts +88 -5
  43. package/src/__tests__/kv.test.ts +655 -540
  44. package/src/__tests__/logout.test.ts +47 -0
  45. package/src/__tests__/metrics.test.ts +95 -45
  46. package/src/__tests__/middleware.scheduled.test.ts +145 -0
  47. package/src/__tests__/middleware.test.ts +750 -0
  48. package/src/__tests__/pages-deployment-tail.test.ts +884 -0
  49. package/src/__tests__/pages.test.ts +1301 -119
  50. package/src/__tests__/paths.test.ts +39 -0
  51. package/src/__tests__/publish.test.ts +2266 -1180
  52. package/src/__tests__/pubsub.test.ts +211 -88
  53. package/src/__tests__/queues.test.ts +522 -0
  54. package/src/__tests__/r2.test.ts +363 -203
  55. package/src/__tests__/secret.test.ts +261 -59
  56. package/src/__tests__/tail.test.ts +352 -151
  57. package/src/__tests__/test-old-node-version.js +3 -3
  58. package/src/__tests__/tsconfig-sanity.ts +12 -0
  59. package/src/__tests__/tsconfig.json +8 -0
  60. package/src/__tests__/tsconfig.tsbuildinfo +1 -0
  61. package/src/__tests__/type-generation.test.ts +233 -0
  62. package/src/__tests__/user.test.ts +59 -73
  63. package/src/__tests__/utils-collectKeyValues.test.ts +47 -0
  64. package/src/__tests__/validate-dev-props.test.ts +56 -0
  65. package/src/__tests__/whoami.test.tsx +114 -66
  66. package/src/__tests__/worker-namespace.test.ts +154 -155
  67. package/src/api/dev.ts +170 -38
  68. package/src/api/index.ts +1 -0
  69. package/src/bundle-reporter.tsx +41 -2
  70. package/src/bundle.ts +668 -81
  71. package/src/cfetch/index.ts +40 -3
  72. package/src/cfetch/internal.ts +144 -32
  73. package/src/cli.ts +4 -3
  74. package/src/config/config.ts +27 -3
  75. package/src/config/environment.ts +131 -7
  76. package/src/config/index.ts +128 -8
  77. package/src/config/validation-helpers.ts +19 -6
  78. package/src/config/validation.ts +411 -14
  79. package/src/config-cache.ts +3 -2
  80. package/src/create-worker-preview.ts +31 -6
  81. package/src/create-worker-upload-form.ts +84 -22
  82. package/src/d1/backups.tsx +223 -0
  83. package/src/d1/constants.ts +2 -0
  84. package/src/d1/create.tsx +63 -0
  85. package/src/d1/delete.tsx +56 -0
  86. package/src/d1/execute.tsx +352 -0
  87. package/src/d1/formatTimeAgo.ts +14 -0
  88. package/src/d1/index.ts +101 -0
  89. package/src/d1/list.tsx +48 -0
  90. package/src/d1/migrations/apply.tsx +196 -0
  91. package/src/d1/migrations/create.tsx +77 -0
  92. package/src/d1/migrations/helpers.ts +147 -0
  93. package/src/d1/migrations/index.tsx +3 -0
  94. package/src/d1/migrations/list.tsx +79 -0
  95. package/src/d1/migrations/options.ts +18 -0
  96. package/src/d1/options.ts +22 -0
  97. package/src/d1/types.tsx +24 -0
  98. package/src/d1/utils.ts +48 -0
  99. package/src/delete.ts +108 -0
  100. package/src/deployments.ts +83 -0
  101. package/src/deprecated/index.ts +145 -0
  102. package/src/dev/dev-vars.ts +11 -8
  103. package/src/dev/dev.tsx +220 -58
  104. package/src/dev/get-local-persistence-path.tsx +31 -0
  105. package/src/dev/local.tsx +740 -181
  106. package/src/dev/remote.tsx +340 -123
  107. package/src/dev/start-server.ts +543 -0
  108. package/src/dev/use-esbuild.ts +61 -7
  109. package/src/dev/validate-dev-props.ts +31 -0
  110. package/src/dev-registry.tsx +201 -0
  111. package/src/dev.tsx +614 -258
  112. package/src/dialogs.tsx +41 -8
  113. package/src/{worker-namespace.ts → dispatch-namespace.ts} +23 -22
  114. package/src/docs/index.ts +97 -0
  115. package/src/entry.ts +3 -2
  116. package/src/environment-variables/factory.ts +88 -0
  117. package/src/environment-variables/misc-variables.ts +30 -0
  118. package/src/generate/index.ts +300 -0
  119. package/src/git-client.ts +100 -7
  120. package/src/index.tsx +249 -1560
  121. package/src/init.ts +626 -150
  122. package/src/inspect.ts +137 -32
  123. package/src/{metrics/is-ci.ts → is-ci.ts} +0 -0
  124. package/src/is-interactive.ts +4 -0
  125. package/src/jest.d.ts +4 -0
  126. package/src/{kv.ts → kv/helpers.ts} +3 -3
  127. package/src/kv/index.ts +596 -0
  128. package/src/logger.ts +27 -8
  129. package/src/metrics/index.ts +1 -0
  130. package/src/metrics/metrics-config.ts +4 -4
  131. package/src/metrics/metrics-dispatcher.ts +1 -0
  132. package/src/metrics/metrics-usage-headers.ts +24 -0
  133. package/src/metrics/send-event.ts +13 -8
  134. package/src/miniflare-cli/assets.ts +172 -465
  135. package/src/miniflare-cli/index.ts +149 -24
  136. package/src/miniflare-cli/tsconfig.json +9 -0
  137. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
  138. package/src/miniflare-cli/types.ts +11 -0
  139. package/src/module-collection.ts +12 -3
  140. package/src/pages/build.tsx +108 -42
  141. package/src/pages/constants.ts +11 -0
  142. package/src/pages/deployment-tails.tsx +284 -0
  143. package/src/pages/deployments.tsx +9 -31
  144. package/src/pages/dev.tsx +417 -108
  145. package/src/pages/errors.ts +66 -0
  146. package/src/pages/functions/buildPlugin.ts +86 -84
  147. package/src/pages/functions/buildWorker.ts +121 -106
  148. package/src/pages/functions/routes-consolidation.test.ts +250 -0
  149. package/src/pages/functions/routes-consolidation.ts +73 -0
  150. package/src/pages/functions/routes-transformation.test.ts +282 -0
  151. package/src/pages/functions/routes-transformation.ts +115 -0
  152. package/src/pages/functions/routes-validation.test.ts +403 -0
  153. package/src/pages/functions/routes-validation.ts +202 -0
  154. package/src/pages/functions/tsconfig.json +8 -0
  155. package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
  156. package/src/pages/functions.tsx +82 -0
  157. package/src/pages/hash.tsx +13 -0
  158. package/src/pages/index.tsx +73 -55
  159. package/src/pages/projects.tsx +9 -3
  160. package/src/pages/prompt-select-project.tsx +31 -0
  161. package/src/pages/publish.tsx +183 -60
  162. package/src/pages/types.ts +1 -0
  163. package/src/pages/upload.tsx +107 -56
  164. package/src/pages/utils.ts +13 -2
  165. package/src/paths.ts +49 -4
  166. package/src/proxy.ts +375 -157
  167. package/src/publish/index.ts +270 -0
  168. package/src/{publish.ts → publish/publish.ts} +431 -188
  169. package/src/pubsub/pubsub-commands.tsx +4 -3
  170. package/src/queues/cli/commands/consumer/add.ts +71 -0
  171. package/src/queues/cli/commands/consumer/index.ts +22 -0
  172. package/src/queues/cli/commands/consumer/remove.ts +38 -0
  173. package/src/queues/cli/commands/create.ts +25 -0
  174. package/src/queues/cli/commands/delete.ts +26 -0
  175. package/src/queues/cli/commands/index.ts +36 -0
  176. package/src/queues/cli/commands/list.ts +25 -0
  177. package/src/queues/client.ts +135 -0
  178. package/src/queues/utils.ts +18 -0
  179. package/src/r2/constants.ts +4 -0
  180. package/src/r2/helpers.ts +131 -0
  181. package/src/r2/index.ts +289 -0
  182. package/src/routes.ts +140 -0
  183. package/src/secret/index.ts +379 -0
  184. package/src/sites.tsx +3 -3
  185. package/src/tail/createTail.ts +379 -0
  186. package/src/tail/filters.ts +4 -6
  187. package/src/tail/index.ts +199 -284
  188. package/src/tail/printing.ts +43 -3
  189. package/src/tsconfig-sanity.ts +16 -0
  190. package/src/type-generation.ts +181 -0
  191. package/src/user/access.ts +68 -0
  192. package/src/user/auth-variables.ts +113 -0
  193. package/src/user/choose-account.tsx +1 -1
  194. package/src/user/index.ts +0 -1
  195. package/src/user/user.tsx +116 -49
  196. package/src/utils/collectKeyValues.ts +14 -0
  197. package/src/whoami.tsx +80 -2
  198. package/src/worker.ts +69 -9
  199. package/src/yargs-types.ts +24 -0
  200. package/src/zones.ts +124 -9
  201. package/templates/__tests__/pages-dev-util.test.ts +128 -0
  202. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  203. package/templates/__tests__/tsconfig.json +8 -0
  204. package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
  205. package/templates/d1-beta-facade.js +205 -0
  206. package/templates/facade.d.ts +14 -0
  207. package/templates/first-party-worker-module-facade.ts +19 -0
  208. package/templates/format-dev-errors.ts +33 -0
  209. package/templates/init-tests/test-jest-new-worker.js +23 -0
  210. package/templates/init-tests/test-vitest-new-worker.js +24 -0
  211. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  212. package/templates/middleware/common.ts +62 -0
  213. package/templates/middleware/loader-modules.ts +82 -0
  214. package/templates/middleware/loader-sw.ts +233 -0
  215. package/templates/middleware/middleware-miniflare3-json-error.ts +20 -0
  216. package/templates/middleware/middleware-pretty-error.ts +40 -0
  217. package/templates/middleware/middleware-scheduled.ts +15 -0
  218. package/templates/new-worker.js +1 -1
  219. package/templates/pages-dev-pipeline.ts +31 -0
  220. package/templates/pages-dev-util.ts +52 -0
  221. package/templates/pages-shim.ts +4 -1
  222. package/templates/pages-template-plugin.ts +21 -5
  223. package/templates/pages-template-worker.ts +37 -9
  224. package/templates/{static-asset-facade.js → serve-static-assets.ts} +23 -7
  225. package/templates/service-bindings-module-facade.js +54 -0
  226. package/templates/service-bindings-sw-facade.js +42 -0
  227. package/templates/tsconfig-sanity.ts +11 -0
  228. package/templates/tsconfig.init.json +106 -0
  229. package/templates/tsconfig.json +5 -102
  230. package/templates/tsconfig.tsbuildinfo +1 -0
  231. package/wrangler-dist/cli.d.ts +621 -42
  232. package/wrangler-dist/cli.js +144441 -102606
  233. package/src/environment-variables.ts +0 -35
  234. package/src/faye-websocket.d.ts +0 -6
  235. package/src/generate.ts +0 -33
  236. package/src/miniflare-cli/enum-keys.ts +0 -17
  237. package/src/preview.ts +0 -31
  238. package/src/r2.ts +0 -50
  239. package/src/user/env-vars.ts +0 -46
@@ -9,7 +9,7 @@ import {
9
9
  } from "../create-worker-preview";
10
10
  import useInspector from "../inspect";
11
11
  import { logger } from "../logger";
12
- import { usePreviewServer } from "../proxy";
12
+ import { startPreviewServer, usePreviewServer } from "../proxy";
13
13
  import { syncAssets } from "../sites";
14
14
  import {
15
15
  ChooseAccount,
@@ -33,7 +33,7 @@ import type {
33
33
  } from "../worker";
34
34
  import type { EsbuildBundle } from "./use-esbuild";
35
35
 
36
- export function Remote(props: {
36
+ interface RemoteProps {
37
37
  name: string | undefined;
38
38
  bundle: EsbuildBundle | undefined;
39
39
  format: CfScriptFormat | undefined;
@@ -54,8 +54,12 @@ export function Remote(props: {
54
54
  zone: string | undefined;
55
55
  host: string | undefined;
56
56
  routes: Route[] | undefined;
57
- onReady?: (() => void) | undefined;
58
- }) {
57
+ onReady?: ((ip: string, port: number) => void) | undefined;
58
+ sourceMapPath: string | undefined;
59
+ sendMetrics: boolean | undefined;
60
+ }
61
+
62
+ export function Remote(props: RemoteProps) {
59
63
  const [accountId, setAccountId] = useState(props.accountId);
60
64
  const accountChoicesRef = useRef<Promise<ChooseAccountItem[]>>();
61
65
  const [accountChoices, setAccountChoices] = useState<ChooseAccountItem[]>();
@@ -69,7 +73,6 @@ export function Remote(props: {
69
73
  bindings: props.bindings,
70
74
  assetPaths: props.assetPaths,
71
75
  isWorkersSite: props.isWorkersSite,
72
- port: props.port,
73
76
  compatibilityDate: props.compatibilityDate,
74
77
  compatibilityFlags: props.compatibilityFlags,
75
78
  usageModel: props.usageModel,
@@ -79,6 +82,8 @@ export function Remote(props: {
79
82
  host: props.host,
80
83
  routes: props.routes,
81
84
  onReady: props.onReady,
85
+ sendMetrics: props.sendMetrics,
86
+ port: props.port,
82
87
  });
83
88
 
84
89
  usePreviewServer({
@@ -98,6 +103,8 @@ export function Remote(props: {
98
103
  : undefined,
99
104
  port: props.inspectorPort,
100
105
  logToTerminal: true,
106
+ sourceMapPath: props.sourceMapPath,
107
+ host: previewToken?.host,
101
108
  });
102
109
 
103
110
  const errorHandler = useErrorHandler();
@@ -144,7 +151,7 @@ export function Remote(props: {
144
151
  ) : null;
145
152
  }
146
153
 
147
- export function useWorker(props: {
154
+ interface RemoteWorkerProps {
148
155
  name: string | undefined;
149
156
  bundle: EsbuildBundle | undefined;
150
157
  format: CfScriptFormat | undefined;
@@ -153,7 +160,6 @@ export function useWorker(props: {
153
160
  bindings: CfWorkerInit["bindings"];
154
161
  assetPaths: AssetPaths | undefined;
155
162
  isWorkersSite: boolean;
156
- port: number;
157
163
  compatibilityDate: string | undefined;
158
164
  compatibilityFlags: string[] | undefined;
159
165
  usageModel: "bundled" | "unbound" | undefined;
@@ -162,63 +168,63 @@ export function useWorker(props: {
162
168
  zone: string | undefined;
163
169
  host: string | undefined;
164
170
  routes: Route[] | undefined;
165
- onReady: (() => void) | undefined;
166
- }): CfPreviewToken | undefined {
167
- const {
168
- name,
169
- bundle,
170
- format,
171
- modules,
172
- accountId,
173
- bindings,
174
- assetPaths,
175
- compatibilityDate,
176
- compatibilityFlags,
177
- usageModel,
178
- port,
179
- onReady,
180
- } = props;
171
+ onReady: ((ip: string, port: number) => void) | undefined;
172
+ sendMetrics: boolean | undefined;
173
+ port: number;
174
+ }
175
+
176
+ export function useWorker(
177
+ props: RemoteWorkerProps
178
+ ): CfPreviewToken | undefined {
181
179
  const [session, setSession] = useState<CfPreviewSession | undefined>();
182
180
  const [token, setToken] = useState<CfPreviewToken | undefined>();
183
-
181
+ const [restartCounter, setRestartCounter] = useState<number>(0);
184
182
  // This is the most reliable way to detect whether
185
183
  // something's "happened" in our system; We make a ref and
186
184
  // mark it once we log our initial message. Refs are vars!
187
185
  const startedRef = useRef(false);
188
-
186
+ // functions must be destructured before use inside a useEffect, otherwise the entire props object has to be added to the dependency array
187
+ const { onReady } = props;
189
188
  // This effect sets up the preview session
190
189
  useEffect(() => {
191
190
  const abortController = new AbortController();
192
191
  async function start() {
193
- if (accountId === undefined) {
192
+ if (props.accountId === undefined) {
194
193
  return;
195
194
  }
196
-
197
- const workerAccount: CfAccount = {
198
- accountId,
199
- apiToken: requireApiToken(),
200
- };
201
-
202
- const workerCtx: CfWorkerContext = {
195
+ const { workerAccount, workerContext } = getWorkerAccountAndContext({
196
+ accountId: props.accountId,
203
197
  env: props.env,
204
198
  legacyEnv: props.legacyEnv,
205
199
  zone: props.zone,
206
200
  host: props.host,
207
201
  routes: props.routes,
208
- };
202
+ sendMetrics: props.sendMetrics,
203
+ });
209
204
 
210
205
  setSession(
211
206
  await createPreviewSession(
212
207
  workerAccount,
213
- workerCtx,
208
+ workerContext,
214
209
  abortController.signal
215
210
  )
216
211
  );
217
212
  }
218
213
  start().catch((err) => {
214
+ // instead of logging the raw API error to the user,
215
+ // give them friendly instructions
216
+ // for error 10063 (workers.dev subdomain required)
217
+ if (err.code === 10063) {
218
+ const errorMessage =
219
+ "Error: You need to register a workers.dev subdomain before running the dev command in remote mode";
220
+ const solutionMessage =
221
+ "You can either enable local mode by pressing l, or register a workers.dev subdomain here:";
222
+ const onboardingLink = `https://dash.cloudflare.com/${props.accountId}/workers/onboarding`;
223
+ logger.error(`${errorMessage}\n${solutionMessage}\n${onboardingLink}`);
224
+ }
219
225
  // we want to log the error, but not end the process
220
226
  // since it could recover after the developer fixes whatever's wrong
221
- if ((err as { code: string }).code !== "ABORT_ERR") {
227
+ else if ((err as { code: string }).code !== "ABORT_ERR") {
222
228
  logger.error("Error while creating remote dev session:", err);
223
229
  }
224
230
  });
@@ -227,19 +233,21 @@ export function useWorker(props: {
227
233
  abortController.abort();
228
234
  };
229
235
  }, [
230
- accountId,
236
+ props.accountId,
231
237
  props.env,
232
238
  props.host,
233
239
  props.legacyEnv,
234
240
  props.routes,
235
241
  props.zone,
242
+ props.sendMetrics,
243
+ restartCounter,
236
244
  ]);
237
245
 
238
246
  // This effect uses the session to upload the worker and create a preview
239
247
  useEffect(() => {
240
248
  const abortController = new AbortController();
241
249
  async function start() {
242
- if (accountId === undefined) {
250
+ if (props.accountId === undefined) {
243
251
  return;
244
252
  }
245
253
  if (session === undefined) {
@@ -247,7 +255,7 @@ export function useWorker(props: {
247
255
  }
248
256
  setToken(undefined); // reset token in case we're re-running
249
257
 
250
- if (!bundle || !format) return;
258
+ if (!props.bundle || !props.format) return;
251
259
 
252
260
  if (!startedRef.current) {
253
261
  startedRef.current = true;
@@ -255,86 +263,63 @@ export function useWorker(props: {
255
263
  logger.log("⎔ Detected changes, restarted server.");
256
264
  }
257
265
 
258
- const content = await readFile(bundle.path, "utf-8");
259
-
260
- // TODO: For Dev we could show the reporter message in the interactive box.
261
- void printBundleSize(
262
- { name: path.basename(bundle.path), content: content },
263
- modules
264
- );
266
+ const init = await createRemoteWorkerInit({
267
+ bundle: props.bundle,
268
+ modules: props.modules,
269
+ accountId: props.accountId,
270
+ name: props.name,
271
+ legacyEnv: props.legacyEnv,
272
+ env: props.env,
273
+ isWorkersSite: props.isWorkersSite,
274
+ assetPaths: props.assetPaths,
275
+ format: props.format,
276
+ bindings: props.bindings,
277
+ compatibilityDate: props.compatibilityDate,
278
+ compatibilityFlags: props.compatibilityFlags,
279
+ usageModel: props.usageModel,
280
+ });
265
281
 
266
- const assets = await syncAssets(
267
- accountId,
268
- // When we're using the newer service environments, we wouldn't
269
- // have added the env name on to the script name. However, we must
270
- // include it in the kv namespace name regardless (since there's no
271
- // concept of service environments for kv namespaces yet).
272
- name + (!props.legacyEnv && props.env ? `-${props.env}` : ""),
273
- props.isWorkersSite ? assetPaths : undefined,
274
- true,
275
- false
276
- ); // TODO: cancellable?
277
-
278
- const init: CfWorkerInit = {
279
- name,
280
- main: {
281
- name: path.basename(bundle.path),
282
- type: format === "modules" ? "esm" : "commonjs",
283
- content,
284
- },
285
- modules: modules.concat(
286
- assets.manifest
287
- ? {
288
- name: "__STATIC_CONTENT_MANIFEST",
289
- content: JSON.stringify(assets.manifest),
290
- type: "text",
291
- }
292
- : []
293
- ),
294
- bindings: {
295
- ...bindings,
296
- kv_namespaces: (bindings.kv_namespaces || []).concat(
297
- assets.namespace
298
- ? { binding: "__STATIC_CONTENT", id: assets.namespace }
299
- : []
300
- ),
301
- text_blobs: {
302
- ...bindings.text_blobs,
303
- ...(assets.manifest &&
304
- format === "service-worker" && {
305
- __STATIC_CONTENT_MANIFEST: "__STATIC_CONTENT_MANIFEST",
306
- }),
307
- },
308
- },
309
- migrations: undefined, // no migrations in dev
310
- compatibility_date: compatibilityDate,
311
- compatibility_flags: compatibilityFlags,
312
- usage_model: usageModel,
313
- };
314
-
315
- const workerAccount: CfAccount = {
316
- accountId,
317
- apiToken: requireApiToken(),
318
- };
319
-
320
- const workerCtx: CfWorkerContext = {
282
+ const { workerAccount, workerContext } = getWorkerAccountAndContext({
283
+ accountId: props.accountId,
321
284
  env: props.env,
322
285
  legacyEnv: props.legacyEnv,
323
286
  zone: props.zone,
324
287
  host: props.host,
325
288
  routes: props.routes,
326
- };
289
+ sendMetrics: props.sendMetrics,
290
+ });
327
291
 
328
- setToken(
329
- await createWorkerPreview(
330
- init,
331
- workerAccount,
332
- workerCtx,
333
- session,
334
- abortController.signal
335
- )
292
+ const workerPreviewToken = await createWorkerPreview(
293
+ init,
294
+ workerAccount,
295
+ workerContext,
296
+ session,
297
+ abortController.signal
336
298
  );
337
- onReady?.();
299
+
300
+ setToken(workerPreviewToken);
301
+
302
+ // TODO: Once we get service bindings working in the
303
+ // edge preview server, we can define remote dev service bindings
304
+ // and you can uncomment this code.
305
+ // https://github.com/cloudflare/wrangler2/issues/1182
306
+
307
+ /*
308
+ if (name) {
309
+ await registerWorker(name, {
310
+ mode: "remote",
311
+ // upstream protocol is always https (https://github.com/cloudflare/wrangler2/issues/583)
312
+ protocol: "https",
313
+ port: undefined,
314
+ host: workerPreviewToken.host,
315
+ headers: {
316
+ "cf-workers-preview-token": workerPreviewToken.value,
317
+ host: workerPreviewToken.host,
318
+ },
319
+ });
320
+ }
321
+ */
322
+ onReady?.(props.host || "localhost", props.port);
338
323
  }
339
324
  start().catch((err) => {
340
325
  // we want to log the error, but not end the process
@@ -348,10 +333,17 @@ export function useWorker(props: {
348
333
  "Error: You need to register a workers.dev subdomain before running the dev command in remote mode";
349
334
  const solutionMessage =
350
335
  "You can either enable local mode by pressing l, or register a workers.dev subdomain here:";
351
- const onboardingLink = `https://dash.cloudflare.com/${accountId}/workers/onboarding`;
336
+ const onboardingLink = `https://dash.cloudflare.com/${props.accountId}/workers/onboarding`;
352
337
  logger.error(
353
338
  `${errorMessage}\n${solutionMessage}\n${onboardingLink}`
354
339
  );
340
+ } else if (err.code === 10049) {
341
+ logger.log("Preview token expired, fetching a new one");
342
+ // code 10049 happens when the preview token expires
343
+ // since we want a new preview token when this happens,
344
+ // lets increment the counter, and trigger a rerun of
345
+ // the useEffect above
346
+ setRestartCounter((prevCount) => prevCount + 1);
355
347
  } else {
356
348
  logger.error("Error on remote worker:", err);
357
349
  }
@@ -362,18 +354,17 @@ export function useWorker(props: {
362
354
  abortController.abort();
363
355
  };
364
356
  }, [
365
- name,
366
- bundle,
367
- format,
368
- accountId,
369
- port,
370
- assetPaths,
357
+ props.name,
358
+ props.bundle,
359
+ props.format,
360
+ props.accountId,
361
+ props.assetPaths,
371
362
  props.isWorkersSite,
372
- compatibilityDate,
373
- compatibilityFlags,
374
- usageModel,
375
- bindings,
376
- modules,
363
+ props.compatibilityDate,
364
+ props.compatibilityFlags,
365
+ props.usageModel,
366
+ props.bindings,
367
+ props.modules,
377
368
  props.env,
378
369
  props.legacyEnv,
379
370
  props.zone,
@@ -381,6 +372,232 @@ export function useWorker(props: {
381
372
  props.routes,
382
373
  session,
383
374
  onReady,
375
+ props.sendMetrics,
376
+ props.port,
384
377
  ]);
378
+
385
379
  return token;
386
380
  }
381
+
382
+ export async function startRemoteServer(props: RemoteProps) {
383
+ let accountId = props.accountId;
384
+ if (accountId === undefined) {
385
+ const accountChoices = await getAccountChoices();
386
+ if (accountChoices.length === 1) {
387
+ saveAccountToCache({
388
+ id: accountChoices[0].id,
389
+ name: accountChoices[0].name,
390
+ });
391
+ accountId = accountChoices[0].id;
392
+ } else {
393
+ throw logger.error(
394
+ "In a non-interactive environment, it is mandatory to specify an account ID, either by assigning its value to CLOUDFLARE_ACCOUNT_ID, or as `account_id` in your `wrangler.toml` file."
395
+ );
396
+ }
397
+ }
398
+
399
+ const previewToken = await getRemotePreviewToken({
400
+ ...props,
401
+ accountId: accountId,
402
+ });
403
+
404
+ if (previewToken === undefined) {
405
+ throw logger.error("Failed to get a previewToken");
406
+ }
407
+ // start our proxy server
408
+ const previewServer = await startPreviewServer({
409
+ previewToken,
410
+ assetDirectory: props.isWorkersSite
411
+ ? undefined
412
+ : props.assetPaths?.assetDirectory,
413
+ localProtocol: props.localProtocol,
414
+ localPort: props.port,
415
+ ip: props.ip,
416
+ onReady: props.onReady,
417
+ });
418
+ if (!previewServer) {
419
+ throw logger.error("Failed to start remote server");
420
+ }
421
+ return { stop: previewServer.stop };
422
+ }
423
+
424
+ /**
425
+ * getRemotePreviewToken is a react-free version of `useWorker`.
426
+ * It returns a preview token, which we then use in our proxy server
427
+ */
428
+ export async function getRemotePreviewToken(props: RemoteProps) {
429
+ //setup the preview session
430
+ async function start() {
431
+ if (props.accountId === undefined) {
432
+ throw logger.error("no accountId provided");
433
+ }
434
+ const abortController = new AbortController();
435
+ const { workerAccount, workerContext } = getWorkerAccountAndContext({
436
+ accountId: props.accountId,
437
+ env: props.env,
438
+ legacyEnv: props.legacyEnv,
439
+ zone: props.zone,
440
+ host: props.host,
441
+ routes: props.routes,
442
+ sendMetrics: props.sendMetrics,
443
+ });
444
+ const session = await createPreviewSession(
445
+ workerAccount,
446
+ workerContext,
447
+ abortController.signal
448
+ );
449
+ //use the session to upload the worker, and create a preview
450
+
451
+ if (session === undefined) {
452
+ throw logger.error("Failed to start a session");
453
+ }
454
+ if (!props.bundle || !props.format) return;
455
+
456
+ const init = await createRemoteWorkerInit({
457
+ bundle: props.bundle,
458
+ modules: props.bundle ? props.bundle.modules : [],
459
+ accountId: props.accountId,
460
+ name: props.name,
461
+ legacyEnv: props.legacyEnv,
462
+ env: props.env,
463
+ isWorkersSite: props.isWorkersSite,
464
+ assetPaths: props.assetPaths,
465
+ format: props.format,
466
+ bindings: props.bindings,
467
+ compatibilityDate: props.compatibilityDate,
468
+ compatibilityFlags: props.compatibilityFlags,
469
+ usageModel: props.usageModel,
470
+ });
471
+ const workerPreviewToken = await createWorkerPreview(
472
+ init,
473
+ workerAccount,
474
+ workerContext,
475
+ session,
476
+ abortController.signal
477
+ );
478
+ return workerPreviewToken;
479
+ }
480
+ return start().catch((err) => {
481
+ if ((err as { code?: string })?.code !== "ABORT_ERR") {
482
+ // instead of logging the raw API error to the user,
483
+ // give them friendly instructions
484
+ // for error 10063 (workers.dev subdomain required)
485
+ if (err?.code === 10063) {
486
+ const errorMessage =
487
+ "Error: You need to register a workers.dev subdomain before running the dev command in remote mode";
488
+ const solutionMessage =
489
+ "You can either enable local mode by pressing l, or register a workers.dev subdomain here:";
490
+ const onboardingLink = `https://dash.cloudflare.com/${props.accountId}/workers/onboarding`;
491
+ logger.error(`${errorMessage}\n${solutionMessage}\n${onboardingLink}`);
492
+ } else if (err?.code === 10049) {
493
+ // code 10049 happens when the preview token expires
494
+ logger.log("Preview token expired, restart server to fetch a new one");
495
+ } else {
496
+ logger.error("Error on remote worker:", err);
497
+ }
498
+ }
499
+ });
500
+ }
501
+
502
+ async function createRemoteWorkerInit(props: {
503
+ bundle: EsbuildBundle;
504
+ modules: CfModule[];
505
+ accountId: string;
506
+ name: string | undefined;
507
+ legacyEnv: boolean | undefined;
508
+ env: string | undefined;
509
+ isWorkersSite: boolean;
510
+ assetPaths: AssetPaths | undefined;
511
+ format: CfScriptFormat;
512
+ bindings: CfWorkerInit["bindings"];
513
+ compatibilityDate: string | undefined;
514
+ compatibilityFlags: string[] | undefined;
515
+ usageModel: "bundled" | "unbound" | undefined;
516
+ }) {
517
+ const content = await readFile(props.bundle.path, "utf-8");
518
+
519
+ // TODO: For Dev we could show the reporter message in the interactive box.
520
+ void printBundleSize(
521
+ { name: path.basename(props.bundle.path), content: content },
522
+ props.modules
523
+ );
524
+
525
+ const assets = await syncAssets(
526
+ props.accountId,
527
+ // When we're using the newer service environments, we wouldn't
528
+ // have added the env name on to the script name. However, we must
529
+ // include it in the kv namespace name regardless (since there's no
530
+ // concept of service environments for kv namespaces yet).
531
+ props.name + (!props.legacyEnv && props.env ? `-${props.env}` : ""),
532
+ props.isWorkersSite ? props.assetPaths : undefined,
533
+ true,
534
+ false
535
+ ); // TODO: cancellable?
536
+
537
+ const init: CfWorkerInit = {
538
+ name: props.name,
539
+ main: {
540
+ name: path.basename(props.bundle.path),
541
+ type: props.format === "modules" ? "esm" : "commonjs",
542
+ content,
543
+ },
544
+ modules: props.modules.concat(
545
+ assets.manifest
546
+ ? {
547
+ name: "__STATIC_CONTENT_MANIFEST",
548
+ content: JSON.stringify(assets.manifest),
549
+ type: "text",
550
+ }
551
+ : []
552
+ ),
553
+ bindings: {
554
+ ...props.bindings,
555
+ kv_namespaces: (props.bindings.kv_namespaces || []).concat(
556
+ assets.namespace
557
+ ? { binding: "__STATIC_CONTENT", id: assets.namespace }
558
+ : []
559
+ ),
560
+ text_blobs: {
561
+ ...props.bindings.text_blobs,
562
+ ...(assets.manifest &&
563
+ props.format === "service-worker" && {
564
+ __STATIC_CONTENT_MANIFEST: "__STATIC_CONTENT_MANIFEST",
565
+ }),
566
+ },
567
+ },
568
+ migrations: undefined, // no migrations in dev
569
+ compatibility_date: props.compatibilityDate,
570
+ compatibility_flags: props.compatibilityFlags,
571
+ usage_model: props.usageModel,
572
+ keepVars: true,
573
+ logpush: false,
574
+ };
575
+
576
+ return init;
577
+ }
578
+
579
+ function getWorkerAccountAndContext(props: {
580
+ accountId: string;
581
+ env?: string;
582
+ legacyEnv?: boolean;
583
+ zone?: string;
584
+ host?: string;
585
+ routes: Route[] | undefined;
586
+ sendMetrics?: boolean;
587
+ }): { workerAccount: CfAccount; workerContext: CfWorkerContext } {
588
+ const workerAccount: CfAccount = {
589
+ accountId: props.accountId,
590
+ apiToken: requireApiToken(),
591
+ };
592
+
593
+ const workerContext: CfWorkerContext = {
594
+ env: props.env,
595
+ legacyEnv: props.legacyEnv,
596
+ zone: props.zone,
597
+ host: props.host,
598
+ routes: props.routes,
599
+ sendMetrics: props.sendMetrics,
600
+ };
601
+
602
+ return { workerAccount, workerContext };
603
+ }