wrangler 2.0.12 → 2.0.16

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 (149) hide show
  1. package/README.md +7 -1
  2. package/bin/wrangler.js +111 -57
  3. package/miniflare-dist/index.mjs +9 -2
  4. package/package.json +156 -154
  5. package/src/__tests__/config-cache-without-cache-dir.test.ts +38 -0
  6. package/src/__tests__/config-cache.test.ts +30 -24
  7. package/src/__tests__/configuration.test.ts +3935 -3476
  8. package/src/__tests__/dev.test.tsx +1128 -979
  9. package/src/__tests__/guess-worker-format.test.ts +68 -68
  10. package/src/__tests__/helpers/cmd-shim.d.ts +6 -6
  11. package/src/__tests__/helpers/faye-websocket.d.ts +4 -4
  12. package/src/__tests__/helpers/mock-account-id.ts +24 -24
  13. package/src/__tests__/helpers/mock-bin.ts +20 -20
  14. package/src/__tests__/helpers/mock-cfetch.ts +92 -92
  15. package/src/__tests__/helpers/mock-console.ts +49 -39
  16. package/src/__tests__/helpers/mock-dialogs.ts +94 -71
  17. package/src/__tests__/helpers/mock-http-server.ts +30 -30
  18. package/src/__tests__/helpers/mock-istty.ts +65 -18
  19. package/src/__tests__/helpers/mock-kv.ts +26 -26
  20. package/src/__tests__/helpers/mock-oauth-flow.ts +223 -228
  21. package/src/__tests__/helpers/mock-process.ts +39 -0
  22. package/src/__tests__/helpers/mock-stdin.ts +82 -77
  23. package/src/__tests__/helpers/mock-web-socket.ts +21 -21
  24. package/src/__tests__/helpers/run-in-tmp.ts +27 -27
  25. package/src/__tests__/helpers/run-wrangler.ts +8 -8
  26. package/src/__tests__/helpers/write-worker-source.ts +16 -16
  27. package/src/__tests__/helpers/write-wrangler-toml.ts +9 -9
  28. package/src/__tests__/https-options.test.ts +104 -104
  29. package/src/__tests__/index.test.ts +239 -234
  30. package/src/__tests__/init.test.ts +1605 -1250
  31. package/src/__tests__/jest.setup.ts +63 -33
  32. package/src/__tests__/kv.test.ts +1128 -1011
  33. package/src/__tests__/logger.test.ts +100 -74
  34. package/src/__tests__/package-manager.test.ts +303 -303
  35. package/src/__tests__/pages.test.ts +1152 -652
  36. package/src/__tests__/parse.test.ts +252 -252
  37. package/src/__tests__/publish.test.ts +6371 -5622
  38. package/src/__tests__/pubsub.test.ts +367 -0
  39. package/src/__tests__/r2.test.ts +133 -133
  40. package/src/__tests__/route.test.ts +18 -18
  41. package/src/__tests__/secret.test.ts +382 -377
  42. package/src/__tests__/tail.test.ts +530 -530
  43. package/src/__tests__/user.test.ts +123 -111
  44. package/src/__tests__/whoami.test.tsx +198 -117
  45. package/src/__tests__/worker-namespace.test.ts +327 -0
  46. package/src/abort.d.ts +1 -1
  47. package/src/api/dev.ts +49 -0
  48. package/src/api/index.ts +1 -0
  49. package/src/bundle-reporter.tsx +29 -0
  50. package/src/bundle.ts +157 -149
  51. package/src/cfetch/index.ts +80 -80
  52. package/src/cfetch/internal.ts +90 -83
  53. package/src/cli.ts +21 -7
  54. package/src/config/config.ts +204 -195
  55. package/src/config/diagnostics.ts +61 -61
  56. package/src/config/environment.ts +390 -357
  57. package/src/config/index.ts +206 -193
  58. package/src/config/validation-helpers.ts +366 -366
  59. package/src/config/validation.ts +1573 -1376
  60. package/src/config-cache.ts +79 -41
  61. package/src/create-worker-preview.ts +206 -136
  62. package/src/create-worker-upload-form.ts +247 -238
  63. package/src/dev/dev-vars.ts +13 -13
  64. package/src/dev/dev.tsx +329 -307
  65. package/src/dev/local.tsx +304 -275
  66. package/src/dev/remote.tsx +366 -224
  67. package/src/dev/use-esbuild.ts +126 -91
  68. package/src/dev.tsx +538 -0
  69. package/src/dialogs.tsx +97 -97
  70. package/src/durable.ts +87 -87
  71. package/src/entry.ts +234 -228
  72. package/src/environment-variables.ts +23 -23
  73. package/src/errors.ts +6 -6
  74. package/src/generate.ts +33 -0
  75. package/src/git-client.ts +42 -0
  76. package/src/https-options.ts +79 -79
  77. package/src/index.tsx +1775 -2763
  78. package/src/init.ts +549 -0
  79. package/src/inspect.ts +593 -593
  80. package/src/intl-polyfill.d.ts +123 -123
  81. package/src/is-interactive.ts +12 -0
  82. package/src/kv.ts +277 -277
  83. package/src/logger.ts +46 -39
  84. package/src/miniflare-cli/enum-keys.ts +8 -8
  85. package/src/miniflare-cli/index.ts +42 -31
  86. package/src/miniflare-cli/request-context.ts +18 -18
  87. package/src/module-collection.ts +212 -212
  88. package/src/open-in-browser.ts +4 -6
  89. package/src/package-manager.ts +123 -123
  90. package/src/pages/build.tsx +202 -0
  91. package/src/pages/constants.ts +7 -0
  92. package/src/pages/deployments.tsx +101 -0
  93. package/src/pages/dev.tsx +964 -0
  94. package/src/pages/functions/buildPlugin.ts +105 -0
  95. package/src/pages/functions/buildWorker.ts +151 -0
  96. package/{pages → src/pages}/functions/filepath-routing.test.ts +113 -113
  97. package/src/pages/functions/filepath-routing.ts +189 -0
  98. package/src/pages/functions/identifiers.ts +78 -0
  99. package/src/pages/functions/routes.ts +151 -0
  100. package/src/pages/index.tsx +84 -0
  101. package/src/pages/projects.tsx +157 -0
  102. package/src/pages/publish.tsx +335 -0
  103. package/src/pages/types.ts +40 -0
  104. package/src/pages/upload.tsx +384 -0
  105. package/src/pages/utils.ts +12 -0
  106. package/src/parse.ts +202 -138
  107. package/src/paths.ts +6 -6
  108. package/src/preview.ts +31 -0
  109. package/src/proxy.ts +400 -402
  110. package/src/publish.ts +667 -621
  111. package/src/pubsub/index.ts +286 -0
  112. package/src/pubsub/pubsub-commands.tsx +577 -0
  113. package/src/r2.ts +19 -19
  114. package/src/selfsigned.d.ts +23 -23
  115. package/src/sites.tsx +271 -225
  116. package/src/tail/filters.ts +108 -108
  117. package/src/tail/index.ts +217 -217
  118. package/src/tail/printing.ts +45 -45
  119. package/src/update-check.ts +11 -11
  120. package/src/user/choose-account.tsx +60 -0
  121. package/src/user/env-vars.ts +46 -0
  122. package/src/user/generate-auth-url.ts +33 -0
  123. package/src/user/generate-random-state.ts +16 -0
  124. package/src/user/index.ts +3 -0
  125. package/src/user/user.tsx +1161 -0
  126. package/src/whoami.tsx +61 -42
  127. package/src/worker-namespace.ts +190 -0
  128. package/src/worker.ts +110 -100
  129. package/src/zones.ts +39 -36
  130. package/templates/checked-fetch.js +17 -0
  131. package/templates/new-worker-scheduled.js +3 -3
  132. package/templates/new-worker-scheduled.ts +15 -15
  133. package/templates/new-worker.js +3 -3
  134. package/templates/new-worker.ts +15 -15
  135. package/templates/no-op-worker.js +10 -0
  136. package/templates/pages-template-plugin.ts +155 -0
  137. package/templates/pages-template-worker.ts +161 -0
  138. package/templates/static-asset-facade.js +31 -31
  139. package/templates/tsconfig.json +95 -95
  140. package/wrangler-dist/cli.js +55383 -54138
  141. package/pages/functions/buildPlugin.ts +0 -105
  142. package/pages/functions/buildWorker.ts +0 -151
  143. package/pages/functions/filepath-routing.ts +0 -189
  144. package/pages/functions/identifiers.ts +0 -78
  145. package/pages/functions/routes.ts +0 -156
  146. package/pages/functions/template-plugin.ts +0 -147
  147. package/pages/functions/template-worker.ts +0 -143
  148. package/src/pages.tsx +0 -2093
  149. package/src/user.tsx +0 -1214
