wrangler 2.0.24 → 2.0.27

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 (63) hide show
  1. package/miniflare-dist/index.mjs +142 -16
  2. package/package.json +3 -3
  3. package/src/__tests__/configuration.test.ts +7 -3
  4. package/src/__tests__/dev.test.tsx +26 -4
  5. package/src/__tests__/generate.test.ts +2 -4
  6. package/src/__tests__/helpers/mock-cfetch.ts +35 -2
  7. package/src/__tests__/init.test.ts +537 -359
  8. package/src/__tests__/jest.setup.ts +7 -0
  9. package/src/__tests__/metrics.test.ts +1 -1
  10. package/src/__tests__/pages.test.ts +14 -0
  11. package/src/__tests__/r2.test.ts +22 -3
  12. package/src/__tests__/tail.test.ts +112 -42
  13. package/src/__tests__/user.test.ts +11 -0
  14. package/src/api/dev.ts +7 -0
  15. package/src/bundle.ts +3 -2
  16. package/src/cfetch/internal.ts +56 -0
  17. package/src/config/config.ts +1 -1
  18. package/src/config/validation-helpers.ts +19 -6
  19. package/src/config/validation.ts +9 -3
  20. package/src/config-cache.ts +2 -1
  21. package/src/dev/dev.tsx +16 -2
  22. package/src/dev/local.tsx +69 -5
  23. package/src/dev/use-esbuild.ts +3 -0
  24. package/src/dev-registry.tsx +3 -0
  25. package/src/dev.tsx +28 -19
  26. package/src/generate.ts +1 -1
  27. package/src/index.tsx +51 -21
  28. package/src/init.ts +111 -38
  29. package/src/inspect.ts +1 -4
  30. package/src/{metrics/is-ci.ts → is-ci.ts} +0 -0
  31. package/src/metrics/metrics-config.ts +1 -1
  32. package/src/miniflare-cli/assets.ts +27 -16
  33. package/src/miniflare-cli/index.ts +124 -2
  34. package/src/pages/build.tsx +75 -41
  35. package/src/pages/constants.ts +4 -0
  36. package/src/pages/deployments.tsx +9 -9
  37. package/src/pages/dev.tsx +178 -64
  38. package/src/pages/errors.ts +22 -0
  39. package/src/pages/functions/buildPlugin.ts +4 -0
  40. package/src/pages/functions/buildWorker.ts +4 -0
  41. package/src/pages/functions/routes-consolidation.test.ts +250 -0
  42. package/src/pages/functions/routes-consolidation.ts +73 -0
  43. package/src/pages/functions/routes-transformation.test.ts +271 -0
  44. package/src/pages/functions/routes-transformation.ts +122 -0
  45. package/src/pages/functions.tsx +96 -0
  46. package/src/pages/index.tsx +65 -55
  47. package/src/pages/projects.tsx +9 -3
  48. package/src/pages/publish.tsx +75 -22
  49. package/src/pages/types.ts +9 -0
  50. package/src/pages/upload.tsx +6 -8
  51. package/src/proxy.ts +10 -0
  52. package/src/r2.ts +17 -4
  53. package/src/tail/filters.ts +3 -1
  54. package/src/tail/index.ts +15 -2
  55. package/src/tail/printing.ts +43 -3
  56. package/src/user/user.tsx +6 -4
  57. package/src/whoami.tsx +5 -5
  58. package/templates/pages-template-plugin.ts +16 -4
  59. package/templates/pages-template-worker.ts +16 -5
  60. package/templates/service-bindings-module-facade.js +10 -7
  61. package/templates/service-bindings-sw-facade.js +10 -7
  62. package/wrangler-dist/cli.d.ts +7 -0
  63. package/wrangler-dist/cli.js +1681 -1091
