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.
- package/README.md +7 -1
- package/bin/wrangler.js +111 -57
- package/miniflare-dist/index.mjs +9 -2
- package/package.json +156 -154
- package/src/__tests__/config-cache-without-cache-dir.test.ts +38 -0
- package/src/__tests__/config-cache.test.ts +30 -24
- package/src/__tests__/configuration.test.ts +3935 -3476
- package/src/__tests__/dev.test.tsx +1128 -979
- package/src/__tests__/guess-worker-format.test.ts +68 -68
- package/src/__tests__/helpers/cmd-shim.d.ts +6 -6
- package/src/__tests__/helpers/faye-websocket.d.ts +4 -4
- package/src/__tests__/helpers/mock-account-id.ts +24 -24
- package/src/__tests__/helpers/mock-bin.ts +20 -20
- package/src/__tests__/helpers/mock-cfetch.ts +92 -92
- package/src/__tests__/helpers/mock-console.ts +49 -39
- package/src/__tests__/helpers/mock-dialogs.ts +94 -71
- package/src/__tests__/helpers/mock-http-server.ts +30 -30
- package/src/__tests__/helpers/mock-istty.ts +65 -18
- package/src/__tests__/helpers/mock-kv.ts +26 -26
- package/src/__tests__/helpers/mock-oauth-flow.ts +223 -228
- package/src/__tests__/helpers/mock-process.ts +39 -0
- package/src/__tests__/helpers/mock-stdin.ts +82 -77
- package/src/__tests__/helpers/mock-web-socket.ts +21 -21
- package/src/__tests__/helpers/run-in-tmp.ts +27 -27
- package/src/__tests__/helpers/run-wrangler.ts +8 -8
- package/src/__tests__/helpers/write-worker-source.ts +16 -16
- package/src/__tests__/helpers/write-wrangler-toml.ts +9 -9
- package/src/__tests__/https-options.test.ts +104 -104
- package/src/__tests__/index.test.ts +239 -234
- package/src/__tests__/init.test.ts +1605 -1250
- package/src/__tests__/jest.setup.ts +63 -33
- package/src/__tests__/kv.test.ts +1128 -1011
- package/src/__tests__/logger.test.ts +100 -74
- package/src/__tests__/package-manager.test.ts +303 -303
- package/src/__tests__/pages.test.ts +1152 -652
- package/src/__tests__/parse.test.ts +252 -252
- package/src/__tests__/publish.test.ts +6371 -5622
- package/src/__tests__/pubsub.test.ts +367 -0
- package/src/__tests__/r2.test.ts +133 -133
- package/src/__tests__/route.test.ts +18 -18
- package/src/__tests__/secret.test.ts +382 -377
- package/src/__tests__/tail.test.ts +530 -530
- package/src/__tests__/user.test.ts +123 -111
- package/src/__tests__/whoami.test.tsx +198 -117
- package/src/__tests__/worker-namespace.test.ts +327 -0
- package/src/abort.d.ts +1 -1
- package/src/api/dev.ts +49 -0
- package/src/api/index.ts +1 -0
- package/src/bundle-reporter.tsx +29 -0
- package/src/bundle.ts +157 -149
- package/src/cfetch/index.ts +80 -80
- package/src/cfetch/internal.ts +90 -83
- package/src/cli.ts +21 -7
- package/src/config/config.ts +204 -195
- package/src/config/diagnostics.ts +61 -61
- package/src/config/environment.ts +390 -357
- package/src/config/index.ts +206 -193
- package/src/config/validation-helpers.ts +366 -366
- package/src/config/validation.ts +1573 -1376
- package/src/config-cache.ts +79 -41
- package/src/create-worker-preview.ts +206 -136
- package/src/create-worker-upload-form.ts +247 -238
- package/src/dev/dev-vars.ts +13 -13
- package/src/dev/dev.tsx +329 -307
- package/src/dev/local.tsx +304 -275
- package/src/dev/remote.tsx +366 -224
- package/src/dev/use-esbuild.ts +126 -91
- package/src/dev.tsx +538 -0
- package/src/dialogs.tsx +97 -97
- package/src/durable.ts +87 -87
- package/src/entry.ts +234 -228
- package/src/environment-variables.ts +23 -23
- package/src/errors.ts +6 -6
- package/src/generate.ts +33 -0
- package/src/git-client.ts +42 -0
- package/src/https-options.ts +79 -79
- package/src/index.tsx +1775 -2763
- package/src/init.ts +549 -0
- package/src/inspect.ts +593 -593
- package/src/intl-polyfill.d.ts +123 -123
- package/src/is-interactive.ts +12 -0
- package/src/kv.ts +277 -277
- package/src/logger.ts +46 -39
- package/src/miniflare-cli/enum-keys.ts +8 -8
- package/src/miniflare-cli/index.ts +42 -31
- package/src/miniflare-cli/request-context.ts +18 -18
- package/src/module-collection.ts +212 -212
- package/src/open-in-browser.ts +4 -6
- package/src/package-manager.ts +123 -123
- package/src/pages/build.tsx +202 -0
- package/src/pages/constants.ts +7 -0
- package/src/pages/deployments.tsx +101 -0
- package/src/pages/dev.tsx +964 -0
- package/src/pages/functions/buildPlugin.ts +105 -0
- package/src/pages/functions/buildWorker.ts +151 -0
- package/{pages → src/pages}/functions/filepath-routing.test.ts +113 -113
- package/src/pages/functions/filepath-routing.ts +189 -0
- package/src/pages/functions/identifiers.ts +78 -0
- package/src/pages/functions/routes.ts +151 -0
- package/src/pages/index.tsx +84 -0
- package/src/pages/projects.tsx +157 -0
- package/src/pages/publish.tsx +335 -0
- package/src/pages/types.ts +40 -0
- package/src/pages/upload.tsx +384 -0
- package/src/pages/utils.ts +12 -0
- package/src/parse.ts +202 -138
- package/src/paths.ts +6 -6
- package/src/preview.ts +31 -0
- package/src/proxy.ts +400 -402
- package/src/publish.ts +667 -621
- package/src/pubsub/index.ts +286 -0
- package/src/pubsub/pubsub-commands.tsx +577 -0
- package/src/r2.ts +19 -19
- package/src/selfsigned.d.ts +23 -23
- package/src/sites.tsx +271 -225
- package/src/tail/filters.ts +108 -108
- package/src/tail/index.ts +217 -217
- package/src/tail/printing.ts +45 -45
- package/src/update-check.ts +11 -11
- package/src/user/choose-account.tsx +60 -0
- package/src/user/env-vars.ts +46 -0
- package/src/user/generate-auth-url.ts +33 -0
- package/src/user/generate-random-state.ts +16 -0
- package/src/user/index.ts +3 -0
- package/src/user/user.tsx +1161 -0
- package/src/whoami.tsx +61 -42
- package/src/worker-namespace.ts +190 -0
- package/src/worker.ts +110 -100
- package/src/zones.ts +39 -36
- package/templates/checked-fetch.js +17 -0
- package/templates/new-worker-scheduled.js +3 -3
- package/templates/new-worker-scheduled.ts +15 -15
- package/templates/new-worker.js +3 -3
- package/templates/new-worker.ts +15 -15
- package/templates/no-op-worker.js +10 -0
- package/templates/pages-template-plugin.ts +155 -0
- package/templates/pages-template-worker.ts +161 -0
- package/templates/static-asset-facade.js +31 -31
- package/templates/tsconfig.json +95 -95
- package/wrangler-dist/cli.js +55383 -54138
- package/pages/functions/buildPlugin.ts +0 -105
- package/pages/functions/buildWorker.ts +0 -151
- package/pages/functions/filepath-routing.ts +0 -189
- package/pages/functions/identifiers.ts +0 -78
- package/pages/functions/routes.ts +0 -156
- package/pages/functions/template-plugin.ts +0 -147
- package/pages/functions/template-worker.ts +0 -143
- package/src/pages.tsx +0 -2093
- 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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
115
|
+
useTunnel(toggles.tunnel);
|
|
102
116
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
137
|
+
local: boolean;
|
|
124
138
|
};
|
|
125
139
|
|
|
126
140
|
function DevSession(props: DevSessionProps) {
|
|
127
|
-
|
|
141
|
+
useCustomBuild(props.entry, props.build);
|
|
128
142
|
|
|
129
|
-
|
|
143
|
+
const directory = useTmpDir();
|
|
130
144
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
189
|
-
|
|
210
|
+
name: string;
|
|
211
|
+
removeCallback: () => void;
|
|
190
212
|
}
|
|
191
213
|
|
|
192
214
|
function useTmpDir(): string | undefined {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
255
|
+
return () => {
|
|
256
|
+
watcher?.close();
|
|
257
|
+
};
|
|
258
|
+
}, [build, expectedEntry]);
|
|
237
259
|
}
|
|
238
260
|
|
|
239
261
|
function sleep(period: number) {
|
|
240
|
-
|
|
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
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
-
|
|
308
|
-
|
|
309
|
-
|
|
329
|
+
startTunnel().catch(async (err) => {
|
|
330
|
+
logger.error("tunnel:", err);
|
|
331
|
+
});
|
|
310
332
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
-
|
|
325
|
-
|
|
346
|
+
local: boolean;
|
|
347
|
+
tunnel: boolean;
|
|
326
348
|
};
|
|
327
349
|
function useHotkeys(
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
350
|
+
initial: useHotkeysInitialState,
|
|
351
|
+
port: number,
|
|
352
|
+
ip: string,
|
|
353
|
+
inspectorPort: number,
|
|
354
|
+
localProtocol: "http" | "https"
|
|
333
355
|
) {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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
|
-
|
|
416
|
+
FallbackComponent: ErrorFallback,
|
|
395
417
|
});
|