package/src/dev/dev.tsx CHANGED
@@ -17,244 +17,266 @@ import { Local } from "./local";
17
17
  import { Remote } from "./remote";
18
18
  import { useEsbuild } from "./use-esbuild";
19
19
  import type { Config } from "../config";
20
+ import type { Route } from "../config/environment";
20
21
  import type { Entry } from "../entry";
21
22
  import type { AssetPaths } from "../sites";
22
23
  import type { CfWorkerInit } from "../worker";
23
24
 
24
25
  export type DevProps = {
25
- name?: string;
26
- entry: Entry;
27
- port: number;
28
- ip: string;
29
- inspectorPort: number;
30
- rules: Config["rules"];
31
- accountId: string | undefined;
32
- initialMode: "local" | "remote";
33
- jsxFactory: string | undefined;
34
- jsxFragment: string | undefined;
35
- tsconfig: string | undefined;
36
- upstreamProtocol: "https" | "http";
37
- localProtocol: "https" | "http";
38
- enableLocalPersistence: boolean;
39
- bindings: CfWorkerInit["bindings"];
40
- crons: Config["triggers"]["crons"];
41
- public: string | undefined;
42
- assetPaths: AssetPaths | undefined;
43
- compatibilityDate: string;
44
- compatibilityFlags: string[] | undefined;
45
- usageModel: "bundled" | "unbound" | undefined;
46
- minify: boolean | undefined;
47
- nodeCompat: boolean | undefined;
48
- build: Config["build"];
49
- env: string | undefined;
50
- legacyEnv: boolean;
51
- zone: string | undefined;
52
- host: string | undefined;
26
+ name: string | undefined;
27
+ noBundle: boolean;
28
+ entry: Entry;
29
+ port: number;
30
+ ip: string;
31
+ inspectorPort: number;
32
+ rules: Config["rules"];
33
+ accountId: string | undefined;
34
+ initialMode: "local" | "remote";
35
+ jsxFactory: string | undefined;
36
+ jsxFragment: string | undefined;
37
+ tsconfig: string | undefined;
38
+ upstreamProtocol: "https" | "http";
39
+ localProtocol: "https" | "http";
40
+ localUpstream: string | undefined;
41
+ enableLocalPersistence: boolean;
42
+ bindings: CfWorkerInit["bindings"];
43
+ define: Config["define"];
44
+ crons: Config["triggers"]["crons"];
45
+ isWorkersSite: boolean;
46
+ assetPaths: AssetPaths | undefined;
47
+ compatibilityDate: string;
48
+ compatibilityFlags: string[] | undefined;
49
+ usageModel: "bundled" | "unbound" | undefined;
50
+ minify: boolean | undefined;
51
+ nodeCompat: boolean | undefined;
52
+ build: Config["build"];
53
+ env: string | undefined;
54
+ legacyEnv: boolean;
55
+ zone: string | undefined;
56
+ host: string | undefined;
57
+ routes: Route[] | undefined;
58
+ inspect: boolean | undefined;
59
+ logLevel: "none" | "error" | "log" | "warn" | "debug" | undefined;
60
+ onReady: (() => void) | undefined;
61
+ showInteractiveDevSession: boolean | undefined;
53
62
  };