@@ -0,0 +1,122 @@
1
+ import { join as pathJoin } from "node:path";
2
+ import { toUrlPath } from "../../paths";
3
+ import { MAX_FUNCTIONS_ROUTES_RULES, ROUTES_SPEC_VERSION } from "../constants";
4
+ import { consolidateRoutes } from "./routes-consolidation";
5
+ import type { RouteConfig } from "./routes";
6
+
7
+ /** Interface for _routes.json */
8
+ interface RoutesJSONSpec {
9
+ version: typeof ROUTES_SPEC_VERSION;
10
+ include: string[];
11
+ exclude: string[];
12
+ }
13
+
14
+ type RoutesJSONRouteInput = Pick<RouteConfig, "routePath" | "middleware">[];
15
+
16
+ export function convertRoutesToGlobPatterns(
17
+ routes: RoutesJSONRouteInput
18
+ ): string[] {
19
+ const convertedRoutes = routes.map(({ routePath, middleware }) => {
20
+ const globbedRoutePath: string = routePath.replace(/:\w+\*?.*/, "*");
21
+
22
+ // Middleware mountings need to end in glob so that they can handle their
23
+ // own sub-path routes
24
+ if (
25
+ typeof middleware === "string" ||
26
+ (Array.isArray(middleware) && middleware.length > 0)
27
+ ) {
28
+ if (!globbedRoutePath.endsWith("*")) {
29
+ return toUrlPath(pathJoin(globbedRoutePath, "*"));
30
+ }
31
+ }
32
+
33
+ return toUrlPath(globbedRoutePath);
34
+ });
35
+
36
+ return Array.from(new Set(convertedRoutes));
37
+ }
38
+
39
+ /**
40
+ * Converts Functions routes like /foo/:bar to a Routing object that's used
41
+ * to determine if a request should run in the Functions user-worker.
42
+ * Also consolidates redundant routes such as [/foo/bar, /foo/:bar] -> /foo/*
43
+ *
44
+ * @returns RoutesJSONSpec to be written to _routes.json
45
+ */
46
+ export function convertRoutesToRoutesJSONSpec(
47
+ routes: RoutesJSONRouteInput
48
+ ): RoutesJSONSpec {
49
+ // The initial routes coming in are sorted most-specific to least-specific.
50
+ // The order doesn't have any affect on the output of this function, but
51
+ // it should speed up route consolidation with less-specific routes being first.
52
+ const reversedRoutes = [...routes].reverse();
53
+ const include = convertRoutesToGlobPatterns(reversedRoutes);
54
+ return optimizeRoutesJSONSpec({
55
+ version: ROUTES_SPEC_VERSION,
56
+ include,
57
+ exclude: [],
58
+ });
59
+ }
60
+
61
+ /**
62
+ * Optimizes and returns a new Routes JSON Spec instance performing
63
+ * de-duping, consolidation, truncation, and sorting
64
+ */
65
+ export function optimizeRoutesJSONSpec(spec: RoutesJSONSpec): RoutesJSONSpec {
66
+ const optimizedSpec = { ...spec };
67
+
68
+ let consolidatedRoutes = consolidateRoutes(optimizedSpec.include);
69
+ if (consolidatedRoutes.length > MAX_FUNCTIONS_ROUTES_RULES) {
70
+ consolidatedRoutes = ["/*"];
71
+ }
72
+ // Sort so that least-specific routes are first
73
+ consolidatedRoutes.sort((a, b) => compareRoutes(b, a));
74
+
75
+ optimizedSpec.include = consolidatedRoutes;
76
+
77
+ return optimizedSpec;
78
+ }
79
+
80
+ /**
81
+ * Simplified routes comparison (copied from the one in filepath-routing.)
82
+ * This version will sort most-specific to least-specific, but the input is simplified
83
+ * routes like /foo/*, /foo, etc
84
+ */
85
+ export function compareRoutes(routeA: string, routeB: string) {
86
+ function parseRoutePath(routePath: string): string[] {
87
+ return routePath.slice(1).split("/").filter(Boolean);
88
+ }
89
+
90
+ const segmentsA = parseRoutePath(routeA);
91
+ const segmentsB = parseRoutePath(routeB);
92
+
93
+ // sort routes with fewer segments after those with more segments
94
+ if (segmentsA.length !== segmentsB.length) {
95
+ return segmentsB.length - segmentsA.length;
96
+ }
97
+
98
+ for (let i = 0; i < segmentsA.length; i++) {
99
+ const isWildcardA = segmentsA[i].includes("*");
100
+ const isWildcardB = segmentsB[i].includes("*");
101
+
102
+ // sort wildcard segments after non-wildcard segments
103
+ if (isWildcardA && !isWildcardB) return 1;
104
+ if (!isWildcardA && isWildcardB) return -1;
105
+ }
106
+
107
+ // all else equal, just sort the paths lexicographically
108
+ return routeA.localeCompare(routeB);
109
+ }
110
+
111
+ export function isRoutesJSONSpec(data: unknown): data is RoutesJSONSpec {
112
+ return (
113
+ (typeof data === "object" &&
114
+ data &&
115
+ "version" in data &&
116
+ typeof (data as RoutesJSONSpec).version === "number" &&
117
+ (data as RoutesJSONSpec).version === ROUTES_SPEC_VERSION &&
118
+ Array.isArray((data as RoutesJSONSpec).include) &&
119
+ Array.isArray((data as RoutesJSONSpec).exclude)) ||
120
+ false
121
+ );
122
+ }
@@ -0,0 +1,96 @@
1
+ import { existsSync, lstatSync, readFileSync, writeFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { FatalError } from "../errors";
4
+ import { logger } from "../logger";
5
+ import { isInPagesCI, ROUTES_SPEC_VERSION } from "./constants";
6
+ import {
7
+ isRoutesJSONSpec,
8
+ optimizeRoutesJSONSpec,
9
+ } from "./functions/routes-transformation";
10
+ import { pagesBetaWarning } from "./utils";
11
+ import type { YargsOptionsToInterface } from "./types";
12
+ import type { Argv } from "yargs";
13
+
14
+ type OptimizeRoutesArgs = YargsOptionsToInterface<typeof OptimizeRoutesOptions>;
15
+
16
+ export function OptimizeRoutesOptions(yargs: Argv) {
17
+ return yargs
18
+ .options({
19
+ "routes-path": {
20
+ type: "string",
21
+ demandOption: true,
22
+ description: "The location of the _routes.json file",
23
+ },
24
+ })
25
+ .options({
26
+ "output-routes-path": {
27
+ type: "string",
28
+ demandOption: true,
29
+ description: "The location of the optimized output routes file",
30
+ },
31
+ });
32
+ }
33
+
34
+ export async function OptimizeRoutesHandler({
35
+ routesPath,
36
+ outputRoutesPath,
37
+ }: OptimizeRoutesArgs) {
38
+ if (!isInPagesCI) {
39
+ // Beta message for `wrangler pages <commands>` usage
40
+ logger.log(pagesBetaWarning);
41
+ }
42
+
43
+ let routesFileContents: string;
44
+ const routesOutputDirectory = path.dirname(outputRoutesPath);
45
+
46
+ if (!existsSync(routesPath)) {
47
+ throw new FatalError(
48
+ `Oops! File ${routesPath} does not exist. Please make sure --routes-path is a valid file path (for example "/public/_routes.json").`,
49
+ 1
50
+ );
51
+ }
52
+
53
+ if (
54
+ !existsSync(routesOutputDirectory) ||
55
+ !lstatSync(routesOutputDirectory).isDirectory()
56
+ ) {
57
+ throw new FatalError(
58
+ `Oops! Folder ${routesOutputDirectory} does not exist. Please make sure --output-routes-path is a valid file path (for example "/public/_routes.json").`,
59
+ 1
60
+ );
61
+ }
62
+
63
+ try {
64
+ routesFileContents = readFileSync(routesPath, "utf-8");
65
+ } catch (err) {
66
+ throw new FatalError(`Error while reading ${routesPath} file: ${err}`);
67
+ }
68
+
69
+ const routes = JSON.parse(routesFileContents);
70
+
71
+ if (!isRoutesJSONSpec(routes)) {
72
+ throw new FatalError(
73
+ `
74
+ Invalid _routes.json file found at: ${routesPath}. Please make sure the JSON object has the following format:
75
+ {
76
+ version: ${ROUTES_SPEC_VERSION};
77
+ include: string[];
78
+ exclude: string[];
79
+ }
80
+ `,
81
+ 1
82
+ );
83
+ }
84
+
85
+ const optimizedRoutes = optimizeRoutesJSONSpec(routes);
86
+ const optimizedRoutesContents = JSON.stringify(optimizedRoutes);
87
+
88
+ try {
89
+ writeFileSync(outputRoutesPath, optimizedRoutesContents);
90
+ } catch (err) {
91
+ throw new FatalError(
92
+ `Error writing to ${outputRoutesPath} file: ${err}`,
93
+ 1
94
+ );
95
+ }
96
+ }
@@ -3,6 +3,7 @@
3
3
  import * as Build from "./build";
4
4
  import * as Deployments from "./deployments";
5
5
  import * as Dev from "./dev";
6
+ import * as Functions from "./functions";
6
7
  import * as Projects from "./projects";
7
8
  import * as Publish from "./publish";
8
9
  import * as Upload from "./upload";
@@ -19,66 +20,75 @@ process.on("SIGTERM", () => {
19
20
  });
20
21
 
21
22
  export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
22
- return yargs
23
- .command(
24
- "dev [directory] [-- command..]",
25
- "🧑‍💻 Develop your full-stack Pages application locally",
26
- Dev.Options,
27
- Dev.Handler
28
- )
29
- .command("functions", false, (yargs) =>
30
- // we hide this command from help output because
31
- // it's not meant to be used directly right now
32
- {
33
- return yargs.command(
34
- "build [directory]",
35
- "Compile a folder of Cloudflare Pages Functions into a single Worker",
36
- Build.Options,
37
- Build.Handler
38
- );
39
- }
40
- )
41
- .command("project", "⚡️ Interact with your Pages projects", (yargs) =>
42
- yargs
43
- .command(
44
- "list",
45
- "List your Cloudflare Pages projects",
46
- Projects.ListOptions,
47
- Projects.ListHandler
48
- )
49
- .command(
50
- "create [project-name]",
51
- "Create a new Cloudflare Pages project",
52
- Projects.CreateOptions,
53
- Projects.CreateHandler
54
- )
55
- .command("upload [directory]", false, Upload.Options, Upload.Handler)
56
- .epilogue(pagesBetaWarning)
57
- )
58
- .command(
59
- "deployment",
60
- "🚀 Interact with the deployments of a project",
61
- (yargs) =>
23
+ return (
24
+ yargs
25
+ .command(
26
+ "dev [directory] [-- command..]",
27
+ "🧑‍💻 Develop your full-stack Pages application locally",
28
+ Dev.Options,
29
+ Dev.Handler
30
+ )
31
+ /**
32
+ * `wrangler pages functions` is meant for internal use only for now,
33
+ * so let's hide this command from the help output
34
+ */
35
+ .command("functions", false, (yargs) =>
36
+ yargs
37
+ .command(
38
+ "build [directory]",
39
+ "Compile a folder of Cloudflare Pages Functions into a single Worker",
40
+ Build.Options,
41
+ Build.Handler
42
+ )
43
+ .command(
44
+ "optimize-routes [routesPath] [outputRoutesPath]",
45
+ "Consolidate and optimize the route paths declared in _routes.json",
46
+ Functions.OptimizeRoutesOptions,
47
+ Functions.OptimizeRoutesHandler
48
+ )
49
+ )
50
+ .command("project", "⚡️ Interact with your Pages projects", (yargs) =>
62
51
  yargs
63
52
  .command(
64
53
  "list",
65
- "List deployments in your Cloudflare Pages project",
66
- Deployments.ListOptions,
67
- Deployments.ListHandler
54
+ "List your Cloudflare Pages projects",
55
+ Projects.ListOptions,
56
+ Projects.ListHandler
68
57
  )
69
58
  .command(
70
- "create [directory]",
71
- "🆙 Publish a directory of static assets as a Pages deployment",
72
- Publish.Options,
73
- Publish.Handler
59
+ "create [project-name]",
60
+ "Create a new Cloudflare Pages project",
61
+ Projects.CreateOptions,
62
+ Projects.CreateHandler
74
63
  )
64
+ .command("upload [directory]", false, Upload.Options, Upload.Handler)
75
65
  .epilogue(pagesBetaWarning)
76
- )
77
- .command(
78
- "publish [directory]",
79
- "🆙 Publish a directory of static assets as a Pages deployment",
80
- Publish.Options,
81
- Publish.Handler
82
- )
83
- .epilogue(pagesBetaWarning);
66
+ )
67
+ .command(
68
+ "deployment",
69
+ "🚀 Interact with the deployments of a project",
70
+ (yargs) =>
71
+ yargs
72
+ .command(
73
+ "list",
74
+ "List deployments in your Cloudflare Pages project",
75
+ Deployments.ListOptions,
76
+ Deployments.ListHandler
77
+ )
78
+ .command(
79
+ "create [directory]",
80
+ "🆙 Publish a directory of static assets as a Pages deployment",
81
+ Publish.Options,
82
+ Publish.Handler
83
+ )
84
+ .epilogue(pagesBetaWarning)
85
+ )
86
+ .command(
87
+ "publish [directory]",
88
+ "🆙 Publish a directory of static assets as a Pages deployment",
89
+ Publish.Options,
90
+ Publish.Handler
91
+ )
92
+ .epilogue(pagesBetaWarning)
93
+ );
84
94
  };
