wrangler 0.0.0-e178d6fb → 0.0.0-e1c2f5b9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -2
- package/bin/wrangler.js +31 -11
- package/miniflare-dist/index.mjs +1340 -330
- package/package.json +40 -13
- package/src/__tests__/access.test.ts +25 -0
- package/src/__tests__/api-dev.test.ts +238 -0
- package/src/__tests__/api-devregistry.test.js +64 -0
- package/src/__tests__/api.test.ts +80 -0
- package/src/__tests__/configuration.test.ts +683 -470
- package/src/__tests__/d1.test.ts +123 -0
- package/src/__tests__/delete.test.ts +263 -0
- package/src/__tests__/deployments.test.ts +105 -0
- package/src/__tests__/dev.test.tsx +453 -70
- package/src/__tests__/dialogs.test.tsx +40 -0
- package/src/__tests__/generate.test.ts +235 -0
- package/src/__tests__/get-host-from-url.test.ts +16 -0
- package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
- package/src/__tests__/helpers/mock-cfetch.ts +92 -26
- package/src/__tests__/helpers/mock-console.ts +11 -2
- package/src/__tests__/helpers/mock-dialogs.ts +1 -1
- package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
- package/src/__tests__/helpers/mock-known-routes.ts +7 -0
- package/src/__tests__/helpers/mock-kv.ts +1 -1
- package/src/__tests__/helpers/mock-oauth-flow.ts +74 -53
- package/src/__tests__/helpers/mock-process.ts +8 -13
- package/src/__tests__/helpers/msw/handlers/access.ts +13 -0
- package/src/__tests__/helpers/msw/handlers/deployments.ts +59 -0
- package/src/__tests__/helpers/msw/handlers/namespaces.ts +104 -0
- package/src/__tests__/helpers/msw/handlers/oauth.ts +31 -0
- package/src/__tests__/helpers/msw/handlers/r2.ts +80 -0
- package/src/__tests__/helpers/msw/handlers/script.ts +75 -0
- package/src/__tests__/helpers/msw/handlers/user.ts +63 -0
- package/src/__tests__/helpers/msw/handlers/zones.ts +22 -0
- package/src/__tests__/helpers/msw/index.ts +21 -0
- package/src/__tests__/helpers/worker-scripts/child-wrangler.toml +1 -0
- package/src/__tests__/helpers/worker-scripts/hello-world-worker.js +5 -0
- package/src/__tests__/helpers/worker-scripts/hello-world-wrangler.toml +1 -0
- package/src/__tests__/helpers/worker-scripts/parent-worker.js +8 -0
- package/src/__tests__/helpers/worker-scripts/parent-wrangler.toml +5 -0
- package/src/__tests__/index.test.ts +103 -97
- package/src/__tests__/init.test.ts +1484 -382
- package/src/__tests__/jest.setup.ts +88 -5
- package/src/__tests__/kv.test.ts +655 -540
- package/src/__tests__/logout.test.ts +47 -0
- package/src/__tests__/metrics.test.ts +95 -45
- package/src/__tests__/middleware.scheduled.test.ts +145 -0
- package/src/__tests__/middleware.test.ts +750 -0
- package/src/__tests__/pages-deployment-tail.test.ts +884 -0
- package/src/__tests__/pages.test.ts +1301 -119
- package/src/__tests__/paths.test.ts +39 -0
- package/src/__tests__/publish.test.ts +2266 -1180
- package/src/__tests__/pubsub.test.ts +211 -88
- package/src/__tests__/queues.test.ts +522 -0
- package/src/__tests__/r2.test.ts +363 -203
- package/src/__tests__/secret.test.ts +261 -59
- package/src/__tests__/tail.test.ts +352 -151
- package/src/__tests__/test-old-node-version.js +3 -3
- package/src/__tests__/tsconfig-sanity.ts +12 -0
- package/src/__tests__/tsconfig.json +8 -0
- package/src/__tests__/tsconfig.tsbuildinfo +1 -0
- package/src/__tests__/type-generation.test.ts +233 -0
- package/src/__tests__/user.test.ts +59 -73
- package/src/__tests__/utils-collectKeyValues.test.ts +47 -0
- package/src/__tests__/validate-dev-props.test.ts +56 -0
- package/src/__tests__/whoami.test.tsx +114 -66
- package/src/__tests__/worker-namespace.test.ts +154 -155
- package/src/api/dev.ts +170 -38
- package/src/api/index.ts +1 -0
- package/src/bundle-reporter.tsx +41 -2
- package/src/bundle.ts +668 -81
- package/src/cfetch/index.ts +40 -3
- package/src/cfetch/internal.ts +144 -32
- package/src/cli.ts +4 -3
- package/src/config/config.ts +27 -3
- package/src/config/environment.ts +131 -7
- package/src/config/index.ts +128 -8
- package/src/config/validation-helpers.ts +19 -6
- package/src/config/validation.ts +411 -14
- package/src/config-cache.ts +3 -2
- package/src/create-worker-preview.ts +31 -6
- package/src/create-worker-upload-form.ts +84 -22
- package/src/d1/backups.tsx +223 -0
- package/src/d1/constants.ts +2 -0
- package/src/d1/create.tsx +63 -0
- package/src/d1/delete.tsx +56 -0
- package/src/d1/execute.tsx +352 -0
- package/src/d1/formatTimeAgo.ts +14 -0
- package/src/d1/index.ts +101 -0
- package/src/d1/list.tsx +48 -0
- package/src/d1/migrations/apply.tsx +196 -0
- package/src/d1/migrations/create.tsx +77 -0
- package/src/d1/migrations/helpers.ts +147 -0
- package/src/d1/migrations/index.tsx +3 -0
- package/src/d1/migrations/list.tsx +79 -0
- package/src/d1/migrations/options.ts +18 -0
- package/src/d1/options.ts +22 -0
- package/src/d1/types.tsx +24 -0
- package/src/d1/utils.ts +48 -0
- package/src/delete.ts +108 -0
- package/src/deployments.ts +83 -0
- package/src/deprecated/index.ts +145 -0
- package/src/dev/dev-vars.ts +11 -8
- package/src/dev/dev.tsx +220 -58
- package/src/dev/get-local-persistence-path.tsx +31 -0
- package/src/dev/local.tsx +740 -181
- package/src/dev/remote.tsx +340 -123
- package/src/dev/start-server.ts +543 -0
- package/src/dev/use-esbuild.ts +61 -7
- package/src/dev/validate-dev-props.ts +31 -0
- package/src/dev-registry.tsx +201 -0
- package/src/dev.tsx +614 -258
- package/src/dialogs.tsx +41 -8
- package/src/{worker-namespace.ts → dispatch-namespace.ts} +23 -22
- package/src/docs/index.ts +97 -0
- package/src/entry.ts +3 -2
- package/src/environment-variables/factory.ts +88 -0
- package/src/environment-variables/misc-variables.ts +30 -0
- package/src/generate/index.ts +300 -0
- package/src/git-client.ts +100 -7
- package/src/index.tsx +249 -1560
- package/src/init.ts +626 -150
- package/src/inspect.ts +137 -32
- package/src/{metrics/is-ci.ts → is-ci.ts} +0 -0
- package/src/is-interactive.ts +4 -0
- package/src/jest.d.ts +4 -0
- package/src/{kv.ts → kv/helpers.ts} +3 -3
- package/src/kv/index.ts +596 -0
- package/src/logger.ts +27 -8
- package/src/metrics/index.ts +1 -0
- package/src/metrics/metrics-config.ts +4 -4
- package/src/metrics/metrics-dispatcher.ts +1 -0
- package/src/metrics/metrics-usage-headers.ts +24 -0
- package/src/metrics/send-event.ts +13 -8
- package/src/miniflare-cli/assets.ts +172 -465
- package/src/miniflare-cli/index.ts +149 -24
- package/src/miniflare-cli/tsconfig.json +9 -0
- package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
- package/src/miniflare-cli/types.ts +11 -0
- package/src/module-collection.ts +12 -3
- package/src/pages/build.tsx +108 -42
- package/src/pages/constants.ts +11 -0
- package/src/pages/deployment-tails.tsx +284 -0
- package/src/pages/deployments.tsx +9 -31
- package/src/pages/dev.tsx +417 -108
- package/src/pages/errors.ts +66 -0
- package/src/pages/functions/buildPlugin.ts +86 -84
- package/src/pages/functions/buildWorker.ts +121 -106
- package/src/pages/functions/routes-consolidation.test.ts +250 -0
- package/src/pages/functions/routes-consolidation.ts +73 -0
- package/src/pages/functions/routes-transformation.test.ts +282 -0
- package/src/pages/functions/routes-transformation.ts +115 -0
- package/src/pages/functions/routes-validation.test.ts +403 -0
- package/src/pages/functions/routes-validation.ts +202 -0
- package/src/pages/functions/tsconfig.json +8 -0
- package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
- package/src/pages/functions.tsx +82 -0
- package/src/pages/hash.tsx +13 -0
- package/src/pages/index.tsx +73 -55
- package/src/pages/projects.tsx +9 -3
- package/src/pages/prompt-select-project.tsx +31 -0
- package/src/pages/publish.tsx +183 -60
- package/src/pages/types.ts +1 -0
- package/src/pages/upload.tsx +107 -56
- package/src/pages/utils.ts +13 -2
- package/src/paths.ts +49 -4
- package/src/proxy.ts +375 -157
- package/src/publish/index.ts +270 -0
- package/src/{publish.ts → publish/publish.ts} +431 -188
- package/src/pubsub/pubsub-commands.tsx +4 -3
- package/src/queues/cli/commands/consumer/add.ts +71 -0
- package/src/queues/cli/commands/consumer/index.ts +22 -0
- package/src/queues/cli/commands/consumer/remove.ts +38 -0
- package/src/queues/cli/commands/create.ts +25 -0
- package/src/queues/cli/commands/delete.ts +26 -0
- package/src/queues/cli/commands/index.ts +36 -0
- package/src/queues/cli/commands/list.ts +25 -0
- package/src/queues/client.ts +135 -0
- package/src/queues/utils.ts +18 -0
- package/src/r2/constants.ts +4 -0
- package/src/r2/helpers.ts +131 -0
- package/src/r2/index.ts +289 -0
- package/src/routes.ts +140 -0
- package/src/secret/index.ts +379 -0
- package/src/sites.tsx +3 -3
- package/src/tail/createTail.ts +379 -0
- package/src/tail/filters.ts +4 -6
- package/src/tail/index.ts +199 -284
- package/src/tail/printing.ts +43 -3
- package/src/tsconfig-sanity.ts +16 -0
- package/src/type-generation.ts +181 -0
- package/src/user/access.ts +68 -0
- package/src/user/auth-variables.ts +113 -0
- package/src/user/choose-account.tsx +1 -1
- package/src/user/index.ts +0 -1
- package/src/user/user.tsx +116 -49
- package/src/utils/collectKeyValues.ts +14 -0
- package/src/whoami.tsx +80 -2
- package/src/worker.ts +69 -9
- package/src/yargs-types.ts +24 -0
- package/src/zones.ts +124 -9
- package/templates/__tests__/pages-dev-util.test.ts +128 -0
- package/templates/__tests__/tsconfig-sanity.ts +12 -0
- package/templates/__tests__/tsconfig.json +8 -0
- package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
- package/templates/d1-beta-facade.js +205 -0
- package/templates/facade.d.ts +14 -0
- package/templates/first-party-worker-module-facade.ts +19 -0
- package/templates/format-dev-errors.ts +33 -0
- package/templates/init-tests/test-jest-new-worker.js +23 -0
- package/templates/init-tests/test-vitest-new-worker.js +24 -0
- package/templates/init-tests/test-vitest-new-worker.ts +25 -0
- package/templates/middleware/common.ts +62 -0
- package/templates/middleware/loader-modules.ts +82 -0
- package/templates/middleware/loader-sw.ts +233 -0
- package/templates/middleware/middleware-miniflare3-json-error.ts +20 -0
- package/templates/middleware/middleware-pretty-error.ts +40 -0
- package/templates/middleware/middleware-scheduled.ts +15 -0
- package/templates/new-worker.js +1 -1
- package/templates/pages-dev-pipeline.ts +31 -0
- package/templates/pages-dev-util.ts +52 -0
- package/templates/pages-shim.ts +4 -1
- package/templates/pages-template-plugin.ts +21 -5
- package/templates/pages-template-worker.ts +37 -9
- package/templates/{static-asset-facade.js → serve-static-assets.ts} +23 -7
- package/templates/service-bindings-module-facade.js +54 -0
- package/templates/service-bindings-sw-facade.js +42 -0
- package/templates/tsconfig-sanity.ts +11 -0
- package/templates/tsconfig.init.json +106 -0
- package/templates/tsconfig.json +5 -102
- package/templates/tsconfig.tsbuildinfo +1 -0
- package/wrangler-dist/cli.d.ts +621 -42
- package/wrangler-dist/cli.js +144441 -102606
- package/src/environment-variables.ts +0 -35
- package/src/faye-websocket.d.ts +0 -6
- package/src/generate.ts +0 -33
- package/src/miniflare-cli/enum-keys.ts +0 -17
- package/src/preview.ts +0 -31
- package/src/r2.ts +0 -50
- package/src/user/env-vars.ts +0 -46
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { chdir } from "node:process";
|
|
3
|
+
import { ROUTES_SPEC_VERSION } from "../pages/constants";
|
|
4
|
+
import { isRoutesJSONSpec } from "../pages/functions/routes-validation";
|
|
5
|
+
import { version } from "./../../package.json";
|
|
3
6
|
import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
|
|
4
7
|
import {
|
|
5
8
|
createFetchResult,
|
|
@@ -57,23 +60,24 @@ describe("pages", () => {
|
|
|
57
60
|
await endEventLoop();
|
|
58
61
|
|
|
59
62
|
expect(std.out).toMatchInlineSnapshot(`
|
|
60
|
-
|
|
63
|
+
"wrangler pages
|
|
61
64
|
|
|
62
|
-
|
|
65
|
+
⚡️ Configure Cloudflare Pages
|
|
63
66
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
Commands:
|
|
68
|
+
wrangler pages dev [directory] [-- command..] 🧑💻 Develop your full-stack Pages application locally
|
|
69
|
+
wrangler pages project ⚡️ Interact with your Pages projects
|
|
70
|
+
wrangler pages deployment 🚀 Interact with the deployments of a project
|
|
71
|
+
wrangler pages publish [directory] 🆙 Publish a directory of static assets as a Pages deployment
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
Flags:
|
|
74
|
+
-c, --config Path to .toml configuration file [string]
|
|
75
|
+
-e, --env Environment to use for operations and .env files [string]
|
|
76
|
+
-h, --help Show help [boolean]
|
|
77
|
+
-v, --version Show version number [boolean]
|
|
74
78
|
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose"
|
|
80
|
+
`);
|
|
77
81
|
});
|
|
78
82
|
|
|
79
83
|
describe("beta message for subcommands", () => {
|
|
@@ -81,24 +85,38 @@ describe("pages", () => {
|
|
|
81
85
|
await expect(
|
|
82
86
|
runWrangler("pages dev")
|
|
83
87
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
84
|
-
`"Must specify a directory of static assets to serve or a command to run."`
|
|
88
|
+
`"Must specify a directory of static assets to serve or a command to run or a proxy port."`
|
|
85
89
|
);
|
|
86
90
|
|
|
87
91
|
expect(std.out).toMatchInlineSnapshot(`
|
|
88
|
-
|
|
92
|
+
"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose[0m"
|
|
95
|
+
`);
|
|
92
96
|
});
|
|
93
97
|
|
|
94
98
|
it("should display for pages:functions:build", async () => {
|
|
95
99
|
await expect(runWrangler("pages functions build")).rejects.toThrowError();
|
|
96
100
|
|
|
97
101
|
expect(std.out).toMatchInlineSnapshot(`
|
|
98
|
-
|
|
102
|
+
"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
|
|
99
103
|
|
|
100
|
-
|
|
101
|
-
|
|
104
|
+
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose[0m"
|
|
105
|
+
`);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should display for pages:functions:optimize-routes", async () => {
|
|
109
|
+
await expect(
|
|
110
|
+
runWrangler(
|
|
111
|
+
'pages functions optimize-routes --routes-path="/build/_routes.json" --output-routes-path="/build/_optimized-routes.json"'
|
|
112
|
+
)
|
|
113
|
+
).rejects.toThrowError();
|
|
114
|
+
|
|
115
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
116
|
+
"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
|
|
117
|
+
|
|
118
|
+
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose[0m"
|
|
119
|
+
`);
|
|
102
120
|
});
|
|
103
121
|
});
|
|
104
122
|
|
|
@@ -220,9 +238,9 @@ describe("pages", () => {
|
|
|
220
238
|
"pages project create a-new-project --production-branch=main"
|
|
221
239
|
);
|
|
222
240
|
expect(std.out).toMatchInlineSnapshot(`
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
241
|
+
"✨ Successfully created the 'a-new-project' project. It will be available at https://a-new-project.pages.dev/ once you create your first deployment.
|
|
242
|
+
To deploy a folder of assets, run 'wrangler pages publish [directory]'."
|
|
243
|
+
`);
|
|
226
244
|
});
|
|
227
245
|
});
|
|
228
246
|
|
|
@@ -255,6 +273,7 @@ describe("pages", () => {
|
|
|
255
273
|
id: "87bbc8fe-16be-45cd-81e0-63d722e82cdf",
|
|
256
274
|
url: "https://87bbc8fe.images.pages.dev",
|
|
257
275
|
environment: "preview",
|
|
276
|
+
created_on: "2021-11-17T14:52:26.133835Z",
|
|
258
277
|
latest_stage: {
|
|
259
278
|
ended_on: "2021-11-17T14:52:26.133835Z",
|
|
260
279
|
status: "success",
|
|
@@ -298,26 +317,28 @@ describe("pages", () => {
|
|
|
298
317
|
await endEventLoop();
|
|
299
318
|
|
|
300
319
|
expect(std.out).toMatchInlineSnapshot(`
|
|
301
|
-
|
|
320
|
+
"wrangler pages publish [directory]
|
|
302
321
|
|
|
303
|
-
|
|
322
|
+
🆙 Publish a directory of static assets as a Pages deployment
|
|
304
323
|
|
|
305
|
-
|
|
306
|
-
|
|
324
|
+
Positionals:
|
|
325
|
+
directory The directory of static files to upload [string]
|
|
307
326
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
327
|
+
Flags:
|
|
328
|
+
-e, --env Environment to use for operations and .env files [string]
|
|
329
|
+
-h, --help Show help [boolean]
|
|
330
|
+
-v, --version Show version number [boolean]
|
|
311
331
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
332
|
+
Options:
|
|
333
|
+
--project-name The name of the project you want to deploy to [string]
|
|
334
|
+
--branch The name of the branch you want to deploy to [string]
|
|
335
|
+
--commit-hash The SHA to attach to this deployment [string]
|
|
336
|
+
--commit-message The commit message to attach to this deployment [string]
|
|
337
|
+
--commit-dirty Whether or not the workspace should be considered dirty for this deployment [boolean]
|
|
338
|
+
--skip-caching Skip asset caching which speeds up builds [boolean]
|
|
318
339
|
|
|
319
|
-
|
|
320
|
-
|
|
340
|
+
🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose"
|
|
341
|
+
`);
|
|
321
342
|
});
|
|
322
343
|
|
|
323
344
|
it("should upload a directory of files", async () => {
|
|
@@ -370,10 +391,10 @@ describe("pages", () => {
|
|
|
370
391
|
const body = init.body as FormData;
|
|
371
392
|
const manifest = JSON.parse(body.get("manifest") as string);
|
|
372
393
|
expect(manifest).toMatchInlineSnapshot(`
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
394
|
+
Object {
|
|
395
|
+
"/logo.png": "2082190357cfd3617ccfe04f340c6247",
|
|
396
|
+
}
|
|
397
|
+
`);
|
|
377
398
|
});
|
|
378
399
|
|
|
379
400
|
return {
|
|
@@ -382,15 +403,24 @@ describe("pages", () => {
|
|
|
382
403
|
}
|
|
383
404
|
);
|
|
384
405
|
|
|
385
|
-
|
|
406
|
+
setMockResponse(
|
|
407
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
408
|
+
"GET",
|
|
409
|
+
async ([_url, accountId]) => {
|
|
410
|
+
assertLater(() => {
|
|
411
|
+
expect(accountId).toEqual("some-account-id");
|
|
412
|
+
});
|
|
413
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
414
|
+
}
|
|
415
|
+
);
|
|
386
416
|
|
|
387
|
-
|
|
417
|
+
await runWrangler("pages publish . --project-name=foo");
|
|
388
418
|
|
|
389
|
-
|
|
390
|
-
|
|
419
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
420
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
391
421
|
|
|
392
|
-
|
|
393
|
-
|
|
422
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
423
|
+
`);
|
|
394
424
|
});
|
|
395
425
|
|
|
396
426
|
it("should retry uploads", async () => {
|
|
@@ -441,10 +471,10 @@ describe("pages", () => {
|
|
|
441
471
|
const body = init.body as FormData;
|
|
442
472
|
const manifest = JSON.parse(body.get("manifest") as string);
|
|
443
473
|
expect(manifest).toMatchInlineSnapshot(`
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
474
|
+
Object {
|
|
475
|
+
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
476
|
+
}
|
|
477
|
+
`);
|
|
448
478
|
});
|
|
449
479
|
|
|
450
480
|
return {
|
|
@@ -453,6 +483,17 @@ describe("pages", () => {
|
|
|
453
483
|
}
|
|
454
484
|
);
|
|
455
485
|
|
|
486
|
+
setMockResponse(
|
|
487
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
488
|
+
"GET",
|
|
489
|
+
async ([_url, accountId]) => {
|
|
490
|
+
assertLater(() => {
|
|
491
|
+
expect(accountId).toEqual("some-account-id");
|
|
492
|
+
});
|
|
493
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
494
|
+
}
|
|
495
|
+
);
|
|
496
|
+
|
|
456
497
|
await runWrangler("pages publish . --project-name=foo");
|
|
457
498
|
|
|
458
499
|
// Assert two identical requests
|
|
@@ -478,10 +519,10 @@ describe("pages", () => {
|
|
|
478
519
|
}
|
|
479
520
|
|
|
480
521
|
expect(std.out).toMatchInlineSnapshot(`
|
|
481
|
-
|
|
522
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
482
523
|
|
|
483
|
-
|
|
484
|
-
|
|
524
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
525
|
+
`);
|
|
485
526
|
});
|
|
486
527
|
|
|
487
528
|
it("should refetch a JWT if it expires while uploading", async () => {
|
|
@@ -535,10 +576,10 @@ describe("pages", () => {
|
|
|
535
576
|
const body = init.body as FormData;
|
|
536
577
|
const manifest = JSON.parse(body.get("manifest") as string);
|
|
537
578
|
expect(manifest).toMatchInlineSnapshot(`
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
579
|
+
Object {
|
|
580
|
+
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
581
|
+
}
|
|
582
|
+
`);
|
|
542
583
|
});
|
|
543
584
|
|
|
544
585
|
return {
|
|
@@ -547,6 +588,17 @@ describe("pages", () => {
|
|
|
547
588
|
}
|
|
548
589
|
);
|
|
549
590
|
|
|
591
|
+
setMockResponse(
|
|
592
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
593
|
+
"GET",
|
|
594
|
+
async ([_url, accountId]) => {
|
|
595
|
+
assertLater(() => {
|
|
596
|
+
expect(accountId).toEqual("some-account-id");
|
|
597
|
+
});
|
|
598
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
599
|
+
}
|
|
600
|
+
);
|
|
601
|
+
|
|
550
602
|
await runWrangler("pages publish . --project-name=foo");
|
|
551
603
|
|
|
552
604
|
// Assert two requests
|
|
@@ -575,10 +627,10 @@ describe("pages", () => {
|
|
|
575
627
|
}
|
|
576
628
|
|
|
577
629
|
expect(std.out).toMatchInlineSnapshot(`
|
|
578
|
-
|
|
630
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
579
631
|
|
|
580
|
-
|
|
581
|
-
|
|
632
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
633
|
+
`);
|
|
582
634
|
});
|
|
583
635
|
|
|
584
636
|
it("should try to use multiple buckets (up to the max concurrency)", async () => {
|
|
@@ -626,13 +678,13 @@ describe("pages", () => {
|
|
|
626
678
|
const body = init.body as FormData;
|
|
627
679
|
const manifest = JSON.parse(body.get("manifest") as string);
|
|
628
680
|
expect(manifest).toMatchInlineSnapshot(`
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
681
|
+
Object {
|
|
682
|
+
"/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
|
|
683
|
+
"/logo.js": "6be321bef99e758250dac034474ddbb8",
|
|
684
|
+
"/logo.png": "2082190357cfd3617ccfe04f340c6247",
|
|
685
|
+
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
686
|
+
}
|
|
687
|
+
`);
|
|
636
688
|
});
|
|
637
689
|
|
|
638
690
|
return {
|
|
@@ -641,6 +693,17 @@ describe("pages", () => {
|
|
|
641
693
|
}
|
|
642
694
|
);
|
|
643
695
|
|
|
696
|
+
setMockResponse(
|
|
697
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
698
|
+
"GET",
|
|
699
|
+
async ([_url, accountId]) => {
|
|
700
|
+
assertLater(() => {
|
|
701
|
+
expect(accountId).toEqual("some-account-id");
|
|
702
|
+
});
|
|
703
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
704
|
+
}
|
|
705
|
+
);
|
|
706
|
+
|
|
644
707
|
await runWrangler("pages publish . --project-name=foo");
|
|
645
708
|
|
|
646
709
|
// We have 3 buckets, so expect 3 uploads
|
|
@@ -685,10 +748,10 @@ describe("pages", () => {
|
|
|
685
748
|
);
|
|
686
749
|
|
|
687
750
|
expect(std.out).toMatchInlineSnapshot(`
|
|
688
|
-
|
|
751
|
+
"✨ Success! Uploaded 4 files (TIMINGS)
|
|
689
752
|
|
|
690
|
-
|
|
691
|
-
|
|
753
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
754
|
+
`);
|
|
692
755
|
});
|
|
693
756
|
|
|
694
757
|
it("should resolve child directories correctly", async () => {
|
|
@@ -740,13 +803,13 @@ describe("pages", () => {
|
|
|
740
803
|
const body = init.body as FormData;
|
|
741
804
|
const manifest = JSON.parse(body.get("manifest") as string);
|
|
742
805
|
expect(manifest).toMatchInlineSnapshot(`
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
806
|
+
Object {
|
|
807
|
+
"/imgs/logo.png": "2082190357cfd3617ccfe04f340c6247",
|
|
808
|
+
"/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
|
|
809
|
+
"/logo.js": "6be321bef99e758250dac034474ddbb8",
|
|
810
|
+
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
811
|
+
}
|
|
812
|
+
`);
|
|
750
813
|
});
|
|
751
814
|
|
|
752
815
|
return {
|
|
@@ -755,6 +818,17 @@ describe("pages", () => {
|
|
|
755
818
|
}
|
|
756
819
|
);
|
|
757
820
|
|
|
821
|
+
setMockResponse(
|
|
822
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
823
|
+
"GET",
|
|
824
|
+
async ([_url, accountId]) => {
|
|
825
|
+
assertLater(() => {
|
|
826
|
+
expect(accountId).toEqual("some-account-id");
|
|
827
|
+
});
|
|
828
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
829
|
+
}
|
|
830
|
+
);
|
|
831
|
+
|
|
758
832
|
await runWrangler(`pages publish public --project-name=foo`);
|
|
759
833
|
|
|
760
834
|
// We have 3 buckets, so expect 3 uploads
|
|
@@ -799,10 +873,10 @@ describe("pages", () => {
|
|
|
799
873
|
);
|
|
800
874
|
|
|
801
875
|
expect(std.out).toMatchInlineSnapshot(`
|
|
802
|
-
|
|
876
|
+
"✨ Success! Uploaded 4 files (TIMINGS)
|
|
803
877
|
|
|
804
|
-
|
|
805
|
-
|
|
878
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
879
|
+
`);
|
|
806
880
|
});
|
|
807
881
|
|
|
808
882
|
it("should resolve the current directory correctly", async () => {
|
|
@@ -854,13 +928,13 @@ describe("pages", () => {
|
|
|
854
928
|
const body = init.body as FormData;
|
|
855
929
|
const manifest = JSON.parse(body.get("manifest") as string);
|
|
856
930
|
expect(manifest).toMatchInlineSnapshot(`
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
931
|
+
Object {
|
|
932
|
+
"/imgs/logo.png": "2082190357cfd3617ccfe04f340c6247",
|
|
933
|
+
"/logo.html": "d96fef225537c9f5e44a3cb27fd0b492",
|
|
934
|
+
"/logo.js": "6be321bef99e758250dac034474ddbb8",
|
|
935
|
+
"/logo.txt": "1a98fb08af91aca4a7df1764a2c4ddb0",
|
|
936
|
+
}
|
|
937
|
+
`);
|
|
864
938
|
});
|
|
865
939
|
|
|
866
940
|
return {
|
|
@@ -869,6 +943,17 @@ describe("pages", () => {
|
|
|
869
943
|
}
|
|
870
944
|
);
|
|
871
945
|
|
|
946
|
+
setMockResponse(
|
|
947
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
948
|
+
"GET",
|
|
949
|
+
async ([_url, accountId]) => {
|
|
950
|
+
assertLater(() => {
|
|
951
|
+
expect(accountId).toEqual("some-account-id");
|
|
952
|
+
});
|
|
953
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
954
|
+
}
|
|
955
|
+
);
|
|
956
|
+
|
|
872
957
|
chdir("public");
|
|
873
958
|
await runWrangler(`pages publish . --project-name=foo`);
|
|
874
959
|
|
|
@@ -914,10 +999,10 @@ describe("pages", () => {
|
|
|
914
999
|
);
|
|
915
1000
|
|
|
916
1001
|
expect(std.out).toMatchInlineSnapshot(`
|
|
917
|
-
|
|
1002
|
+
"✨ Success! Uploaded 4 files (TIMINGS)
|
|
918
1003
|
|
|
919
|
-
|
|
920
|
-
|
|
1004
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
1005
|
+
`);
|
|
921
1006
|
});
|
|
922
1007
|
|
|
923
1008
|
it("should not error when directory names contain periods and houses a extensionless file", async () => {
|
|
@@ -971,6 +1056,17 @@ describe("pages", () => {
|
|
|
971
1056
|
})
|
|
972
1057
|
);
|
|
973
1058
|
|
|
1059
|
+
setMockResponse(
|
|
1060
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
1061
|
+
"GET",
|
|
1062
|
+
async ([_url, accountId]) => {
|
|
1063
|
+
assertLater(() => {
|
|
1064
|
+
expect(accountId).toEqual("some-account-id");
|
|
1065
|
+
});
|
|
1066
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
1067
|
+
}
|
|
1068
|
+
);
|
|
1069
|
+
|
|
974
1070
|
await runWrangler("pages publish . --project-name=foo");
|
|
975
1071
|
|
|
976
1072
|
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
@@ -988,27 +1084,336 @@ describe("pages", () => {
|
|
|
988
1084
|
`"Pages does not support wrangler.toml"`
|
|
989
1085
|
);
|
|
990
1086
|
});
|
|
991
|
-
});
|
|
992
1087
|
|
|
993
|
-
|
|
994
|
-
|
|
1088
|
+
it("should upload a Functions project", async () => {
|
|
1089
|
+
// set up the directory of static files to upload.
|
|
1090
|
+
mkdirSync("public");
|
|
1091
|
+
writeFileSync("public/README.md", "This is a readme");
|
|
1092
|
+
|
|
1093
|
+
// set up /functions
|
|
1094
|
+
mkdirSync("functions");
|
|
1095
|
+
writeFileSync(
|
|
1096
|
+
"functions/hello.js",
|
|
1097
|
+
`
|
|
1098
|
+
export async function onRequest() {
|
|
1099
|
+
return new Response("Hello, world!");
|
|
1100
|
+
}
|
|
1101
|
+
`
|
|
1102
|
+
);
|
|
995
1103
|
|
|
996
|
-
|
|
997
|
-
mockApiToken();
|
|
998
|
-
runInTempDir();
|
|
1104
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
999
1105
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1106
|
+
setMockResponse(
|
|
1107
|
+
"/pages/assets/check-missing",
|
|
1108
|
+
"POST",
|
|
1109
|
+
async (_, init) => {
|
|
1110
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
1111
|
+
assertLater(() => {
|
|
1112
|
+
expect(init.headers).toMatchObject({
|
|
1113
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1114
|
+
});
|
|
1115
|
+
expect(body).toMatchObject({
|
|
1116
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1117
|
+
});
|
|
1118
|
+
});
|
|
1119
|
+
return body.hashes;
|
|
1120
|
+
}
|
|
1121
|
+
);
|
|
1122
|
+
|
|
1123
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
1124
|
+
assertLater(() => {
|
|
1125
|
+
expect(init.headers).toMatchObject({
|
|
1126
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1127
|
+
});
|
|
1128
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1129
|
+
expect(body).toMatchObject([
|
|
1130
|
+
{
|
|
1131
|
+
key: "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1132
|
+
value: Buffer.from("This is a readme").toString("base64"),
|
|
1133
|
+
metadata: {
|
|
1134
|
+
contentType: "text/markdown",
|
|
1135
|
+
},
|
|
1136
|
+
base64: true,
|
|
1137
|
+
},
|
|
1138
|
+
]);
|
|
1139
|
+
});
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
setMockResponse(
|
|
1143
|
+
`/pages/assets/upsert-hashes`,
|
|
1144
|
+
"POST",
|
|
1145
|
+
async (_, init) => {
|
|
1146
|
+
assertLater(() => {
|
|
1147
|
+
expect(init.headers).toMatchObject({
|
|
1148
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1149
|
+
});
|
|
1150
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1151
|
+
expect(body).toMatchObject({
|
|
1152
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1153
|
+
});
|
|
1154
|
+
});
|
|
1155
|
+
|
|
1156
|
+
return Promise.resolve(true);
|
|
1157
|
+
}
|
|
1158
|
+
);
|
|
1159
|
+
|
|
1160
|
+
setMockResponse(
|
|
1161
|
+
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
1162
|
+
async ([_url, accountId], init) => {
|
|
1163
|
+
assertLater(async () => {
|
|
1164
|
+
expect(accountId).toEqual("some-account-id");
|
|
1165
|
+
expect(init.method).toEqual("POST");
|
|
1166
|
+
const body = init.body as FormData;
|
|
1167
|
+
const manifest = JSON.parse(body.get("manifest") as string);
|
|
1168
|
+
|
|
1169
|
+
// for Functions projects, we auto-generate a `_worker.js`,
|
|
1170
|
+
// `functions-filepath-routing-config.json`, and `_routes.json`
|
|
1171
|
+
// file, based on the contents of `/functions`
|
|
1172
|
+
const generatedWorkerJS = body.get("_worker.js") as Blob;
|
|
1173
|
+
const generatedRoutesJSON = await (
|
|
1174
|
+
body.get("_routes.json") as Blob
|
|
1175
|
+
).text();
|
|
1176
|
+
const generatedFilepathRoutingConfig = await (
|
|
1177
|
+
body.get("functions-filepath-routing-config.json") as Blob
|
|
1178
|
+
).text();
|
|
1179
|
+
|
|
1180
|
+
// make sure this is all we uploaded
|
|
1181
|
+
expect([...body.keys()]).toEqual([
|
|
1182
|
+
"manifest",
|
|
1183
|
+
"functions-filepath-routing-config.json",
|
|
1184
|
+
"_worker.js",
|
|
1185
|
+
"_routes.json",
|
|
1186
|
+
]);
|
|
1187
|
+
|
|
1188
|
+
expect(manifest).toMatchInlineSnapshot(`
|
|
1189
|
+
Object {
|
|
1190
|
+
"/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1191
|
+
}
|
|
1192
|
+
`);
|
|
1193
|
+
|
|
1194
|
+
// the contents of the generated `_worker.js` file is pretty massive, so I don't
|
|
1195
|
+
// think snapshot testing makes much sense here. Plus, calling
|
|
1196
|
+
// `.toMatchInlineSnapshot()` without any arguments, in order to generate that
|
|
1197
|
+
// snapshot value, doesn't generate anything in this case (probably because the
|
|
1198
|
+
// file contents is too big). So for now, let's test that _worker.js was indeed
|
|
1199
|
+
// generated and that the file size is greater than zero
|
|
1200
|
+
expect(generatedWorkerJS).not.toBeNull();
|
|
1201
|
+
expect(generatedWorkerJS.size).toBeGreaterThan(0);
|
|
1202
|
+
|
|
1203
|
+
const maybeRoutesJSONSpec = JSON.parse(generatedRoutesJSON);
|
|
1204
|
+
expect(isRoutesJSONSpec(maybeRoutesJSONSpec)).toBe(true);
|
|
1205
|
+
expect(maybeRoutesJSONSpec).toMatchObject({
|
|
1206
|
+
version: ROUTES_SPEC_VERSION,
|
|
1207
|
+
description: `Generated by wrangler@${version}`,
|
|
1208
|
+
include: ["/hello"],
|
|
1209
|
+
exclude: [],
|
|
1210
|
+
});
|
|
1211
|
+
|
|
1212
|
+
// Make sure the routing config is valid json
|
|
1213
|
+
const parsedFilepathRoutingConfig = JSON.parse(
|
|
1214
|
+
generatedFilepathRoutingConfig
|
|
1215
|
+
);
|
|
1216
|
+
// The actual shape doesn't matter that much since this
|
|
1217
|
+
// is only used for display in Dash, but it's still useful for
|
|
1218
|
+
// tracking unexpected changes to this config.
|
|
1219
|
+
expect(parsedFilepathRoutingConfig).toStrictEqual({
|
|
1220
|
+
routes: [
|
|
1221
|
+
{
|
|
1222
|
+
routePath: "/hello",
|
|
1223
|
+
mountPath: "/",
|
|
1224
|
+
method: "",
|
|
1225
|
+
module: ["hello.js:onRequest"],
|
|
1226
|
+
},
|
|
1227
|
+
],
|
|
1228
|
+
baseURL: "/",
|
|
1229
|
+
});
|
|
1230
|
+
});
|
|
1231
|
+
|
|
1232
|
+
return {
|
|
1233
|
+
url: "https://abcxyz.foo.pages.dev/",
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
);
|
|
1237
|
+
|
|
1238
|
+
setMockResponse(
|
|
1239
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
1240
|
+
"GET",
|
|
1241
|
+
async ([_url, accountId]) => {
|
|
1242
|
+
assertLater(() => {
|
|
1243
|
+
expect(accountId).toEqual("some-account-id");
|
|
1244
|
+
});
|
|
1245
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
1246
|
+
}
|
|
1247
|
+
);
|
|
1248
|
+
|
|
1249
|
+
await runWrangler("pages publish public --project-name=foo");
|
|
1250
|
+
|
|
1251
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
1252
|
+
"Compiled Worker successfully.
|
|
1253
|
+
✨ Success! Uploaded 1 files (TIMINGS)
|
|
1254
|
+
|
|
1255
|
+
✨ Uploading Functions
|
|
1256
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
1257
|
+
`);
|
|
1258
|
+
|
|
1259
|
+
expect(std.err).toMatchInlineSnapshot('""');
|
|
1003
1260
|
});
|
|
1004
1261
|
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1262
|
+
it("should upload an Advanced Mode project", async () => {
|
|
1263
|
+
// set up the directory of static files to upload.
|
|
1264
|
+
mkdirSync("public");
|
|
1265
|
+
writeFileSync("public/README.md", "This is a readme");
|
|
1266
|
+
|
|
1267
|
+
// set up _worker.js
|
|
1268
|
+
writeFileSync(
|
|
1269
|
+
"public/_worker.js",
|
|
1270
|
+
`
|
|
1271
|
+
export default {
|
|
1272
|
+
async fetch(request, env) {
|
|
1273
|
+
const url = new URL(request.url);
|
|
1274
|
+
return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
|
|
1275
|
+
};
|
|
1276
|
+
`
|
|
1277
|
+
);
|
|
1278
|
+
|
|
1279
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
1280
|
+
|
|
1281
|
+
setMockResponse(
|
|
1282
|
+
"/pages/assets/check-missing",
|
|
1283
|
+
"POST",
|
|
1284
|
+
async (_, init) => {
|
|
1285
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
1286
|
+
assertLater(() => {
|
|
1287
|
+
expect(init.headers).toMatchObject({
|
|
1288
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1289
|
+
});
|
|
1290
|
+
expect(body).toMatchObject({
|
|
1291
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1292
|
+
});
|
|
1293
|
+
});
|
|
1294
|
+
return body.hashes;
|
|
1295
|
+
}
|
|
1296
|
+
);
|
|
1297
|
+
|
|
1298
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
1299
|
+
assertLater(() => {
|
|
1300
|
+
expect(init.headers).toMatchObject({
|
|
1301
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1302
|
+
});
|
|
1303
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1304
|
+
expect(body).toMatchObject([
|
|
1305
|
+
{
|
|
1306
|
+
key: "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1307
|
+
value: Buffer.from("This is a readme").toString("base64"),
|
|
1308
|
+
metadata: {
|
|
1309
|
+
contentType: "text/markdown",
|
|
1310
|
+
},
|
|
1311
|
+
base64: true,
|
|
1312
|
+
},
|
|
1313
|
+
]);
|
|
1314
|
+
});
|
|
1315
|
+
});
|
|
1316
|
+
|
|
1317
|
+
setMockResponse(
|
|
1318
|
+
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
1319
|
+
async ([_url, accountId], init) => {
|
|
1320
|
+
assertLater(async () => {
|
|
1321
|
+
expect(accountId).toEqual("some-account-id");
|
|
1322
|
+
expect(init.method).toEqual("POST");
|
|
1323
|
+
const body = init.body as FormData;
|
|
1324
|
+
const manifest = JSON.parse(body.get("manifest") as string);
|
|
1325
|
+
const customWorkerJS = await (
|
|
1326
|
+
body.get("_worker.js") as Blob
|
|
1327
|
+
).text();
|
|
1328
|
+
|
|
1329
|
+
// make sure this is all we uploaded
|
|
1330
|
+
expect([...body.keys()]).toEqual(["manifest", "_worker.js"]);
|
|
1331
|
+
|
|
1332
|
+
expect(manifest).toMatchInlineSnapshot(`
|
|
1333
|
+
Object {
|
|
1334
|
+
"/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1335
|
+
}
|
|
1336
|
+
`);
|
|
1337
|
+
|
|
1338
|
+
expect(customWorkerJS).toMatchInlineSnapshot(`
|
|
1339
|
+
"
|
|
1340
|
+
export default {
|
|
1341
|
+
async fetch(request, env) {
|
|
1342
|
+
const url = new URL(request.url);
|
|
1343
|
+
return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
|
|
1344
|
+
};
|
|
1345
|
+
"
|
|
1346
|
+
`);
|
|
1347
|
+
});
|
|
1348
|
+
|
|
1349
|
+
return {
|
|
1350
|
+
url: "https://abcxyz.foo.pages.dev/",
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
);
|
|
1354
|
+
|
|
1355
|
+
setMockResponse(
|
|
1356
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
1357
|
+
"GET",
|
|
1358
|
+
async ([_url, accountId]) => {
|
|
1359
|
+
assertLater(() => {
|
|
1360
|
+
expect(accountId).toEqual("some-account-id");
|
|
1361
|
+
});
|
|
1362
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
1363
|
+
}
|
|
1364
|
+
);
|
|
1365
|
+
|
|
1366
|
+
await runWrangler("pages publish public --project-name=foo");
|
|
1367
|
+
|
|
1368
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
1369
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
1370
|
+
|
|
1371
|
+
✨ Uploading _worker.js
|
|
1372
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
1373
|
+
`);
|
|
1374
|
+
|
|
1375
|
+
expect(std.err).toMatchInlineSnapshot('""');
|
|
1008
1376
|
});
|
|
1009
1377
|
|
|
1010
|
-
it("should upload
|
|
1011
|
-
|
|
1378
|
+
it("should upload _routes.json for Functions projects, if provided", async () => {
|
|
1379
|
+
// set up the directory of static files to upload.
|
|
1380
|
+
mkdirSync("public");
|
|
1381
|
+
writeFileSync("public/README.md", "This is a readme");
|
|
1382
|
+
|
|
1383
|
+
// set up /functions
|
|
1384
|
+
mkdirSync("functions");
|
|
1385
|
+
writeFileSync(
|
|
1386
|
+
"functions/hello.js",
|
|
1387
|
+
`
|
|
1388
|
+
export async function onRequest() {
|
|
1389
|
+
return new Response("Hello, world!");
|
|
1390
|
+
}
|
|
1391
|
+
`
|
|
1392
|
+
);
|
|
1393
|
+
|
|
1394
|
+
writeFileSync(
|
|
1395
|
+
"functions/goodbye.ts",
|
|
1396
|
+
`
|
|
1397
|
+
export async function onRequest() {
|
|
1398
|
+
return new Response("Bye bye!");
|
|
1399
|
+
}
|
|
1400
|
+
`
|
|
1401
|
+
);
|
|
1402
|
+
|
|
1403
|
+
// set up _routes.json
|
|
1404
|
+
writeFileSync(
|
|
1405
|
+
"public/_routes.json",
|
|
1406
|
+
`
|
|
1407
|
+
{
|
|
1408
|
+
"version": ${ROUTES_SPEC_VERSION},
|
|
1409
|
+
"description": "Custom _routes.json file",
|
|
1410
|
+
"include": ["/hello"],
|
|
1411
|
+
"exclude": []
|
|
1412
|
+
}
|
|
1413
|
+
`
|
|
1414
|
+
);
|
|
1415
|
+
|
|
1416
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
1012
1417
|
|
|
1013
1418
|
setMockResponse(
|
|
1014
1419
|
"/pages/assets/check-missing",
|
|
@@ -1020,7 +1425,7 @@ describe("pages", () => {
|
|
|
1020
1425
|
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1021
1426
|
});
|
|
1022
1427
|
expect(body).toMatchObject({
|
|
1023
|
-
hashes: ["
|
|
1428
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1024
1429
|
});
|
|
1025
1430
|
});
|
|
1026
1431
|
return body.hashes;
|
|
@@ -1035,10 +1440,10 @@ describe("pages", () => {
|
|
|
1035
1440
|
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1036
1441
|
expect(body).toMatchObject([
|
|
1037
1442
|
{
|
|
1038
|
-
key: "
|
|
1039
|
-
value: Buffer.from("
|
|
1443
|
+
key: "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1444
|
+
value: Buffer.from("This is a readme").toString("base64"),
|
|
1040
1445
|
metadata: {
|
|
1041
|
-
contentType: "
|
|
1446
|
+
contentType: "text/markdown",
|
|
1042
1447
|
},
|
|
1043
1448
|
base64: true,
|
|
1044
1449
|
},
|
|
@@ -1046,13 +1451,790 @@ describe("pages", () => {
|
|
|
1046
1451
|
});
|
|
1047
1452
|
});
|
|
1048
1453
|
|
|
1454
|
+
setMockResponse(
|
|
1455
|
+
`/pages/assets/upsert-hashes`,
|
|
1456
|
+
"POST",
|
|
1457
|
+
async (_, init) => {
|
|
1458
|
+
assertLater(() => {
|
|
1459
|
+
expect(init.headers).toMatchObject({
|
|
1460
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1461
|
+
});
|
|
1462
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1463
|
+
expect(body).toMatchObject({
|
|
1464
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1465
|
+
});
|
|
1466
|
+
});
|
|
1467
|
+
|
|
1468
|
+
return Promise.resolve(true);
|
|
1469
|
+
}
|
|
1470
|
+
);
|
|
1471
|
+
|
|
1472
|
+
setMockResponse(
|
|
1473
|
+
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
1474
|
+
async ([_url, accountId], init) => {
|
|
1475
|
+
assertLater(async () => {
|
|
1476
|
+
expect(accountId).toEqual("some-account-id");
|
|
1477
|
+
expect(init.method).toEqual("POST");
|
|
1478
|
+
const body = init.body as FormData;
|
|
1479
|
+
const manifest = JSON.parse(body.get("manifest") as string);
|
|
1480
|
+
const generatedWorkerJS = body.get("_worker.js") as Blob;
|
|
1481
|
+
const customRoutesJSON = await (
|
|
1482
|
+
body.get("_routes.json") as Blob
|
|
1483
|
+
).text();
|
|
1484
|
+
const generatedFilepathRoutingConfig = await (
|
|
1485
|
+
body.get("functions-filepath-routing-config.json") as Blob
|
|
1486
|
+
).text();
|
|
1487
|
+
|
|
1488
|
+
// make sure this is all we uploaded
|
|
1489
|
+
expect([...body.keys()]).toEqual([
|
|
1490
|
+
"manifest",
|
|
1491
|
+
"functions-filepath-routing-config.json",
|
|
1492
|
+
"_worker.js",
|
|
1493
|
+
"_routes.json",
|
|
1494
|
+
]);
|
|
1495
|
+
|
|
1496
|
+
expect(manifest).toMatchInlineSnapshot(`
|
|
1497
|
+
Object {
|
|
1498
|
+
"/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1499
|
+
}
|
|
1500
|
+
`);
|
|
1501
|
+
|
|
1502
|
+
// file content of generated `_worker.js` is too massive to snapshot test
|
|
1503
|
+
expect(generatedWorkerJS).not.toBeNull();
|
|
1504
|
+
expect(generatedWorkerJS.size).toBeGreaterThan(0);
|
|
1505
|
+
|
|
1506
|
+
const customRoutes = JSON.parse(customRoutesJSON);
|
|
1507
|
+
expect(customRoutes).toMatchObject({
|
|
1508
|
+
version: ROUTES_SPEC_VERSION,
|
|
1509
|
+
description: "Custom _routes.json file",
|
|
1510
|
+
include: ["/hello"],
|
|
1511
|
+
exclude: [],
|
|
1512
|
+
});
|
|
1513
|
+
|
|
1514
|
+
// Make sure the routing config is valid json
|
|
1515
|
+
const parsedFilepathRoutingConfig = JSON.parse(
|
|
1516
|
+
generatedFilepathRoutingConfig
|
|
1517
|
+
);
|
|
1518
|
+
// The actual shape doesn't matter that much since this
|
|
1519
|
+
// is only used for display in Dash, but it's still useful for
|
|
1520
|
+
// tracking unexpected changes to this config.
|
|
1521
|
+
console.log(generatedFilepathRoutingConfig);
|
|
1522
|
+
expect(parsedFilepathRoutingConfig).toStrictEqual({
|
|
1523
|
+
routes: [
|
|
1524
|
+
{
|
|
1525
|
+
routePath: "/goodbye",
|
|
1526
|
+
mountPath: "/",
|
|
1527
|
+
method: "",
|
|
1528
|
+
module: ["goodbye.ts:onRequest"],
|
|
1529
|
+
},
|
|
1530
|
+
{
|
|
1531
|
+
routePath: "/hello",
|
|
1532
|
+
mountPath: "/",
|
|
1533
|
+
method: "",
|
|
1534
|
+
module: ["hello.js:onRequest"],
|
|
1535
|
+
},
|
|
1536
|
+
],
|
|
1537
|
+
baseURL: "/",
|
|
1538
|
+
});
|
|
1539
|
+
});
|
|
1540
|
+
|
|
1541
|
+
return {
|
|
1542
|
+
url: "https://abcxyz.foo.pages.dev/",
|
|
1543
|
+
};
|
|
1544
|
+
}
|
|
1545
|
+
);
|
|
1546
|
+
|
|
1547
|
+
setMockResponse(
|
|
1548
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
1549
|
+
"GET",
|
|
1550
|
+
async ([_url, accountId]) => {
|
|
1551
|
+
assertLater(() => {
|
|
1552
|
+
expect(accountId).toEqual("some-account-id");
|
|
1553
|
+
});
|
|
1554
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
1555
|
+
}
|
|
1556
|
+
);
|
|
1557
|
+
|
|
1558
|
+
await runWrangler("pages publish public --project-name=foo");
|
|
1559
|
+
|
|
1560
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
1561
|
+
"Compiled Worker successfully.
|
|
1562
|
+
✨ Success! Uploaded 1 files (TIMINGS)
|
|
1563
|
+
|
|
1564
|
+
✨ Uploading Functions
|
|
1565
|
+
✨ Uploading _routes.json
|
|
1566
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
1567
|
+
`);
|
|
1568
|
+
|
|
1569
|
+
expect(std.warn).toMatchInlineSnapshot(`
|
|
1570
|
+
"[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1m_routes.json is an experimental feature and is subject to change. Please use with care.[0m
|
|
1571
|
+
|
|
1572
|
+
"
|
|
1573
|
+
`);
|
|
1574
|
+
|
|
1575
|
+
expect(std.err).toMatchInlineSnapshot('""');
|
|
1576
|
+
});
|
|
1577
|
+
|
|
1578
|
+
it("should not deploy Functions projects that provide an invalid custom _routes.json file", async () => {
|
|
1579
|
+
// set up the directory of static files to upload.
|
|
1580
|
+
mkdirSync("public");
|
|
1581
|
+
writeFileSync("public/README.md", "This is a readme");
|
|
1582
|
+
|
|
1583
|
+
// set up _routes.json
|
|
1584
|
+
writeFileSync(
|
|
1585
|
+
"public/_routes.json",
|
|
1586
|
+
`
|
|
1587
|
+
{
|
|
1588
|
+
"description": "Custom _routes.json file",
|
|
1589
|
+
"include": [],
|
|
1590
|
+
"exclude": []
|
|
1591
|
+
}
|
|
1592
|
+
`
|
|
1593
|
+
);
|
|
1594
|
+
|
|
1595
|
+
// set up /functions
|
|
1596
|
+
mkdirSync("functions");
|
|
1597
|
+
writeFileSync(
|
|
1598
|
+
"functions/hello.js",
|
|
1599
|
+
`
|
|
1600
|
+
export async function onRequest() {
|
|
1601
|
+
return new Response("Hello, world!");
|
|
1602
|
+
}
|
|
1603
|
+
`
|
|
1604
|
+
);
|
|
1605
|
+
|
|
1606
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
1607
|
+
|
|
1608
|
+
setMockResponse(
|
|
1609
|
+
"/pages/assets/check-missing",
|
|
1610
|
+
"POST",
|
|
1611
|
+
async (_, init) => {
|
|
1612
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
1613
|
+
assertLater(() => {
|
|
1614
|
+
expect(init.headers).toMatchObject({
|
|
1615
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1616
|
+
});
|
|
1617
|
+
expect(body).toMatchObject({
|
|
1618
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1619
|
+
});
|
|
1620
|
+
});
|
|
1621
|
+
return body.hashes;
|
|
1622
|
+
}
|
|
1623
|
+
);
|
|
1624
|
+
|
|
1625
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
1626
|
+
assertLater(() => {
|
|
1627
|
+
expect(init.headers).toMatchObject({
|
|
1628
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1629
|
+
});
|
|
1630
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1631
|
+
expect(body).toMatchObject([
|
|
1632
|
+
{
|
|
1633
|
+
key: "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1634
|
+
value: Buffer.from("This is a readme").toString("base64"),
|
|
1635
|
+
metadata: {
|
|
1636
|
+
contentType: "text/markdown",
|
|
1637
|
+
},
|
|
1638
|
+
base64: true,
|
|
1639
|
+
},
|
|
1640
|
+
]);
|
|
1641
|
+
});
|
|
1642
|
+
});
|
|
1643
|
+
|
|
1644
|
+
setMockResponse(
|
|
1645
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
1646
|
+
"GET",
|
|
1647
|
+
async ([_url, accountId]) => {
|
|
1648
|
+
assertLater(() => {
|
|
1649
|
+
expect(accountId).toEqual("some-account-id");
|
|
1650
|
+
});
|
|
1651
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
1652
|
+
}
|
|
1653
|
+
);
|
|
1654
|
+
|
|
1655
|
+
await expect(runWrangler("pages publish public --project-name=foo"))
|
|
1656
|
+
.rejects
|
|
1657
|
+
.toThrow(`Invalid _routes.json file found at: public/_routes.json
|
|
1658
|
+
Please make sure the JSON object has the following format:
|
|
1659
|
+
{
|
|
1660
|
+
version: ${ROUTES_SPEC_VERSION};
|
|
1661
|
+
include: string[];
|
|
1662
|
+
exclude: string[];
|
|
1663
|
+
}
|
|
1664
|
+
and that at least one include rule is provided.
|
|
1665
|
+
`);
|
|
1666
|
+
});
|
|
1667
|
+
|
|
1668
|
+
it("should upload _routes.json for Advanced Mode projects, if provided", async () => {
|
|
1669
|
+
// set up the directory of static files to upload.
|
|
1670
|
+
mkdirSync("public");
|
|
1671
|
+
writeFileSync("public/README.md", "This is a readme");
|
|
1672
|
+
|
|
1673
|
+
// set up _routes.json
|
|
1674
|
+
writeFileSync(
|
|
1675
|
+
"public/_routes.json",
|
|
1676
|
+
`
|
|
1677
|
+
{
|
|
1678
|
+
"version": ${ROUTES_SPEC_VERSION},
|
|
1679
|
+
"description": "Custom _routes.json file",
|
|
1680
|
+
"include": ["/api/*"],
|
|
1681
|
+
"exclude": []
|
|
1682
|
+
}
|
|
1683
|
+
`
|
|
1684
|
+
);
|
|
1685
|
+
|
|
1686
|
+
// set up _worker.js
|
|
1687
|
+
writeFileSync(
|
|
1688
|
+
"public/_worker.js",
|
|
1689
|
+
`
|
|
1690
|
+
export default {
|
|
1691
|
+
async fetch(request, env) {
|
|
1692
|
+
const url = new URL(request.url);
|
|
1693
|
+
return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
|
|
1694
|
+
};
|
|
1695
|
+
`
|
|
1696
|
+
);
|
|
1697
|
+
|
|
1698
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
1699
|
+
|
|
1700
|
+
setMockResponse(
|
|
1701
|
+
"/pages/assets/check-missing",
|
|
1702
|
+
"POST",
|
|
1703
|
+
async (_, init) => {
|
|
1704
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
1705
|
+
assertLater(() => {
|
|
1706
|
+
expect(init.headers).toMatchObject({
|
|
1707
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1708
|
+
});
|
|
1709
|
+
expect(body).toMatchObject({
|
|
1710
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1711
|
+
});
|
|
1712
|
+
});
|
|
1713
|
+
return body.hashes;
|
|
1714
|
+
}
|
|
1715
|
+
);
|
|
1716
|
+
|
|
1717
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
1718
|
+
assertLater(() => {
|
|
1719
|
+
expect(init.headers).toMatchObject({
|
|
1720
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1721
|
+
});
|
|
1722
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1723
|
+
expect(body).toMatchObject([
|
|
1724
|
+
{
|
|
1725
|
+
key: "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1726
|
+
value: Buffer.from("This is a readme").toString("base64"),
|
|
1727
|
+
metadata: {
|
|
1728
|
+
contentType: "text/markdown",
|
|
1729
|
+
},
|
|
1730
|
+
base64: true,
|
|
1731
|
+
},
|
|
1732
|
+
]);
|
|
1733
|
+
});
|
|
1734
|
+
});
|
|
1735
|
+
|
|
1736
|
+
setMockResponse(
|
|
1737
|
+
`/pages/assets/upsert-hashes`,
|
|
1738
|
+
"POST",
|
|
1739
|
+
async (_, init) => {
|
|
1740
|
+
assertLater(() => {
|
|
1741
|
+
expect(init.headers).toMatchObject({
|
|
1742
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1743
|
+
});
|
|
1744
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1745
|
+
expect(body).toMatchObject({
|
|
1746
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1747
|
+
});
|
|
1748
|
+
});
|
|
1749
|
+
|
|
1750
|
+
return Promise.resolve(true);
|
|
1751
|
+
}
|
|
1752
|
+
);
|
|
1753
|
+
|
|
1754
|
+
setMockResponse(
|
|
1755
|
+
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
1756
|
+
async ([_url, accountId], init) => {
|
|
1757
|
+
assertLater(async () => {
|
|
1758
|
+
expect(accountId).toEqual("some-account-id");
|
|
1759
|
+
expect(init.method).toEqual("POST");
|
|
1760
|
+
const body = init.body as FormData;
|
|
1761
|
+
const manifest = JSON.parse(body.get("manifest") as string);
|
|
1762
|
+
const customWorkerJS = await (
|
|
1763
|
+
body.get("_worker.js") as Blob
|
|
1764
|
+
).text();
|
|
1765
|
+
const customRoutesJSON = await (
|
|
1766
|
+
body.get("_routes.json") as Blob
|
|
1767
|
+
).text();
|
|
1768
|
+
|
|
1769
|
+
// make sure this is all we uploaded
|
|
1770
|
+
expect([...body.keys()]).toEqual([
|
|
1771
|
+
"manifest",
|
|
1772
|
+
"_worker.js",
|
|
1773
|
+
"_routes.json",
|
|
1774
|
+
]);
|
|
1775
|
+
|
|
1776
|
+
expect(manifest).toMatchInlineSnapshot(`
|
|
1777
|
+
Object {
|
|
1778
|
+
"/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1779
|
+
}
|
|
1780
|
+
`);
|
|
1781
|
+
|
|
1782
|
+
expect(customWorkerJS).toMatchInlineSnapshot(`
|
|
1783
|
+
"
|
|
1784
|
+
export default {
|
|
1785
|
+
async fetch(request, env) {
|
|
1786
|
+
const url = new URL(request.url);
|
|
1787
|
+
return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
|
|
1788
|
+
};
|
|
1789
|
+
"
|
|
1790
|
+
`);
|
|
1791
|
+
|
|
1792
|
+
const customRoutes = JSON.parse(customRoutesJSON);
|
|
1793
|
+
expect(customRoutes).toMatchObject({
|
|
1794
|
+
version: ROUTES_SPEC_VERSION,
|
|
1795
|
+
description: "Custom _routes.json file",
|
|
1796
|
+
include: ["/api/*"],
|
|
1797
|
+
exclude: [],
|
|
1798
|
+
});
|
|
1799
|
+
});
|
|
1800
|
+
|
|
1801
|
+
return {
|
|
1802
|
+
url: "https://abcxyz.foo.pages.dev/",
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
);
|
|
1806
|
+
|
|
1807
|
+
setMockResponse(
|
|
1808
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
1809
|
+
"GET",
|
|
1810
|
+
async ([_url, accountId]) => {
|
|
1811
|
+
assertLater(() => {
|
|
1812
|
+
expect(accountId).toEqual("some-account-id");
|
|
1813
|
+
});
|
|
1814
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
1815
|
+
}
|
|
1816
|
+
);
|
|
1817
|
+
|
|
1818
|
+
await runWrangler("pages publish public --project-name=foo");
|
|
1819
|
+
|
|
1820
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
1821
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
1822
|
+
|
|
1823
|
+
✨ Uploading _worker.js
|
|
1824
|
+
✨ Uploading _routes.json
|
|
1825
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
1826
|
+
`);
|
|
1827
|
+
|
|
1828
|
+
expect(std.warn).toMatchInlineSnapshot(`
|
|
1829
|
+
"[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1m_routes.json is an experimental feature and is subject to change. Please use with care.[0m
|
|
1830
|
+
|
|
1831
|
+
"
|
|
1832
|
+
`);
|
|
1833
|
+
expect(std.err).toMatchInlineSnapshot(`""`);
|
|
1834
|
+
});
|
|
1835
|
+
|
|
1836
|
+
it("should not deploy Advanced Mode projects that provide an invalid _routes.json file", async () => {
|
|
1837
|
+
// set up the directory of static files to upload.
|
|
1838
|
+
mkdirSync("public");
|
|
1839
|
+
writeFileSync("public/README.md", "This is a readme");
|
|
1840
|
+
|
|
1841
|
+
// set up _routes.json
|
|
1842
|
+
writeFileSync(
|
|
1843
|
+
"public/_routes.json",
|
|
1844
|
+
`
|
|
1845
|
+
{
|
|
1846
|
+
"description": "Custom _routes.json file",
|
|
1847
|
+
"include": [],
|
|
1848
|
+
"exclude": []
|
|
1849
|
+
}
|
|
1850
|
+
`
|
|
1851
|
+
);
|
|
1852
|
+
|
|
1853
|
+
// set up _worker.js
|
|
1854
|
+
writeFileSync(
|
|
1855
|
+
"public/_worker.js",
|
|
1856
|
+
`
|
|
1857
|
+
export default {
|
|
1858
|
+
async fetch(request, env) {
|
|
1859
|
+
const url = new URL(request.url);
|
|
1860
|
+
return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
|
|
1861
|
+
};
|
|
1862
|
+
`
|
|
1863
|
+
);
|
|
1864
|
+
|
|
1865
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
1866
|
+
|
|
1867
|
+
setMockResponse(
|
|
1868
|
+
"/pages/assets/check-missing",
|
|
1869
|
+
"POST",
|
|
1870
|
+
async (_, init) => {
|
|
1871
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
1872
|
+
assertLater(() => {
|
|
1873
|
+
expect(init.headers).toMatchObject({
|
|
1874
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1875
|
+
});
|
|
1876
|
+
expect(body).toMatchObject({
|
|
1877
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1878
|
+
});
|
|
1879
|
+
});
|
|
1880
|
+
return body.hashes;
|
|
1881
|
+
}
|
|
1882
|
+
);
|
|
1883
|
+
|
|
1884
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
1885
|
+
assertLater(() => {
|
|
1886
|
+
expect(init.headers).toMatchObject({
|
|
1887
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1888
|
+
});
|
|
1889
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1890
|
+
expect(body).toMatchObject([
|
|
1891
|
+
{
|
|
1892
|
+
key: "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1893
|
+
value: Buffer.from("This is a readme").toString("base64"),
|
|
1894
|
+
metadata: {
|
|
1895
|
+
contentType: "text/markdown",
|
|
1896
|
+
},
|
|
1897
|
+
base64: true,
|
|
1898
|
+
},
|
|
1899
|
+
]);
|
|
1900
|
+
});
|
|
1901
|
+
});
|
|
1902
|
+
|
|
1903
|
+
setMockResponse(
|
|
1904
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
1905
|
+
"GET",
|
|
1906
|
+
async ([_url, accountId]) => {
|
|
1907
|
+
assertLater(() => {
|
|
1908
|
+
expect(accountId).toEqual("some-account-id");
|
|
1909
|
+
});
|
|
1910
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
1911
|
+
}
|
|
1912
|
+
);
|
|
1913
|
+
|
|
1914
|
+
await expect(runWrangler("pages publish public --project-name=foo"))
|
|
1915
|
+
.rejects
|
|
1916
|
+
.toThrow(`Invalid _routes.json file found at: public/_routes.json
|
|
1917
|
+
Please make sure the JSON object has the following format:
|
|
1918
|
+
{
|
|
1919
|
+
version: ${ROUTES_SPEC_VERSION};
|
|
1920
|
+
include: string[];
|
|
1921
|
+
exclude: string[];
|
|
1922
|
+
}
|
|
1923
|
+
and that at least one include rule is provided.
|
|
1924
|
+
`);
|
|
1925
|
+
});
|
|
1926
|
+
|
|
1927
|
+
it("should ignore the entire /functions directory if _worker.js is provided", async () => {
|
|
1928
|
+
// set up the directory of static files to upload.
|
|
1929
|
+
mkdirSync("public");
|
|
1930
|
+
writeFileSync("public/README.md", "This is a readme");
|
|
1931
|
+
|
|
1932
|
+
// set up /functions
|
|
1933
|
+
mkdirSync("functions");
|
|
1934
|
+
writeFileSync(
|
|
1935
|
+
"functions/hello.js",
|
|
1936
|
+
`
|
|
1937
|
+
export async function onRequest() {
|
|
1938
|
+
return new Response("Hello, world!");
|
|
1939
|
+
}
|
|
1940
|
+
`
|
|
1941
|
+
);
|
|
1942
|
+
|
|
1943
|
+
// set up _worker.js
|
|
1944
|
+
writeFileSync(
|
|
1945
|
+
"public/_worker.js",
|
|
1946
|
+
`
|
|
1947
|
+
export default {
|
|
1948
|
+
async fetch(request, env) {
|
|
1949
|
+
const url = new URL(request.url);
|
|
1950
|
+
return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
|
|
1951
|
+
};
|
|
1952
|
+
`
|
|
1953
|
+
);
|
|
1954
|
+
|
|
1955
|
+
mockGetToken("<<funfetti-auth-jwt>>");
|
|
1956
|
+
|
|
1957
|
+
setMockResponse(
|
|
1958
|
+
"/pages/assets/check-missing",
|
|
1959
|
+
"POST",
|
|
1960
|
+
async (_, init) => {
|
|
1961
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
1962
|
+
assertLater(() => {
|
|
1963
|
+
expect(init.headers).toMatchObject({
|
|
1964
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1965
|
+
});
|
|
1966
|
+
expect(body).toMatchObject({
|
|
1967
|
+
hashes: ["13a03eaf24ae98378acd36ea00f77f2f"],
|
|
1968
|
+
});
|
|
1969
|
+
});
|
|
1970
|
+
return body.hashes;
|
|
1971
|
+
}
|
|
1972
|
+
);
|
|
1973
|
+
|
|
1974
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
1975
|
+
assertLater(() => {
|
|
1976
|
+
expect(init.headers).toMatchObject({
|
|
1977
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
1978
|
+
});
|
|
1979
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
1980
|
+
expect(body).toMatchObject([
|
|
1981
|
+
{
|
|
1982
|
+
key: "13a03eaf24ae98378acd36ea00f77f2f",
|
|
1983
|
+
value: Buffer.from("This is a readme").toString("base64"),
|
|
1984
|
+
metadata: {
|
|
1985
|
+
contentType: "text/markdown",
|
|
1986
|
+
},
|
|
1987
|
+
base64: true,
|
|
1988
|
+
},
|
|
1989
|
+
]);
|
|
1990
|
+
});
|
|
1991
|
+
});
|
|
1992
|
+
|
|
1993
|
+
setMockResponse(
|
|
1994
|
+
"/accounts/:accountId/pages/projects/foo/deployments",
|
|
1995
|
+
async ([_url, accountId], init) => {
|
|
1996
|
+
assertLater(async () => {
|
|
1997
|
+
expect(accountId).toEqual("some-account-id");
|
|
1998
|
+
expect(init.method).toEqual("POST");
|
|
1999
|
+
const body = init.body as FormData;
|
|
2000
|
+
const manifest = JSON.parse(body.get("manifest") as string);
|
|
2001
|
+
const customWorkerJS = await (
|
|
2002
|
+
body.get("_worker.js") as Blob
|
|
2003
|
+
).text();
|
|
2004
|
+
|
|
2005
|
+
// make sure this is all we uploaded
|
|
2006
|
+
expect([...body.keys()]).toEqual(["manifest", "_worker.js"]);
|
|
2007
|
+
|
|
2008
|
+
expect(manifest).toMatchInlineSnapshot(`
|
|
2009
|
+
Object {
|
|
2010
|
+
"/README.md": "13a03eaf24ae98378acd36ea00f77f2f",
|
|
2011
|
+
}
|
|
2012
|
+
`);
|
|
2013
|
+
|
|
2014
|
+
expect(customWorkerJS).toMatchInlineSnapshot(`
|
|
2015
|
+
"
|
|
2016
|
+
export default {
|
|
2017
|
+
async fetch(request, env) {
|
|
2018
|
+
const url = new URL(request.url);
|
|
2019
|
+
return url.pathname.startsWith('/api/') ? new Response('Ok') : env.ASSETS.fetch(request);
|
|
2020
|
+
};
|
|
2021
|
+
"
|
|
2022
|
+
`);
|
|
2023
|
+
});
|
|
2024
|
+
|
|
2025
|
+
return {
|
|
2026
|
+
url: "https://abcxyz.foo.pages.dev/",
|
|
2027
|
+
};
|
|
2028
|
+
}
|
|
2029
|
+
);
|
|
2030
|
+
|
|
2031
|
+
setMockResponse(
|
|
2032
|
+
"/accounts/:accountId/pages/projects/foo",
|
|
2033
|
+
"GET",
|
|
2034
|
+
async ([_url, accountId]) => {
|
|
2035
|
+
assertLater(() => {
|
|
2036
|
+
expect(accountId).toEqual("some-account-id");
|
|
2037
|
+
});
|
|
2038
|
+
return { deployment_configs: { production: {}, preview: {} } };
|
|
2039
|
+
}
|
|
2040
|
+
);
|
|
2041
|
+
|
|
2042
|
+
await runWrangler("pages publish public --project-name=foo");
|
|
2043
|
+
|
|
2044
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
2045
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
2046
|
+
|
|
2047
|
+
✨ Uploading _worker.js
|
|
2048
|
+
✨ Deployment complete! Take a peek over at https://abcxyz.foo.pages.dev/"
|
|
2049
|
+
`);
|
|
2050
|
+
|
|
2051
|
+
expect(std.err).toMatchInlineSnapshot('""');
|
|
2052
|
+
});
|
|
2053
|
+
});
|
|
2054
|
+
|
|
2055
|
+
describe("project upload", () => {
|
|
2056
|
+
const ENV_COPY = process.env;
|
|
2057
|
+
|
|
2058
|
+
mockAccountId();
|
|
2059
|
+
mockApiToken();
|
|
2060
|
+
runInTempDir();
|
|
2061
|
+
|
|
2062
|
+
beforeEach(() => {
|
|
2063
|
+
process.env.CI = "true";
|
|
2064
|
+
process.env.CF_PAGES_UPLOAD_JWT = "<<funfetti-auth-jwt>>";
|
|
2065
|
+
});
|
|
2066
|
+
|
|
2067
|
+
afterEach(() => {
|
|
2068
|
+
unsetAllMocks();
|
|
2069
|
+
process.env = ENV_COPY;
|
|
2070
|
+
});
|
|
2071
|
+
|
|
2072
|
+
it("should upload a directory of files with a provided JWT", async () => {
|
|
2073
|
+
writeFileSync("logo.png", "foobar");
|
|
2074
|
+
|
|
2075
|
+
setMockResponse(
|
|
2076
|
+
"/pages/assets/check-missing",
|
|
2077
|
+
"POST",
|
|
2078
|
+
async (_, init) => {
|
|
2079
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
2080
|
+
assertLater(() => {
|
|
2081
|
+
expect(init.headers).toMatchObject({
|
|
2082
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
2083
|
+
});
|
|
2084
|
+
expect(body).toMatchObject({
|
|
2085
|
+
hashes: ["2082190357cfd3617ccfe04f340c6247"],
|
|
2086
|
+
});
|
|
2087
|
+
});
|
|
2088
|
+
return body.hashes;
|
|
2089
|
+
}
|
|
2090
|
+
);
|
|
2091
|
+
|
|
2092
|
+
setMockResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
2093
|
+
assertLater(() => {
|
|
2094
|
+
expect(init.headers).toMatchObject({
|
|
2095
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
2096
|
+
});
|
|
2097
|
+
const body = JSON.parse(init.body as string) as UploadPayloadFile[];
|
|
2098
|
+
expect(body).toMatchObject([
|
|
2099
|
+
{
|
|
2100
|
+
key: "2082190357cfd3617ccfe04f340c6247",
|
|
2101
|
+
value: Buffer.from("foobar").toString("base64"),
|
|
2102
|
+
metadata: {
|
|
2103
|
+
contentType: "image/png",
|
|
2104
|
+
},
|
|
2105
|
+
base64: true,
|
|
2106
|
+
},
|
|
2107
|
+
]);
|
|
2108
|
+
});
|
|
2109
|
+
});
|
|
2110
|
+
|
|
2111
|
+
await runWrangler("pages project upload .");
|
|
2112
|
+
|
|
2113
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
2114
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
2115
|
+
|
|
2116
|
+
✨ Upload complete!"
|
|
2117
|
+
`);
|
|
2118
|
+
});
|
|
2119
|
+
|
|
2120
|
+
it("should avoid uploading some files", async () => {
|
|
2121
|
+
mkdirSync("some_dir/node_modules", { recursive: true });
|
|
2122
|
+
mkdirSync("some_dir/functions", { recursive: true });
|
|
2123
|
+
|
|
2124
|
+
writeFileSync("logo.png", "foobar");
|
|
2125
|
+
writeFileSync("some_dir/functions/foo.js", "func");
|
|
2126
|
+
writeFileSync("some_dir/_headers", "headersfile");
|
|
2127
|
+
|
|
2128
|
+
writeFileSync("_headers", "headersfile");
|
|
2129
|
+
writeFileSync("_redirects", "redirectsfile");
|
|
2130
|
+
writeFileSync("_worker.js", "workerfile");
|
|
2131
|
+
writeFileSync("_routes.json", "routesfile");
|
|
2132
|
+
mkdirSync(".git");
|
|
2133
|
+
writeFileSync(".git/foo", "gitfile");
|
|
2134
|
+
writeFileSync("some_dir/node_modules/some_package", "nodefile");
|
|
2135
|
+
mkdirSync("functions");
|
|
2136
|
+
writeFileSync("functions/foo.js", "func");
|
|
2137
|
+
|
|
2138
|
+
setMockResponse(
|
|
2139
|
+
"/pages/assets/check-missing",
|
|
2140
|
+
"POST",
|
|
2141
|
+
async (_, init) => {
|
|
2142
|
+
const body = JSON.parse(init.body as string) as { hashes: string[] };
|
|
2143
|
+
assertLater(() => {
|
|
2144
|
+
expect(init.headers).toMatchObject({
|
|
2145
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
2146
|
+
});
|
|
2147
|
+
expect(body).toMatchObject({
|
|
2148
|
+
hashes: [
|
|
2149
|
+
"2082190357cfd3617ccfe04f340c6247",
|
|
2150
|
+
"95dedb64e6d4940fc2e0f11f711cc2f4",
|
|
2151
|
+
"09a79777abda8ccc8bdd51dd3ff8e9e9",
|
|
2152
|
+
],
|
|
2153
|
+
});
|
|
2154
|
+
});
|
|
2155
|
+
return body.hashes;
|
|
2156
|
+
}
|
|
2157
|
+
);
|
|
2158
|
+
|
|
2159
|
+
// Accumulate multiple requests then assert afterwards
|
|
2160
|
+
const requests: RequestInit[] = [];
|
|
2161
|
+
setMockRawResponse("/pages/assets/upload", "POST", async (_, init) => {
|
|
2162
|
+
requests.push(init);
|
|
2163
|
+
|
|
2164
|
+
return createFetchResult(null, true);
|
|
2165
|
+
});
|
|
2166
|
+
|
|
2167
|
+
assertLater(() => {
|
|
2168
|
+
expect(requests.length).toBe(3);
|
|
2169
|
+
|
|
2170
|
+
const sortedRequests = requests.sort((a, b) => {
|
|
2171
|
+
return (JSON.parse(a.body as string)[0].key as string).localeCompare(
|
|
2172
|
+
JSON.parse(b.body as string)[0].key as string
|
|
2173
|
+
);
|
|
2174
|
+
});
|
|
2175
|
+
|
|
2176
|
+
expect(sortedRequests[0].headers).toMatchObject({
|
|
2177
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
2178
|
+
});
|
|
2179
|
+
|
|
2180
|
+
let body = JSON.parse(
|
|
2181
|
+
sortedRequests[0].body as string
|
|
2182
|
+
) as UploadPayloadFile[];
|
|
2183
|
+
expect(body).toMatchObject([
|
|
2184
|
+
{
|
|
2185
|
+
key: "09a79777abda8ccc8bdd51dd3ff8e9e9",
|
|
2186
|
+
value: Buffer.from("func").toString("base64"),
|
|
2187
|
+
metadata: {
|
|
2188
|
+
contentType: "application/javascript",
|
|
2189
|
+
},
|
|
2190
|
+
base64: true,
|
|
2191
|
+
},
|
|
2192
|
+
]);
|
|
2193
|
+
|
|
2194
|
+
expect(sortedRequests[1].headers).toMatchObject({
|
|
2195
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
2196
|
+
});
|
|
2197
|
+
|
|
2198
|
+
body = JSON.parse(
|
|
2199
|
+
sortedRequests[1].body as string
|
|
2200
|
+
) as UploadPayloadFile[];
|
|
2201
|
+
expect(body).toMatchObject([
|
|
2202
|
+
{
|
|
2203
|
+
key: "2082190357cfd3617ccfe04f340c6247",
|
|
2204
|
+
value: Buffer.from("foobar").toString("base64"),
|
|
2205
|
+
metadata: {
|
|
2206
|
+
contentType: "image/png",
|
|
2207
|
+
},
|
|
2208
|
+
base64: true,
|
|
2209
|
+
},
|
|
2210
|
+
]);
|
|
2211
|
+
|
|
2212
|
+
expect(sortedRequests[2].headers).toMatchObject({
|
|
2213
|
+
Authorization: "Bearer <<funfetti-auth-jwt>>",
|
|
2214
|
+
});
|
|
2215
|
+
|
|
2216
|
+
body = JSON.parse(
|
|
2217
|
+
sortedRequests[2].body as string
|
|
2218
|
+
) as UploadPayloadFile[];
|
|
2219
|
+
expect(body).toMatchObject([
|
|
2220
|
+
{
|
|
2221
|
+
key: "95dedb64e6d4940fc2e0f11f711cc2f4",
|
|
2222
|
+
value: Buffer.from("headersfile").toString("base64"),
|
|
2223
|
+
metadata: {
|
|
2224
|
+
contentType: "application/octet-stream",
|
|
2225
|
+
},
|
|
2226
|
+
base64: true,
|
|
2227
|
+
},
|
|
2228
|
+
]);
|
|
2229
|
+
});
|
|
2230
|
+
|
|
1049
2231
|
await runWrangler("pages project upload .");
|
|
1050
2232
|
|
|
1051
2233
|
expect(std.out).toMatchInlineSnapshot(`
|
|
1052
|
-
|
|
2234
|
+
"✨ Success! Uploaded 3 files (TIMINGS)
|
|
1053
2235
|
|
|
1054
|
-
|
|
1055
|
-
|
|
2236
|
+
✨ Upload complete!"
|
|
2237
|
+
`);
|
|
1056
2238
|
});
|
|
1057
2239
|
|
|
1058
2240
|
it("should retry uploads", async () => {
|
|
@@ -1117,10 +2299,10 @@ describe("pages", () => {
|
|
|
1117
2299
|
}
|
|
1118
2300
|
|
|
1119
2301
|
expect(std.out).toMatchInlineSnapshot(`
|
|
1120
|
-
|
|
2302
|
+
"✨ Success! Uploaded 1 files (TIMINGS)
|
|
1121
2303
|
|
|
1122
|
-
|
|
1123
|
-
|
|
2304
|
+
✨ Upload complete!"
|
|
2305
|
+
`);
|
|
1124
2306
|
});
|
|
1125
2307
|
|
|
1126
2308
|
it("should try to use multiple buckets (up to the max concurrency)", async () => {
|
|
@@ -1203,10 +2385,10 @@ describe("pages", () => {
|
|
|
1203
2385
|
);
|
|
1204
2386
|
|
|
1205
2387
|
expect(std.out).toMatchInlineSnapshot(`
|
|
1206
|
-
|
|
2388
|
+
"✨ Success! Uploaded 4 files (TIMINGS)
|
|
1207
2389
|
|
|
1208
|
-
|
|
1209
|
-
|
|
2390
|
+
✨ Upload complete!"
|
|
2391
|
+
`);
|
|
1210
2392
|
});
|
|
1211
2393
|
|
|
1212
2394
|
it("should not error when directory names contain periods and houses a extensionless file", async () => {
|