54
63
 
55
64
  export function DevImplementation(props: DevProps): JSX.Element {
56
- if (props.public && props.entry.format === "service-worker") {
57
- throw new Error(
58
- "You cannot use the service-worker format with a `public` directory."
59
- );
60
- }
65
+ if (
66
+ !props.isWorkersSite &&
67
+ props.assetPaths &&
68
+ props.entry.format === "service-worker"
69
+ ) {
70
+ throw new Error(
71
+ "You cannot use the service-worker format with an `assets` directory yet. For information on how to migrate to the module-worker format, see: https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/"
72
+ );
73
+ }
61
74
 
62
- if (props.bindings.wasm_modules && props.entry.format === "modules") {
63
- throw new Error(
64
- "You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code"
65
- );
66
- }
75
+ if (props.bindings.wasm_modules && props.entry.format === "modules") {
76
+ throw new Error(
77
+ "You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code"
78
+ );
79
+ }
67
80
 
68
- if (props.bindings.text_blobs && props.entry.format === "modules") {
69
- throw new Error(
70
- "You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure `[rules]` in your wrangler.toml"
71
- );
72
- }
81
+ if (props.bindings.text_blobs && props.entry.format === "modules") {
82
+ throw new Error(
83
+ "You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure `[rules]` in your wrangler.toml"
84
+ );
85
+ }
73
86
 
74
- if (props.bindings.data_blobs && props.entry.format === "modules") {
75
- throw new Error(
76
- "You cannot configure [data_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure `[rules]` in your wrangler.toml"
77
- );
78
- }
87
+ if (props.bindings.data_blobs && props.entry.format === "modules") {
88
+ throw new Error(
89
+ "You cannot configure [data_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure `[rules]` in your wrangler.toml"
90
+ );
91
+ }
79
92
 
80
- // only load the UI if we're running in a supported environment
81
- const { isRawModeSupported } = useStdin();
82
- return isRawModeSupported ? (
83
- <InteractiveDevSession {...props} />
84
- ) : (
85
- <DevSession {...props} local={props.initialMode === "local"} />
86
- );
93
+ // only load the UI if we're running in a supported environment
94
+ const { isRawModeSupported } = useStdin();
95
+
96
+ return props.showInteractiveDevSession ?? isRawModeSupported ? (
97
+ <InteractiveDevSession {...props} />
98
+ ) : (
99
+ <DevSession {...props} local={props.initialMode === "local"} />
100
+ );
87
101
  }
