wrangler 0.0.0-e1c615f → 0.0.0-e6733a3

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/src/dev.tsx CHANGED
@@ -8,7 +8,7 @@ import { Box, Text, useApp, useInput } from "ink";
8
8
  import React, { useState, useEffect, useRef } from "react";
9
9
  import path from "path";
10
10
  import open from "open";
11
- import { DtInspector } from "./api/inspect";
11
+ import useInspector from "./inspect";
12
12
  import type { CfModule } from "./api/worker";
13
13
  import { createWorker } from "./api/worker";
14
14
  import type { CfWorkerInit } from "./api/worker";
@@ -16,34 +16,33 @@ import { spawn } from "child_process";
16
16
  import onExit from "signal-exit";
17
17
  import { syncAssets } from "./sites";
18
18
  import clipboardy from "clipboardy";
19
- import http from "node:http";
20
19
  import commandExists from "command-exists";
21
20
  import assert from "assert";
22
21
  import { getAPIToken } from "./user";
23
22
  import fetch from "node-fetch";
24
23
  import makeModuleCollector from "./module-collection";
25
24
  import { withErrorBoundary, useErrorHandler } from "react-error-boundary";
26
- import { createHttpProxy } from "./proxy";
25
+ import { usePreviewServer } from "./proxy";
27
26
  import { execa } from "execa";
28
27
  import { watch } from "chokidar";
29
28
 
30
- type CfScriptFormat = void | "modules" | "service-worker";
29
+ type CfScriptFormat = undefined | "modules" | "service-worker";
31
30
 