@@ -124,12 +124,18 @@ export async function CreateHandler({
124
124
  isGitDir = false;
125
125
  }
126
126
 
127
+ if (isGitDir) {
128
+ try {
129
+ productionBranch = execSync(`git rev-parse --abbrev-ref HEAD`)
130
+ .toString()
131
+ .trim();
132
+ } catch (err) {}
133
+ }
134
+
127
135
  productionBranch = await prompt(
128
136
  "Enter the production branch name:",
129
137
  "text",
130
- isGitDir
131
- ? execSync(`git rev-parse --abbrev-ref HEAD`).toString().trim()
132
- : "production"
138
+ productionBranch ?? "production"
133
139
  );
134
140
  }
135
141
 
@@ -16,22 +16,25 @@ import * as metrics from "../metrics";
16
16
  import { requireAuth } from "../user";
17
17
  import { buildFunctions } from "./build";
18
18
  import { PAGES_CONFIG_CACHE_FILENAME } from "./constants";
19
+ import { FunctionsNoRoutesError, getFunctionsNoRoutesWarning } from "./errors";
20
+ import {
21
+ isRoutesJSONSpec,
22
+ optimizeRoutesJSONSpec,
23
+ } from "./functions/routes-transformation";
19
24
  import { listProjects } from "./projects";