88
102
 
89
103
  function InteractiveDevSession(props: DevProps) {
90
- const toggles = useHotkeys(
91
- {
92
- local: props.initialMode === "local",
93
- tunnel: false,
94
- },
95
- props.port,
96
- props.ip,
97
- props.inspectorPort,
98
- props.localProtocol
99
- );
104
+ const toggles = useHotkeys(
105
+ {
106
+ local: props.initialMode === "local",
107
+ tunnel: false,
108
+ },
109
+ props.port,
110
+ props.ip,
111
+ props.inspectorPort,
112
+ props.localProtocol
113
+ );
100
114
 
101
- useTunnel(toggles.tunnel);
115
+ useTunnel(toggles.tunnel);
102
116
 
103
- return (
104
- <>
105
- <DevSession {...props} local={toggles.local} />
106
- <Box borderStyle="round" paddingLeft={1} paddingRight={1}>
107
- <Text bold={true}>[b]</Text>
108
- <Text> open a browser, </Text>
109
- <Text bold={true}>[d]</Text>
110
- <Text> open Devtools, </Text>
111
- <Text bold={true}>[l]</Text>
112
- <Text> {toggles.local ? "turn off" : "turn on"} local mode, </Text>
113
- <Text bold={true}>[c]</Text>
114
- <Text> clear console, </Text>
115
- <Text bold={true}>[x]</Text>
116
- <Text> to exit</Text>
117
- </Box>
118
- </>
119
- );
117
+ return (
118
+ <>
119
+ <DevSession {...props} local={toggles.local} />
120
+ <Box borderStyle="round" paddingLeft={1} paddingRight={1}>
121
+ <Text bold={true}>[b]</Text>
122
+ <Text> open a browser, </Text>
123
+ <Text bold={true}>[d]</Text>
124
+ <Text> open Devtools, </Text>
125
+ <Text bold={true}>[l]</Text>
126
+ <Text> {toggles.local ? "turn off" : "turn on"} local mode, </Text>
127
+ <Text bold={true}>[c]</Text>
128
+ <Text> clear console, </Text>
129
+ <Text bold={true}>[x]</Text>
130
+ <Text> to exit</Text>
131
+ </Box>
132
+ </>
133
+ );
120
134
  }
121
135
 
122
136
  type DevSessionProps = DevProps & {
123
- local: boolean;
137
+ local: boolean;
124
138
  };
125
139
 