32
31
  export type DevProps = {
33
32
  name?: string;
34
33
  entry: string;
35
34
  port?: number;
36
35
  format: CfScriptFormat;
37
- accountId: void | string;
36
+ accountId: undefined | string;
38
37
  initialMode: "local" | "remote";
39
- jsxFactory: void | string;
40
- jsxFragment: void | string;
38
+ jsxFactory: undefined | string;
39
+ jsxFragment: undefined | string;
41
40
  bindings: CfWorkerInit["bindings"];
42
- public: void | string;
43
- site: void | string;
44
- compatibilityDate: void | string;
45
- compatibilityFlags: void | string[];
46
- usageModel: void | "bundled" | "unbound";
41
+ public: undefined | string;
42
+ site: undefined | string;
43
+ compatibilityDate: undefined | string;
44
+ compatibilityFlags: undefined | string[];
45
+ usageModel: undefined | "bundled" | "unbound";
47
46
  buildCommand: {
48
47
  command?: undefined | string;
49
48
  cwd?: undefined | string;
@@ -79,9 +78,6 @@ function Dev(props: DevProps): JSX.Element {
79
78
  );
80
79
  }
81
80
 
82
- // @ts-expect-error whack
83
- useDevtoolsRefresh(bundle?.id ?? 0);
84
-
85
81
  const toggles = useHotkeys(
86
82
  {
87
83
  local: props.initialMode === "local",
@@ -133,53 +129,23 @@ function Dev(props: DevProps): JSX.Element {
133
129
  );
134
130
  }
135
131
 
136
- function useDevtoolsRefresh(bundleId: number) {
137
- // TODO: this is a hack while we figure out
138
- // a better cleaner solution to get devtools to reconnect
139
- // without having to do a full refresh
140
- const ref = useRef();
141
- // @ts-expect-error whack
142
- ref.current = bundleId;
143
-
144
- useEffect(() => {
145
- const server = http.createServer((req, res) => {
146
- res.setHeader("Access-Control-Allow-Origin", "*");
147
- res.setHeader("Access-Control-Request-Method", "*");
148
- res.setHeader("Access-Control-Allow-Methods", "OPTIONS, GET");
149
- res.setHeader("Access-Control-Allow-Headers", "*");
150
- if (req.method === "OPTIONS") {
151
- res.writeHead(200);
152
- res.end();
153
- return;
154
- }
155
- res.writeHead(200, { "Content-Type": "application/json" });
156
- res.end(JSON.stringify({ value: ref.current }));
157
- });
158
-
159
- server.listen(3142);
160
- return () => {
161
- server.close();
162
- };
163
- }, []);
164
- }
165
-
166
132
  function Remote(props: {
167
- name: void | string;
168
- bundle: EsbuildBundle | void;
133
+ name: undefined | string;
134
+ bundle: EsbuildBundle | undefined;
169
135
  format: CfScriptFormat;
170
- public: void | string;
171
- site: void | string;
136
+ public: undefined | string;
137
+ site: undefined | string;
172
138
  port: number;
173
- accountId: void | string;
174
- apiToken: void | string;
139
+ accountId: undefined | string;
140
+ apiToken: undefined | string;
175
141
  bindings: CfWorkerInit["bindings"];
176
- compatibilityDate: string | void;
177
- compatibilityFlags: void | string[];
178
- usageModel: void | "bundled" | "unbound";
142
+ compatibilityDate: string | undefined;
143
+ compatibilityFlags: undefined | string[];
144
+ usageModel: undefined | "bundled" | "unbound";
179
145
  }) {
180
146
  assert(props.accountId, "accountId is required");
181
147
  assert(props.apiToken, "apiToken is required");
182
- const token = useWorker({
148
+ const previewToken = useWorker({
183
149
  name: props.name,
184
150
  bundle: props.bundle,
185
151
  format: props.format,
@@ -194,18 +160,26 @@ function Remote(props: {
194
160
  usageModel: props.usageModel,
195
161
  });
196
162
 
197
- useProxy({ token, publicRoot: props.public, port: props.port });
163
+ usePreviewServer({
164
+ previewToken,
165
+ publicRoot: props.public,
166
+ port: props.port,
167
+ });
198
168
 
199
- useInspector(token ? token.inspectorUrl.href : undefined);
169
+ useInspector({
170
+ inspectorUrl: previewToken ? previewToken.inspectorUrl.href : undefined,
171
+ port: 9229,
172
+ logToTerminal: true,
173
+ });
200
174
  return null;
201
175
  }
202
176
  function Local(props: {
203
- name: void | string;
204
- bundle: EsbuildBundle | void;
177
+ name: undefined | string;
178
+ bundle: EsbuildBundle | undefined;
205
179
  format: CfScriptFormat;
206
180
  bindings: CfWorkerInit["bindings"];
207
- public: void | string;
208
- site: void | string;
181
+ public: undefined | string;
182
+ site: undefined | string;
209
183
  port: number;
210
184
  }) {
211
185
  const { inspectorUrl } = useLocalWorker({
@@ -215,13 +189,13 @@ function Local(props: {
215
189
  bindings: props.bindings,
216
190
  port: props.port,
217
191
  });
218
- useInspector(inspectorUrl);
192
+ useInspector({ inspectorUrl, port: 9229, logToTerminal: false });
219
193
  return null;
220
194
  }
221
195
 
222
196
  function useLocalWorker(props: {
223
- name: void | string;
224
- bundle: EsbuildBundle | void;
197
+ name: undefined | string;
198
+ bundle: EsbuildBundle | undefined;
225
199
  format: CfScriptFormat;
226
200
  bindings: CfWorkerInit["bindings"];
227
201
  port: number;
@@ -230,7 +204,7 @@ function useLocalWorker(props: {
230
204
  const { bundle, format, bindings, port } = props;
231
205
  const local = useRef<ReturnType<typeof spawn>>();
232
206
  const removeSignalExitListener = useRef<() => void>();
233
- const [inspectorUrl, setInspectorUrl] = useState<string | void>();
207
+ const [inspectorUrl, setInspectorUrl] = useState<string | undefined>();
234
208
  useEffect(() => {
235
209
  async function startLocalWorker() {
236
210
  if (!bundle) return;
@@ -346,7 +320,7 @@ function useLocalWorker(props: {
346
320
  return { inspectorUrl };
347
321
  }
348
322
 
349
- function useTmpDir(): string | void {
323
+ function useTmpDir(): string | undefined {
350
324
  const [directory, setDirectory] = useState<DirectoryResult>();
351
325
  const handleError = useErrorHandler();
352
326
  useEffect(() => {
@@ -384,8 +358,8 @@ function useCustomBuild(
384
358
  cwd?: undefined | string;
385
359
  watch_dir?: undefined | string;
386
360
  }
387
- ): void | string {
388
- const [entry, setEntry] = useState<string | void>(
361
+ ): undefined | string {
362
+ const [entry, setEntry] = useState<string | undefined>(
389
363
  // if there's no build command, just return the expected entry
390
364
  props.command ? null : expectedEntry
391
365
  );
@@ -456,12 +430,12 @@ type EsbuildBundle = {
456
430
  };
457
431
 
458
432
  function useEsbuild(props: {
459
- entry: void | string;
460
- destination: string | void;
461
- staticRoot: void | string;
462
- jsxFactory: string | void;
463
- jsxFragment: string | void;
464
- }): EsbuildBundle | void {
433
+ entry: undefined | string;
434
+ destination: string | undefined;
435
+ staticRoot: undefined | string;
436
+ jsxFactory: string | undefined;
437
+ jsxFragment: string | undefined;
438
+ }): EsbuildBundle | undefined {
465
439
  const { entry, destination, staticRoot, jsxFactory, jsxFragment } = props;
466
440
  const [bundle, setBundle] = useState<EsbuildBundle>();
467
441
  useEffect(() => {
@@ -501,7 +475,8 @@ function useEsbuild(props: {
501
475
  });
502
476
 
503
477
  const chunks = Object.entries(result.metafile.outputs).find(
504
- ([_path, { entryPoint }]) => entryPoint === entry
478
+ ([_path, { entryPoint }]) =>
479
+ entryPoint === Object.keys(result.metafile.inputs)[0]
505
480
  ); // assumedly only one entry point
506
481
 
507
482
  setBundle({
@@ -527,19 +502,19 @@ function useEsbuild(props: {
527
502
  }
528
503
 
529
504
  function useWorker(props: {
530
- name: void | string;
531
- bundle: EsbuildBundle | void;
505
+ name: undefined | string;
506
+ bundle: EsbuildBundle | undefined;
532
507
  format: CfScriptFormat;
533
508
  modules: CfModule[];
534
509
  accountId: string;
535
510
  apiToken: string;
536
511
  bindings: CfWorkerInit["bindings"];
537
- sitesFolder: void | string;
512
+ sitesFolder: undefined | string;
538
513
  port: number;
539
- compatibilityDate: string | void;
540
- compatibilityFlags: string[] | void;
541
- usageModel: void | "bundled" | "unbound";
542
- }): CfPreviewToken | void {
514
+ compatibilityDate: string | undefined;
515
+ compatibilityFlags: string[] | undefined;
516
+ usageModel: undefined | "bundled" | "unbound";
517
+ }): CfPreviewToken | undefined {
543
518
  const {
544
519
  name,
545
520
  bundle,
@@ -554,7 +529,7 @@ function useWorker(props: {
554
529
  usageModel,
555
530
  port,
556
531
  } = props;
557
- const [token, setToken] = useState<CfPreviewToken>();
532
+ const [token, setToken] = useState<CfPreviewToken | undefined>();
558
533
 
559
534
  // This is the most reliable way to detect whether
560
535
  // something's "happened" in our system; We make a ref and
@@ -563,6 +538,8 @@ function useWorker(props: {
563
538
 
564
539
  useEffect(() => {
565
540
  async function start() {
541
+ setToken(undefined); // reset token in case we're re-running
542
+
566
543
  if (!bundle) return;
567
544
  if (format === "modules" && bundle.type === "commonjs") {
568
545
  console.error("⎔ Cannot use modules with a commonjs bundle.");
@@ -576,7 +553,6 @@ function useWorker(props: {
576
553
  }
577
554
 
578
555
  if (!startedRef.current) {
579
- console.log("⎔ Starting server...");
580
556
  startedRef.current = true;
581
557
  } else {
582
558
  console.log("⎔ Detected changes, restarting server...");
@@ -654,85 +630,6 @@ function useWorker(props: {
654
630
  return token;
655
631
  }
656
632
 
657
- function useProxy({
658
- token,
659
- publicRoot,
660
- port,
661
- }: {
662
- token: CfPreviewToken | void;
663
- publicRoot: void | string;
664
- port: number;
665
- }) {
666
- useEffect(() => {
667
- if (!token) return;
668
- // TODO(soon): since headers are added in callbacks, the server
669
- // does not need to restart when changes are made.
670
- const host = token.host;
671
- const proxy = createHttpProxy({
672
- host,
673
- assetPath: typeof publicRoot === "string" ? publicRoot : null,
674
- onRequest: (headers) => {
675
- headers["cf-workers-preview-token"] = token.value;
676
- },
677
- onResponse: (headers) => {
678
- for (const [name, value] of Object.entries(headers)) {
679
- // Rewrite the remote host to the local host.
680
- if (typeof value === "string" && value.includes(host)) {
681
- headers[name] = value
682
- .replaceAll(`https://${host}`, `http://localhost:${port}`)
683
- .replaceAll(host, `localhost:${port}`);
684
- }
685
- }
686
- },
687
- });
688
-
689
- console.log(`⬣ Listening at http://localhost:${port}`);
690
-
691
- const server = proxy.listen(port);
692
-
693
- // TODO(soon): refactor logging format into its own function
694
- proxy.on("request", function (req, res) {
695
- // log all requests
696
- console.log(
697
- new Date().toLocaleTimeString(),
698
- req.method,
699
- req.url,
700
- res.statusCode
701
- );
702
- });
703
- proxy.on("upgrade", (req) => {
704
- console.log(
705
- new Date().toLocaleTimeString(),
706
- req.method,
707
- req.url,
708
- 101,
709
- "(WebSocket)"
710
- );
711
- });
712
- proxy.on("error", (err) => {
713
- console.error(new Date().toLocaleTimeString(), err);
714
- });
715
-
716
- return () => {
717
- proxy.close();
718
- server.close();
719
- };
720
- }, [token, publicRoot, port]);
721
- }
722
-
723
- function useInspector(inspectorUrl: string | void) {
724
- useEffect(() => {
725
- if (!inspectorUrl) return;
726
-
727
- const inspector = new DtInspector(inspectorUrl);
728
- const abortController = inspector.proxyTo(9229);
729
- return () => {
730
- inspector.close();
731
- abortController.abort();
732
- };
733
- }, [inspectorUrl]);
734
- }
735
-
736
633
  function sleep(period: number) {
737
634
  return new Promise((resolve) => setTimeout(resolve, period));
738
635
  }
@@ -740,7 +637,7 @@ const SLEEP_DURATION = 2000;
740
637
  // really need a first class api for this
741
638
  const hostNameRegex = /userHostname="(.*)"/g;
742
639
  async function findTunnelHostname() {
743
- let hostName: string;
640
+ let hostName: string | undefined;
744
641
  while (!hostName) {
745
642
  try {
746
643
  const resp = await fetch("http://localhost:8789/metrics");
package/src/index.tsx CHANGED
@@ -435,6 +435,20 @@ export async function main(argv: string[]): Promise<void> {
435
435
  type: "string",
436
436
  // TODO: get choices for the toml file?
437
437
  })
438
+ .option("compatibility-date", {
439
+ describe: "Date to use for compatibility checks",
440
+ type: "string",
441
+ })
442
+ .option("compatibility-flags", {
443
+ describe: "Flags to use for compatibility checks",
444
+ type: "array",
445
+ alias: "compatibility-flag",
446
+ })
447
+ .option("latest", {
448
+ describe: "Use the latest version of the worker runtime",
449
+ type: "boolean",
450
+ default: true,
451
+ })
438
452
  .option("ip", {
439
453
  describe: "IP address to listen on",
440
454
  type: "string",
@@ -520,7 +534,7 @@ export async function main(argv: string[]): Promise<void> {
520
534
  if ("durable_objects" in envRootObj) {
521
535
  if (!(args.name || config.name)) {
522
536
  console.warn(
523
- 'A worker with durable objects need to be named, or it may not work as expected. Add a "name" into wrangler.toml, or pass it in the command line with --name.'
537
+ 'A worker with durable objects needs to be named, or it may not work as expected. Add a "name" into wrangler.toml, or pass it in the command line with --name.'
524
538
  );
525
539
  }
526
540
  // TODO: if not already published, publish a draft worker
@@ -539,8 +553,15 @@ export async function main(argv: string[]): Promise<void> {
539
553
  site={args.site || config.site?.bucket}
540
554
  port={args.port || config.dev?.port}
541
555
  public={args["experimental-public"]}
542
- compatibilityDate={config.compatibility_date}
543
- compatibilityFlags={config.compatibility_flags}
556
+ compatibilityDate={
557
+ args["compatibility-date"] ||
558
+ config.compatibility_date ||
559
+ new Date().toISOString().substring(0, 10)
560
+ }
561
+ compatibilityFlags={
562
+ (args["compatibility-flags"] as string[]) ||
563
+ config.compatibility_flags
564
+ }
544
565
  usageModel={config.usage_model}
545
566
  bindings={{
546
567
  kv_namespaces: envRootObj.kv_namespaces?.map(
@@ -592,6 +613,20 @@ export async function main(argv: string[]): Promise<void> {
592
613
  describe: "name to use when uploading",
593
614
  type: "string",
594
615
  })
616
+ .option("compatibility-date", {
617
+ describe: "Date to use for compatibility checks",
618
+ type: "string",
619
+ })
620
+ .option("compatibility-flags", {
621
+ describe: "Flags to use for compatibility checks",
622
+ type: "array",
623
+ alias: "compatibility-flag",
624
+ })
625
+ .option("latest", {
626
+ describe: "Use the latest version of the worker runtime",
627
+ type: "boolean",
628
+ default: false,
629
+ })
595
630
  .option("experimental-public", {
596
631
  describe: "Static assets to be served",
597
632
  type: "string",
@@ -645,6 +680,12 @@ export async function main(argv: string[]): Promise<void> {
645
680
 
646
681
  const config = args.config as Config;
647
682
 
683
+ if (args.latest) {
684
+ console.warn(
685
+ "⚠️ Using the latest version of the Workers runtime. To silence this warning, please choose a specific version of the runtime with --compatibility-date, or add a compatibility_date to your wrangler.toml.\n"
686
+ );
687
+ }
688
+
648
689
  // -- snip, extract --
649
690
  if (!args.local) {
650
691
  const loggedIn = await loginOrRefreshIfRequired();
@@ -668,6 +709,10 @@ export async function main(argv: string[]): Promise<void> {
668
709
  name: args.name,
669
710
  script: args.script,
670
711
  env: args.env,
712
+ compatibilityDate: args.latest
713
+ ? new Date().toISOString().substring(0, 10)
714
+ : args["compatibility-date"],
715
+ compatibilityFlags: args["compatibility-flags"] as string[],
671
716
  triggers: args.triggers,
672
717
  jsxFactory: args["jsx-factory"],
673
718
  jsxFragment: args["jsx-fragment"],