20
25
  import { upload } from "./upload";
21
26
  import { pagesBetaWarning } from "./utils";
22
- import type { Deployment, PagesConfigCache, Project } from "./types";
23
- import type { ArgumentsCamelCase, Argv } from "yargs";
24
-
25
- type PublishArgs = {
26
- directory: string;
27
- "project-name"?: string;
28
- branch?: string;
29
- "commit-hash"?: string;
30
- "commit-message"?: string;
31
- "commit-dirty"?: boolean;
32
- };
27
+ import type {
28
+ Deployment,
29
+ PagesConfigCache,
30
+ Project,
31
+ YargsOptionsToInterface,
32
+ } from "./types";
33
+ import type { Argv } from "yargs";
34
+
35
+ type PublishArgs = YargsOptionsToInterface<typeof Options>;
33
36
 
34
- export function Options(yargs: Argv): Argv<PublishArgs> {
37
+ export function Options(yargs: Argv) {
35
38
  return yargs
36
39
  .positional("directory", {
37
40
  type: "string",
@@ -77,7 +80,7 @@ export const Handler = async ({
77
80
  commitMessage,
78
81
  commitDirty,
79
82
  config: wranglerConfig,
80
- }: ArgumentsCamelCase<PublishArgs>) => {
83
+ }: PublishArgs) => {
81
84
  if (wranglerConfig) {
82
85
  throw new FatalError("Pages does not support wrangler.toml", 1);
83
86
  }
@@ -251,19 +254,27 @@ export const Handler = async ({
251
254
 
252
255
  let builtFunctions: string | undefined = undefined;
253
256
  const functionsDirectory = join(cwd(), "functions");
257
+ const routesOutputPath = join(tmpdir(), `_routes-${Math.random()}.json`);
254
258
  if (existsSync(functionsDirectory)) {
255
259
  const outfile = join(tmpdir(), `./functionsWorker-${Math.random()}.js`);
256
-
257
- await new Promise((resolve) =>
258
- buildFunctions({
260
+ try {
261
+ await buildFunctions({
259
262
  outfile,
260
263
  functionsDirectory,
261
- onEnd: () => resolve(null),
264
+ onEnd: () => {},
262
265
  buildOutputDirectory: dirname(outfile),
263
- })
264
- );
265
-
266
- builtFunctions = readFileSync(outfile, "utf-8");
266
+ routesOutputPath,
267
+ });
268
+ builtFunctions = readFileSync(outfile, "utf-8");
269
+ } catch (e) {
270
+ if (e instanceof FunctionsNoRoutesError) {
271
+ logger.warn(
272
+ getFunctionsNoRoutesWarning(functionsDirectory, "skipping")
273
+ );
274
+ } else {
275
+ throw e;
276
+ }
277
+ }
267
278
  }
268
279
 
269
280
  const manifest = await upload({ directory, accountId, projectName });
@@ -290,6 +301,7 @@ export const Handler = async ({
290
301
 
291
302
  let _headers: string | undefined,
292
303
  _redirects: string | undefined,
304
+ _routes: string | undefined,
293
305
  _workerJS: string | undefined;
294
306
 
295
307
  try {
@@ -306,18 +318,59 @@ export const Handler = async ({
306
318
 
307
319
  if (_headers) {
308
320
  formData.append("_headers", new File([_headers], "_headers"));
321
+ logger.log(`✨ Uploading _headers`);
309
322
  }
310
323
 
311
324
  if (_redirects) {
312
325
  formData.append("_redirects", new File([_redirects], "_redirects"));
326
+ logger.log(`✨ Uploading _redirects`);
313
327
  }
314
328
 
315
329
  if (builtFunctions) {
316
330
  formData.append("_worker.js", new File([builtFunctions], "_worker.js"));
331
+ logger.log(`✨ Uploading Functions`);
332
+ try {
333
+ _routes = readFileSync(routesOutputPath, "utf-8");
334
+ if (_routes) {
335
+ formData.append("_routes.json", new File([_routes], "_routes.json"));
336
+ }
337
+ } catch {}
317
338
  } else if (_workerJS) {
339
+ // Advanced Mode
340
+ // https://developers.cloudflare.com/pages/platform/functions/#advanced-mode
318
341
  formData.append("_worker.js", new File([_workerJS], "_worker.js"));
319
- }
342
+ logger.log(`✨ Uploading _worker.js`);
343
+
344
+ try {
345
+ // In advanced mode, developers can specify a custom _routes.json
346
+ // file. In which case, we need to run it through optimization
347
+ // to potentially reduce the overall worker pipeline size
348
+ const routesPath = join(directory, "_routes.json");
349
+ const advancedModeRoutesString = readFileSync(routesPath, "utf-8");
350
+ const advancedModeRoutes = JSON.parse(advancedModeRoutesString);
351
+
352
+ if (!isRoutesJSONSpec(advancedModeRoutes)) {
353
+ throw new FatalError(
354
+ "Invalid _routes.json file found at:" + routesPath,
355
+ 1
356
+ );
357
+ }
358
+
359
+ _routes = JSON.stringify(optimizeRoutesJSONSpec(advancedModeRoutes));
360
+ formData.append("_routes.json", new File([_routes], "_routes.json"));
361
+ logger.log(`✨ Uploading _routes.json`);
320
362
 
363
+ logger.warn(
364
+ `🚨 _routes.json is an experimental feature and is subject to change. Don't use unless you really must!`
365
+ );
366
+ } catch (e) {
367
+ // Ignore file not existing errors for _routes.json but forward the potential
368
+ // FatalError from an invalid spec
369
+ if (e instanceof FatalError) {
370
+ throw e;
371
+ }
372
+ }
373
+ }
321
374
  const deploymentResponse = await fetchResult<Deployment>(
322
375
  `/accounts/${accountId}/pages/projects/${projectName}/deployments`,
323
376
  {
@@ -1,3 +1,12 @@
1
+ import type { ArgumentsCamelCase, Argv } from "yargs";
2
+
3
+ /**
4
+ * Given some Yargs Options function factory, extract the interface
5
+ * that corresponds to the yargs arguments
6
+ */
7
+ export type YargsOptionsToInterface<T extends (yargs: Argv) => Argv> =
8
+ T extends (yargs: Argv) => Argv<infer P> ? ArgumentsCamelCase<P> : never;
9
+
1
10
  export type Project = {
2
11
  name: string;
3
12
  subdomain: string;
@@ -26,15 +26,12 @@ import {
26
26
  MAX_UPLOAD_ATTEMPTS,
27
27
  } from "./constants";
28
28
  import { pagesBetaWarning } from "./utils";
29
- import type { UploadPayloadFile } from "./types";
30
- import type { ArgumentsCamelCase, Argv } from "yargs";
29
+ import type { UploadPayloadFile, YargsOptionsToInterface } from "./types";
30
+ import type { Argv } from "yargs";
31
31
 
32
- type UploadArgs = {
33
- directory: string;
34
- "output-manifest-path"?: string;
35
- };
32
+ type UploadArgs = YargsOptionsToInterface<typeof Options>;
36
33
 
37
- export function Options(yargs: Argv): Argv<UploadArgs> {
34
+ export function Options(yargs: Argv) {
38
35
  return yargs
39
36
  .positional("directory", {
40
37
  type: "string",
@@ -53,7 +50,7 @@ export function Options(yargs: Argv): Argv<UploadArgs> {
53
50
  export const Handler = async ({
54
51
  directory,
55
52
  outputManifestPath,
56
- }: ArgumentsCamelCase<UploadArgs>) => {
53
+ }: UploadArgs) => {
57
54
  if (!directory) {
58
55
  throw new FatalError("Must specify a directory.", 1);
59
56
  }
@@ -106,6 +103,7 @@ export const upload = async (
106
103
  "_worker.js",
107
104
  "_redirects",
108
105
  "_headers",
106
+ "_routes.json",
109
107
  ".DS_Store",
110
108
  "node_modules",
111
109
  ".git",
package/src/proxy.ts CHANGED
@@ -177,6 +177,7 @@ export function usePreviewServer({
177
177
  const cleanupListeners: (() => void)[] = [];
178
178
 
179
179
  // create a ClientHttp2Session
180
+ logger.debug("PREVIEW URL:", `https://${previewToken.host}`);
180
181
  const remote = connect(`https://${previewToken.host}`);
181
182
  cleanupListeners.push(() => remote.destroy());
182
183
 
@@ -221,6 +222,15 @@ export function usePreviewServer({
221
222
  }
222
223
  }
223
224
  const request = message.pipe(remote.request(headers));
225
+ logger.debug(
226
+ "WORKER REQUEST",
227
+ new Date().toLocaleTimeString(),
228
+ method,
229
+ url
230
+ );
231
+ logger.debug("HEADERS", JSON.stringify(headers, null, 2));
232
+ logger.debug("PREVIEW TOKEN", previewToken);
233
+
224
234
  request.on("response", (responseHeaders) => {
225
235
  const status = responseHeaders[":status"] ?? 500;
226
236
 
package/src/r2.ts CHANGED
@@ -33,10 +33,10 @@ export async function createR2Bucket(
33
33
  accountId: string,
34
34
  bucketName: string
35
35
  ): Promise<void> {
36
- return await fetchResult<void>(
37
- `/accounts/${accountId}/r2/buckets/${bucketName}`,
38
- { method: "PUT" }
39
- );
36
+ return await fetchResult<void>(`/accounts/${accountId}/r2/buckets`, {
37
+ method: "POST",
38
+ body: JSON.stringify({ name: bucketName }),
39
+ });
40
40
  }
41
41
 
42
42
  /**
@@ -116,3 +116,16 @@ export async function putR2Object(
116
116
  }
117
117
  );
118
118
  }
119
+ /**
120
+ * Delete an Object
121
+ */
122
+ export async function deleteR2Object(
123
+ accountId: string,
124
+ bucketName: string,
125
+ objectName: string
126
+ ): Promise<void> {
127
+ await fetchR2Objects(
128
+ `/accounts/${accountId}/r2/buckets/${bucketName}/objects/${objectName}`,
129
+ { method: "DELETE" }
130
+ );
131
+ }
@@ -58,13 +58,14 @@ type OutcomeFilter = {
58
58
 
59
59
  /**
60
60
  * There are five possible outcomes we can get, three of which
61
- * (exception, exceededCpu, and unknown) are considered errors
61
+ * (exception, exceededCpu, exceededMemory, and unknown) are considered errors
62
62
  */
63
63
  export type Outcome =
64
64
  | "ok"
65
65
  | "canceled"
66
66
  | "exception"
67
67
  | "exceededCpu"
68
+ | "exceededMemory"
68
69
  | "unknown";
69
70
 
70
71
  /**
@@ -210,6 +211,7 @@ function parseOutcome(
210
211
  case "error":
211
212
  outcomes.add("exception");
212
213
  outcomes.add("exceededCpu");
214
+ outcomes.add("exceededMemory");
213
215
  outcomes.add("unknown");
214
216
  break;
215
217