126
140
  function DevSession(props: DevSessionProps) {
127
- useCustomBuild(props.entry, props.build);
141
+ useCustomBuild(props.entry, props.build);
128
142
 
129
- const directory = useTmpDir();
143
+ const directory = useTmpDir();
130
144
 
131
- const bundle = useEsbuild({
132
- entry: props.entry,
133
- destination: directory,
134
- staticRoot: props.public,
135
- jsxFactory: props.jsxFactory,
136
- rules: props.rules,
137
- jsxFragment: props.jsxFragment,
138
- // In dev for remote mode, we serve --experimental-assets from the local proxy before we send the request to the worker.
139
- serveAssetsFromWorker: !!props.public && !!props.local,
140
- tsconfig: props.tsconfig,
141
- minify: props.minify,
142
- nodeCompat: props.nodeCompat,
143
- });
145
+ const bundle = useEsbuild({
146
+ entry: props.entry,
147
+ destination: directory,
148
+ jsxFactory: props.jsxFactory,
149
+ rules: props.rules,
150
+ jsxFragment: props.jsxFragment,
151
+ serveAssetsFromWorker: Boolean(
152
+ props.assetPaths && !props.isWorkersSite && props.local
153
+ ),
154
+ tsconfig: props.tsconfig,
155
+ minify: props.minify,
156
+ nodeCompat: props.nodeCompat,
157
+ define: props.define,
158
+ noBundle: props.noBundle,
159
+ });
144
160
 
145
- return props.local ? (
146
- <Local
147
- name={props.name}
148
- bundle={bundle}
149
- format={props.entry.format}
150
- compatibilityDate={props.compatibilityDate}
151
- localProtocol={props.localProtocol}
152
- compatibilityFlags={props.compatibilityFlags}
153
- bindings={props.bindings}
154
- assetPaths={props.assetPaths}
155
- public={props.public}
156
- port={props.port}
157
- ip={props.ip}
158
- rules={props.rules}
159
- inspectorPort={props.inspectorPort}
160
- enableLocalPersistence={props.enableLocalPersistence}
161
- crons={props.crons}
162
- />
163
- ) : (
164
- <Remote
165
- name={props.name}
166
- bundle={bundle}
167
- format={props.entry.format}
168
- accountId={props.accountId}
169
- bindings={props.bindings}
170
- assetPaths={props.assetPaths}
171
- public={props.public}
172
- port={props.port}
173
- ip={props.ip}
174
- localProtocol={props.localProtocol}
175
- inspectorPort={props.inspectorPort}
176
- compatibilityDate={props.compatibilityDate}
177
- compatibilityFlags={props.compatibilityFlags}
178
- usageModel={props.usageModel}
179
- env={props.env}
180
- legacyEnv={props.legacyEnv}
181
- zone={props.zone}
182
- host={props.host}
183
- />
184
- );
161
+ return props.local ? (
162
+ <Local
163
+ name={props.name}
164
+ bundle={bundle}
165
+ format={props.entry.format}
166
+ compatibilityDate={props.compatibilityDate}
167
+ compatibilityFlags={props.compatibilityFlags}
168
+ bindings={props.bindings}
169
+ assetPaths={props.assetPaths}
170
+ isWorkersSite={props.isWorkersSite}
171
+ port={props.port}
172
+ ip={props.ip}
173
+ rules={props.rules}
174
+ inspectorPort={props.inspectorPort}
175
+ enableLocalPersistence={props.enableLocalPersistence}
176
+ crons={props.crons}
177
+ localProtocol={props.localProtocol}
178
+ localUpstream={props.localUpstream}
179
+ logLevel={props.logLevel}
180
+ inspect={props.inspect}
181
+ onReady={props.onReady}
182
+ />
183
+ ) : (
184
+ <Remote
185
+ name={props.name}
186
+ bundle={bundle}
187
+ format={props.entry.format}
188
+ accountId={props.accountId}
189
+ bindings={props.bindings}
190
+ assetPaths={props.assetPaths}
191
+ isWorkersSite={props.isWorkersSite}
192
+ port={props.port}
193
+ ip={props.ip}
194
+ localProtocol={props.localProtocol}
195
+ inspectorPort={props.inspectorPort}
196
+ compatibilityDate={props.compatibilityDate}
197
+ compatibilityFlags={props.compatibilityFlags}
198
+ usageModel={props.usageModel}
199
+ env={props.env}
200
+ legacyEnv={props.legacyEnv}
201
+ zone={props.zone}
202
+ host={props.host}
203
+ routes={props.routes}
204
+ onReady={props.onReady}
205
+ />
206
+ );
185
207
  }
186
208
 
187
209
  export interface DirectorySyncResult {
188
- name: string;
189
- removeCallback: () => void;
210
+ name: string;
211
+ removeCallback: () => void;
190
212
  }
191
213
 
192
214
  function useTmpDir(): string | undefined {
193
- const [directory, setDirectory] = useState<DirectorySyncResult>();
194
- const handleError = useErrorHandler();
195
- useEffect(() => {
196
- let dir: DirectorySyncResult | undefined;
197
- try {
198
- dir = tmp.dirSync({ unsafeCleanup: true });
199
- setDirectory(dir);
200
- return;
201
- } catch (err) {
202
- logger.error(
203
- "Failed to create temporary directory to store built files."
204
- );
205
- handleError(err);
206
- }
207
- return () => {
208
- dir?.removeCallback();
209
- };
210
- }, [handleError]);
211
- return directory?.name;
215
+ const [directory, setDirectory] = useState<DirectorySyncResult>();
216
+ const handleError = useErrorHandler();
217
+ useEffect(() => {
218
+ let dir: DirectorySyncResult | undefined;
219
+ try {
220
+ dir = tmp.dirSync({ unsafeCleanup: true });
221
+ setDirectory(dir);
222
+ return;
223
+ } catch (err) {
224
+ logger.error(
225
+ "Failed to create temporary directory to store built files."
226
+ );
227
+ handleError(err);
228
+ }
229
+ return () => {
230
+ dir?.removeCallback();
231
+ };
232
+ }, [handleError]);
233
+ return directory?.name;
212
234
  }
213
235
 
214
236
  function useCustomBuild(expectedEntry: Entry, build: Config["build"]): void {
215
- useEffect(() => {
216
- if (!build.command) return;
217
- let watcher: ReturnType<typeof watch> | undefined;
218
- if (build.watch_dir) {
219
- watcher = watch(build.watch_dir, {
220
- persistent: true,
221
- ignoreInitial: true,
222
- }).on("all", (_event, filePath) => {
223
- const relativeFile =
224
- path.relative(expectedEntry.directory, expectedEntry.file) || ".";
225
- //TODO: we should buffer requests to the proxy until this completes
226
- logger.log(`The file ${filePath} changed, restarting build...`);
227
- runCustomBuild(expectedEntry.file, relativeFile, build).catch((err) => {
228
- logger.error("Custom build failed:", err);
229
- });
230
- });
231
- }
237
+ useEffect(() => {
238
+ if (!build.command) return;
239
+ let watcher: ReturnType<typeof watch> | undefined;
240
+ if (build.watch_dir) {
241
+ watcher = watch(build.watch_dir, {
242
+ persistent: true,
243
+ ignoreInitial: true,
244
+ }).on("all", (_event, filePath) => {
245
+ const relativeFile =
246
+ path.relative(expectedEntry.directory, expectedEntry.file) || ".";
247
+ //TODO: we should buffer requests to the proxy until this completes
248
+ logger.log(`The file ${filePath} changed, restarting build...`);
249
+ runCustomBuild(expectedEntry.file, relativeFile, build).catch((err) => {
250
+ logger.error("Custom build failed:", err);
251
+ });
252
+ });
253
+ }
232
254
 
233
- return () => {
234
- watcher?.close();
235
- };
236
- }, [build, expectedEntry]);
255
+ return () => {
256
+ watcher?.close();
257
+ };
258
+ }, [build, expectedEntry]);
237
259
  }
238
260
 
239
261
  function sleep(period: number) {
240
- return new Promise((resolve) => setTimeout(resolve, period));
262
+ return new Promise((resolve) => setTimeout(resolve, period));
241
263
  }
242
264
  const SLEEP_DURATION = 2000;
243
265
  // really need a first class api for this
244
266
  const hostNameRegex = /userHostname="(.*)"/g;
245
267
  async function findTunnelHostname() {
246
- let hostName: string | undefined;
247
- while (!hostName) {
248
- try {
249
- const resp = await fetch("http://localhost:8789/metrics");
250
- const data = await resp.text();
251
- const matches = Array.from(data.matchAll(hostNameRegex));
252
- hostName = matches[0][1];
253
- } catch (err) {
254
- await sleep(SLEEP_DURATION);
255
- }
256
- }
257
- return hostName;
268
+ let hostName: string | undefined;
269
+ while (!hostName) {
270
+ try {
271
+ const resp = await fetch("http://localhost:8789/metrics");
272
+ const data = await resp.text();
273
+ const matches = Array.from(data.matchAll(hostNameRegex));
274
+ hostName = matches[0][1];
275
+ } catch (err) {
276
+ await sleep(SLEEP_DURATION);
277
+ }
278
+ }
279
+ return hostName;
258
280
  }
259
281
 
260
282
  /**
@@ -262,134 +284,134 @@ async function findTunnelHostname() {
262
284
  * We've disabled this for now until we figure out a better user experience.
263
285
  */
264
286
  function useTunnel(toggle: boolean) {
265
- const tunnel = useRef<ReturnType<typeof spawn>>();
266
- const removeSignalExitListener = useRef<() => void>();
267
- // TODO: test if cloudflared is available, if not
268
- // point them to a url where they can get docs to install it
269
- useEffect(() => {
270
- async function startTunnel() {
271
- if (toggle) {
272
- try {
273
- await commandExists("cloudflared");
274
- } catch (e) {
275
- logger.warn(
276
- "To share your worker on the Internet, please install `cloudflared` from https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation"
277
- );
278
- return;
279
- }
280
- logger.log("⎔ Starting a tunnel...");
281
- tunnel.current = spawn("cloudflared", [
282
- "tunnel",
283
- "--url",
284
- "http://localhost:8787",
285
- "--metrics",
286
- "localhost:8789",
287
- ]);
287
+ const tunnel = useRef<ReturnType<typeof spawn>>();
288
+ const removeSignalExitListener = useRef<() => void>();
289
+ // TODO: test if cloudflared is available, if not
290
+ // point them to a url where they can get docs to install it
291
+ useEffect(() => {
292
+ async function startTunnel() {
293
+ if (toggle) {
294
+ try {
295
+ await commandExists("cloudflared");
296
+ } catch (e) {
297
+ logger.warn(
298
+ "To share your worker on the Internet, please install `cloudflared` from https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation"
299
+ );
300
+ return;
301
+ }
302
+ logger.log("⎔ Starting a tunnel...");
303
+ tunnel.current = spawn("cloudflared", [
304
+ "tunnel",
305
+ "--url",
306
+ "http://localhost:8787",
307
+ "--metrics",
308
+ "localhost:8789",
309
+ ]);
288
310
 
289
- tunnel.current.on("close", (code) => {
290
- if (code) {
291
- logger.log(`Tunnel process exited with code ${code}`);
292
- }
293
- });
311
+ tunnel.current.on("close", (code) => {
312
+ if (code) {
313
+ logger.log(`Tunnel process exited with code ${code}`);
314
+ }
315
+ });
294
316
 
295
- removeSignalExitListener.current = onExit((_code, _signal) => {
296
- logger.log("⎔ Shutting down local tunnel.");
297
- tunnel.current?.kill();
298
- tunnel.current = undefined;
299
- });
317
+ removeSignalExitListener.current = onExit((_code, _signal) => {
318
+ logger.log("⎔ Shutting down local tunnel.");
319
+ tunnel.current?.kill();
320
+ tunnel.current = undefined;
321
+ });
300
322
 
301
- const hostName = await findTunnelHostname();
302
- await clipboardy.write(hostName);
303
- logger.log(`⬣ Sharing at ${hostName}, copied to clipboard.`);
304
- }
305
- }
323
+ const hostName = await findTunnelHostname();
324
+ await clipboardy.write(hostName);
325
+ logger.log(`⬣ Sharing at ${hostName}, copied to clipboard.`);
326
+ }
327
+ }
306
328
 
307
- startTunnel().catch(async (err) => {
308
- logger.error("tunnel:", err);
309
- });
329
+ startTunnel().catch(async (err) => {
330
+ logger.error("tunnel:", err);
331
+ });
310
332
 
311
- return () => {
312
- if (tunnel.current) {
313
- logger.log("⎔ Shutting down tunnel.");
314
- tunnel.current?.kill();
315
- tunnel.current = undefined;
316
- removeSignalExitListener.current && removeSignalExitListener.current();
317
- removeSignalExitListener.current = undefined;
318
- }
319
- };
320
- }, [toggle]);
333
+ return () => {
334
+ if (tunnel.current) {
335
+ logger.log("⎔ Shutting down tunnel.");
336
+ tunnel.current?.kill();
337
+ tunnel.current = undefined;
338
+ removeSignalExitListener.current && removeSignalExitListener.current();
339
+ removeSignalExitListener.current = undefined;
340
+ }
341
+ };
342
+ }, [toggle]);
321
343
  }
322
344
 
323
345
  type useHotkeysInitialState = {
324
- local: boolean;
325
- tunnel: boolean;
346
+ local: boolean;
347
+ tunnel: boolean;
326
348
  };
327
349
  function useHotkeys(
328
- initial: useHotkeysInitialState,
329
- port: number,
330
- ip: string,
331
- inspectorPort: number,
332
- localProtocol: "http" | "https"
350
+ initial: useHotkeysInitialState,
351
+ port: number,
352
+ ip: string,
353
+ inspectorPort: number,
354
+ localProtocol: "http" | "https"
333
355
  ) {
334
- // UGH, we should put port in context instead
335
- const [toggles, setToggles] = useState(initial);
336
- const { exit } = useApp();
337
- useInput(
338
- async (
339
- input,
340
- // eslint-disable-next-line unused-imports/no-unused-vars
341
- key
342
- ) => {
343
- switch (input.toLowerCase()) {
344
- // clear console
345
- case "c":
346
- console.clear();
347
- // This console.log causes Ink to re-render the `DevSession` component.
348
- // Couldn't find a better way to tell it to do so...
349
- console.log();
350
- break;
351
- // open browser
352
- case "b": {
353
- await openInBrowser(`${localProtocol}://${ip}:${port}`);
354
- break;
355
- }
356
- // toggle inspector
357
- case "d": {
358
- await openInspector(inspectorPort);
359
- break;
360
- }
361
- // toggle local
362
- case "l":
363
- setToggles((previousToggles) => ({
364
- ...previousToggles,
365
- local: !previousToggles.local,
366
- }));
367
- break;
368
- // shut down
369
- case "q":
370
- case "x":
371
- exit();
372
- break;
373
- default:
374
- // nothing?
375
- break;
376
- }
377
- }
378
- );
379
- return toggles;
356
+ // UGH, we should put port in context instead
357
+ const [toggles, setToggles] = useState(initial);
358
+ const { exit } = useApp();
359
+ useInput(
360
+ async (
361
+ input,
362
+ // eslint-disable-next-line unused-imports/no-unused-vars
363
+ key
364
+ ) => {
365
+ switch (input.toLowerCase()) {
366
+ // clear console
367
+ case "c":
368
+ console.clear();
369
+ // This console.log causes Ink to re-render the `DevSession` component.
370
+ // Couldn't find a better way to tell it to do so...
371
+ console.log();
372
+ break;
373
+ // open browser
374
+ case "b": {
375
+ await openInBrowser(`${localProtocol}://${ip}:${port}`);
376
+ break;
377
+ }
378
+ // toggle inspector
379
+ case "d": {
380
+ await openInspector(inspectorPort);
381
+ break;
382
+ }
383
+ // toggle local
384
+ case "l":
385
+ setToggles((previousToggles) => ({
386
+ ...previousToggles,
387
+ local: !previousToggles.local,
388
+ }));
389
+ break;
390
+ // shut down
391
+ case "q":
392
+ case "x":
393
+ exit();
394
+ break;
395
+ default:
396
+ // nothing?
397
+ break;
398
+ }
399
+ }
400
+ );
401
+ return toggles;
380
402
  }
381
403
 
382
404
  function ErrorFallback(props: { error: Error }) {
383
- const { exit } = useApp();
384
- useEffect(() => exit(props.error));
385
- return (
386
- <>
387
- <Text>Something went wrong:</Text>
388
- <Text>{props.error.stack}</Text>
389
- </>
390
- );
405
+ const { exit } = useApp();
406
+ useEffect(() => exit(props.error));
407
+ return (
408
+ <>
409
+ <Text>Something went wrong:</Text>
410
+ <Text>{props.error.stack}</Text>
411
+ </>
412
+ );
391
413
  }
392
414
 
393
415
  export default withErrorBoundary(DevImplementation, {
394
- FallbackComponent: ErrorFallback,
416
+ FallbackComponent: ErrorFallback,
395
417
  });