From c9fcdab1a0ad52a680b518121d81f38a4774f69c Mon Sep 17 00:00:00 2001 From: James Date: Sun, 2 Jul 2023 19:07:23 +0100 Subject: [PATCH 1/7] feat: images support via `/_next/image` --- .changeset/lemon-pears-burn.md | 5 + package-lock.json | 925 ++++-------------- package.json | 3 +- packages/next-on-pages/docs/supported.md | 4 +- .../templates/_worker.js/index.ts | 34 +- .../templates/_worker.js/utils/images.ts | 184 ++++ .../templates/_worker.js/utils/index.ts | 1 + .../tests/templates/utils/images.test.ts | 286 ++++++ packages/next-on-pages/vercel.types.d.ts | 11 +- 9 files changed, 682 insertions(+), 771 deletions(-) create mode 100644 .changeset/lemon-pears-burn.md create mode 100644 packages/next-on-pages/templates/_worker.js/utils/images.ts create mode 100644 packages/next-on-pages/tests/templates/utils/images.test.ts diff --git a/.changeset/lemon-pears-burn.md b/.changeset/lemon-pears-burn.md new file mode 100644 index 000000000..5fb45ab55 --- /dev/null +++ b/.changeset/lemon-pears-burn.md @@ -0,0 +1,5 @@ +--- +'@cloudflare/next-on-pages': minor +--- + +Support for images via `/_next/image`, falling back to the raw image URL when image resizing is not available. diff --git a/package-lock.json b/package-lock.json index ec5be1906..52dab569a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "devDependencies": { "@cfpreview/pages-e2e-test-runner-cli": "^0.0.18", "prettier": "^2.8.8", - "turbo": "^1.10.3" + "turbo": "^1.10.3", + "vitest": "^0.32.2" } }, "internal-packages/eslint-config-next-on-pages": { @@ -5265,27 +5266,32 @@ "peer": true }, "node_modules/@vitest/expect": { - "version": "0.29.8", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.29.8.tgz", - "integrity": "sha512-xlcVXn5I5oTq6NiZSY3ykyWixBxr5mG8HYtjvpgg6KaqHm0mvhX18xuwl5YGxIRNt/A5jidd7CWcNHrSvgaQqQ==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.2.tgz", + "integrity": "sha512-6q5yzweLnyEv5Zz1fqK5u5E83LU+gOMVBDuxBl2d2Jfx1BAp5M+rZgc5mlyqdnxquyoiOXpXmFNkcGcfFnFH3Q==", "dev": true, - "peer": true, "dependencies": { - "@vitest/spy": "0.29.8", - "@vitest/utils": "0.29.8", + "@vitest/spy": "0.32.2", + "@vitest/utils": "0.32.2", "chai": "^4.3.7" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "0.29.8", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.29.8.tgz", - "integrity": "sha512-FzdhnRDwEr/A3Oo1jtIk/B952BBvP32n1ObMEb23oEJNO+qO5cBet6M2XWIDQmA7BDKGKvmhUf2naXyp/2JEwQ==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.32.2.tgz", + "integrity": "sha512-06vEL0C1pomOEktGoLjzZw+1Fb+7RBRhmw/06WkDrd1akkT9i12su0ku+R/0QM69dfkIL/rAIDTG+CSuQVDcKw==", "dev": true, - "peer": true, "dependencies": { - "@vitest/utils": "0.29.8", + "@vitest/utils": "0.32.2", + "concordance": "^5.0.4", "p-limit": "^4.0.0", "pathe": "^1.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot": { @@ -5323,13 +5329,15 @@ "dev": true }, "node_modules/@vitest/spy": { - "version": "0.29.8", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.29.8.tgz", - "integrity": "sha512-VdjBe9w34vOMl5I5mYEzNX8inTxrZ+tYUVk9jxaZJmHFwmDFC/GV3KBFTA/JKswr3XHvZL+FE/yq5EVhb6pSAw==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.32.2.tgz", + "integrity": "sha512-Q/ZNILJ4ca/VzQbRM8ur3Si5Sardsh1HofatG9wsJY1RfEaw0XKP8IVax2lI1qnrk9YPuG9LA2LkZ0EI/3d4ug==", "dev": true, - "peer": true, "dependencies": { - "tinyspy": "^1.0.2" + "tinyspy": "^2.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/ui": { @@ -5347,26 +5355,26 @@ } }, "node_modules/@vitest/utils": { - "version": "0.29.8", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.29.8.tgz", - "integrity": "sha512-qGzuf3vrTbnoY+RjjVVIBYfuWMjn3UMUqyQtdGNZ6ZIIyte7B37exj6LaVkrZiUTvzSadVvO/tJm8AEgbGCBPg==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.2.tgz", + "integrity": "sha512-lnJ0T5i03j0IJaeW73hxe2AuVnZ/y1BhhCOuIcl9LIzXnbpXJT9Lrt6brwKHXLOiA7MZ6N5hSJjt0xE1dGNCzQ==", "dev": true, - "peer": true, "dependencies": { - "cli-truncate": "^3.1.0", - "diff": "^5.1.0", + "diff-sequences": "^29.4.3", "loupe": "^2.3.6", "pretty-format": "^27.5.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/utils/node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "node_modules/@vitest/utils/node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", "dev": true, - "peer": true, "engines": { - "node": ">=0.3.1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@vitest/utils/node_modules/pretty-format": { @@ -5374,7 +5382,6 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, - "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -5388,8 +5395,7 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "peer": true + "dev": true }, "node_modules/@web3-storage/multipart-parser": { "version": "1.0.0", @@ -6486,77 +6492,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", - "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", - "dev": true, - "peer": true, - "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "peer": true - }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "peer": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/cli-width": { "version": "3.0.0", "license": "ISC", @@ -7190,13 +7125,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "peer": true - }, "node_modules/edge-runtime": { "version": "2.1.4", "license": "MPL-2.0", @@ -15116,49 +15044,6 @@ "node": ">=8" } }, - "node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/smart-buffer": { "version": "4.2.0", "license": "MIT", @@ -15933,21 +15818,19 @@ "license": "MIT" }, "node_modules/tinypool": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.4.0.tgz", - "integrity": "sha512-2ksntHOKf893wSAH4z/+JbPpi92esw8Gn9N2deXX+B0EO92hexAVI9GIZZPx7P5aYo5KULfeOSt3kMOmSOy6uA==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.5.0.tgz", + "integrity": "sha512-paHQtnrlS1QZYKF/GnLoOM/DN9fqaGOFbCbxzAhwniySnzl9Ebk8w73/dd34DAhe/obUbPAOldTyYXQZxnPBPQ==", "dev": true, - "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/tinyspy": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-1.1.1.tgz", - "integrity": "sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", + "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", "dev": true, - "peer": true, "engines": { "node": ">=14.0.0" } @@ -18094,7 +17977,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=12" } @@ -18110,7 +17992,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=12" } @@ -18126,7 +18007,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=12" } @@ -18141,7 +18021,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=12" } @@ -18157,7 +18036,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=12" } @@ -18173,7 +18051,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=12" } @@ -18189,7 +18066,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=12" } @@ -18205,7 +18081,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=12" } @@ -18221,7 +18096,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=12" } @@ -18237,7 +18111,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=12" } @@ -18253,7 +18126,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=12" } @@ -18269,7 +18141,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=12" } @@ -18285,7 +18156,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=12" } @@ -18301,7 +18171,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=12" } @@ -18317,7 +18186,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=12" } @@ -18333,7 +18201,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=12" } @@ -18349,7 +18216,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=12" } @@ -18365,7 +18231,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=12" } @@ -18381,7 +18246,6 @@ "os": [ "sunos" ], - "peer": true, "engines": { "node": ">=12" } @@ -18397,7 +18261,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=12" } @@ -18413,7 +18276,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=12" } @@ -18429,7 +18291,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=12" } @@ -18470,45 +18331,45 @@ } }, "node_modules/vitest": { - "version": "0.29.8", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.29.8.tgz", - "integrity": "sha512-JIAVi2GK5cvA6awGpH0HvH/gEG9PZ0a/WoxdiV3PmqK+3CjQMf8c+J/Vhv4mdZ2nRyXFw66sAg6qz7VNkaHfDQ==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.32.2.tgz", + "integrity": "sha512-hU8GNNuQfwuQmqTLfiKcqEhZY72Zxb7nnN07koCUNmntNxbKQnVbeIS6sqUgR3eXSlbOpit8+/gr1KpqoMgWCQ==", "dev": true, - "peer": true, "dependencies": { - "@types/chai": "^4.3.4", + "@types/chai": "^4.3.5", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "@vitest/expect": "0.29.8", - "@vitest/runner": "0.29.8", - "@vitest/spy": "0.29.8", - "@vitest/utils": "0.29.8", - "acorn": "^8.8.1", + "@vitest/expect": "0.32.2", + "@vitest/runner": "0.32.2", + "@vitest/snapshot": "0.32.2", + "@vitest/spy": "0.32.2", + "@vitest/utils": "0.32.2", + "acorn": "^8.8.2", "acorn-walk": "^8.2.0", "cac": "^6.7.14", "chai": "^4.3.7", + "concordance": "^5.0.4", "debug": "^4.3.4", - "local-pkg": "^0.4.2", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.0", "pathe": "^1.1.0", "picocolors": "^1.0.0", - "source-map": "^0.6.1", - "std-env": "^3.3.1", - "strip-literal": "^1.0.0", - "tinybench": "^2.3.1", - "tinypool": "^0.4.0", - "tinyspy": "^1.0.2", + "std-env": "^3.3.2", + "strip-literal": "^1.0.1", + "tinybench": "^2.5.0", + "tinypool": "^0.5.0", "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.29.8", + "vite-node": "0.32.2", "why-is-node-running": "^2.2.2" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": ">=v14.16.0" + "node": ">=v14.18.0" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "url": "https://opencollective.com/vitest" }, "peerDependencies": { "@edge-runtime/vm": "*", @@ -18591,15 +18452,14 @@ } }, "node_modules/vitest/node_modules/vite-node": { - "version": "0.29.8", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.29.8.tgz", - "integrity": "sha512-b6OtCXfk65L6SElVM20q5G546yu10/kNrhg08afEoWlFRJXFq9/6glsvSVY+aI6YeC1tu2TtAqI2jHEQmOmsFw==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.32.2.tgz", + "integrity": "sha512-dTQ1DCLwl2aEseov7cfQ+kDMNJpM1ebpyMMMwWzBvLbis8Nla/6c9WQcqpPssTwS6Rp/+U6KwlIj8Eapw4bLdA==", "dev": true, - "peer": true, "dependencies": { "cac": "^6.7.14", "debug": "^4.3.4", - "mlly": "^1.1.0", + "mlly": "^1.2.0", "pathe": "^1.1.0", "picocolors": "^1.0.0", "vite": "^3.0.0 || ^4.0.0" @@ -18608,10 +18468,10 @@ "vite-node": "vite-node.mjs" }, "engines": { - "node": ">=v14.16.0" + "node": ">=v14.18.0" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "url": "https://opencollective.com/vitest" } }, "node_modules/vm2": { @@ -19258,241 +19118,38 @@ "dev": true, "license": "MIT" }, - "packages/next-on-pages/node_modules/@vitest/expect": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.2.tgz", - "integrity": "sha512-6q5yzweLnyEv5Zz1fqK5u5E83LU+gOMVBDuxBl2d2Jfx1BAp5M+rZgc5mlyqdnxquyoiOXpXmFNkcGcfFnFH3Q==", + "packages/next-on-pages/node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "dev": true, - "dependencies": { - "@vitest/spy": "0.32.2", - "@vitest/utils": "0.32.2", - "chai": "^4.3.7" + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=12.20" } - }, - "packages/next-on-pages/node_modules/@vitest/runner": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.32.2.tgz", - "integrity": "sha512-06vEL0C1pomOEktGoLjzZw+1Fb+7RBRhmw/06WkDrd1akkT9i12su0ku+R/0QM69dfkIL/rAIDTG+CSuQVDcKw==", + } + }, + "dependencies": { + "@actions/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", + "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", "dev": true, - "dependencies": { - "@vitest/utils": "0.32.2", - "concordance": "^5.0.4", - "p-limit": "^4.0.0", - "pathe": "^1.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "requires": { + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" } }, - "packages/next-on-pages/node_modules/@vitest/spy": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.32.2.tgz", - "integrity": "sha512-Q/ZNILJ4ca/VzQbRM8ur3Si5Sardsh1HofatG9wsJY1RfEaw0XKP8IVax2lI1qnrk9YPuG9LA2LkZ0EI/3d4ug==", + "@actions/http-client": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz", + "integrity": "sha512-BonhODnXr3amchh4qkmjPMUO8mFi/zLaaCeCAJZqch8iQqyDnVIkySjB38VHAC8IJ+bnlgfOqlhpyCUZHlQsqw==", "dev": true, - "dependencies": { - "tinyspy": "^2.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "packages/next-on-pages/node_modules/@vitest/utils": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.2.tgz", - "integrity": "sha512-lnJ0T5i03j0IJaeW73hxe2AuVnZ/y1BhhCOuIcl9LIzXnbpXJT9Lrt6brwKHXLOiA7MZ6N5hSJjt0xE1dGNCzQ==", - "dev": true, - "dependencies": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^27.5.1" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "packages/next-on-pages/node_modules/diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "packages/next-on-pages/node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "packages/next-on-pages/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "packages/next-on-pages/node_modules/tinypool": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.5.0.tgz", - "integrity": "sha512-paHQtnrlS1QZYKF/GnLoOM/DN9fqaGOFbCbxzAhwniySnzl9Ebk8w73/dd34DAhe/obUbPAOldTyYXQZxnPBPQ==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "packages/next-on-pages/node_modules/tinyspy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", - "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "packages/next-on-pages/node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=12.20" - } - }, - "packages/next-on-pages/node_modules/vite-node": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.32.2.tgz", - "integrity": "sha512-dTQ1DCLwl2aEseov7cfQ+kDMNJpM1ebpyMMMwWzBvLbis8Nla/6c9WQcqpPssTwS6Rp/+U6KwlIj8Eapw4bLdA==", - "dev": true, - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "mlly": "^1.2.0", - "pathe": "^1.1.0", - "picocolors": "^1.0.0", - "vite": "^3.0.0 || ^4.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": ">=v14.18.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "packages/next-on-pages/node_modules/vitest": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.32.2.tgz", - "integrity": "sha512-hU8GNNuQfwuQmqTLfiKcqEhZY72Zxb7nnN07koCUNmntNxbKQnVbeIS6sqUgR3eXSlbOpit8+/gr1KpqoMgWCQ==", - "dev": true, - "dependencies": { - "@types/chai": "^4.3.5", - "@types/chai-subset": "^1.3.3", - "@types/node": "*", - "@vitest/expect": "0.32.2", - "@vitest/runner": "0.32.2", - "@vitest/snapshot": "0.32.2", - "@vitest/spy": "0.32.2", - "@vitest/utils": "0.32.2", - "acorn": "^8.8.2", - "acorn-walk": "^8.2.0", - "cac": "^6.7.14", - "chai": "^4.3.7", - "concordance": "^5.0.4", - "debug": "^4.3.4", - "local-pkg": "^0.4.3", - "magic-string": "^0.30.0", - "pathe": "^1.1.0", - "picocolors": "^1.0.0", - "std-env": "^3.3.2", - "strip-literal": "^1.0.1", - "tinybench": "^2.5.0", - "tinypool": "^0.5.0", - "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.32.2", - "why-is-node-running": "^2.2.2" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": ">=v14.18.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@vitest/browser": "*", - "@vitest/ui": "*", - "happy-dom": "*", - "jsdom": "*", - "playwright": "*", - "safaridriver": "*", - "webdriverio": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - }, - "playwright": { - "optional": true - }, - "safaridriver": { - "optional": true - }, - "webdriverio": { - "optional": true - } - } - } - }, - "dependencies": { - "@actions/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", - "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", - "dev": true, - "requires": { - "@actions/http-client": "^2.0.1", - "uuid": "^8.3.2" - } - }, - "@actions/http-client": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz", - "integrity": "sha512-BonhODnXr3amchh4qkmjPMUO8mFi/zLaaCeCAJZqch8iQqyDnVIkySjB38VHAC8IJ+bnlgfOqlhpyCUZHlQsqw==", - "dev": true, - "requires": { - "tunnel": "^0.0.6" + "requires": { + "tunnel": "^0.0.6" } }, "@ampproject/remapping": { @@ -21090,136 +20747,11 @@ "version": "20.2.5", "dev": true }, - "@vitest/expect": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.2.tgz", - "integrity": "sha512-6q5yzweLnyEv5Zz1fqK5u5E83LU+gOMVBDuxBl2d2Jfx1BAp5M+rZgc5mlyqdnxquyoiOXpXmFNkcGcfFnFH3Q==", - "dev": true, - "requires": { - "@vitest/spy": "0.32.2", - "@vitest/utils": "0.32.2", - "chai": "^4.3.7" - } - }, - "@vitest/runner": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.32.2.tgz", - "integrity": "sha512-06vEL0C1pomOEktGoLjzZw+1Fb+7RBRhmw/06WkDrd1akkT9i12su0ku+R/0QM69dfkIL/rAIDTG+CSuQVDcKw==", - "dev": true, - "requires": { - "@vitest/utils": "0.32.2", - "concordance": "^5.0.4", - "p-limit": "^4.0.0", - "pathe": "^1.1.0" - } - }, - "@vitest/spy": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.32.2.tgz", - "integrity": "sha512-Q/ZNILJ4ca/VzQbRM8ur3Si5Sardsh1HofatG9wsJY1RfEaw0XKP8IVax2lI1qnrk9YPuG9LA2LkZ0EI/3d4ug==", - "dev": true, - "requires": { - "tinyspy": "^2.1.0" - } - }, - "@vitest/utils": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.2.tgz", - "integrity": "sha512-lnJ0T5i03j0IJaeW73hxe2AuVnZ/y1BhhCOuIcl9LIzXnbpXJT9Lrt6brwKHXLOiA7MZ6N5hSJjt0xE1dGNCzQ==", - "dev": true, - "requires": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^27.5.1" - } - }, - "diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true - }, - "pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "tinypool": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.5.0.tgz", - "integrity": "sha512-paHQtnrlS1QZYKF/GnLoOM/DN9fqaGOFbCbxzAhwniySnzl9Ebk8w73/dd34DAhe/obUbPAOldTyYXQZxnPBPQ==", - "dev": true - }, - "tinyspy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", - "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", - "dev": true - }, "typescript": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "dev": true - }, - "vite-node": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.32.2.tgz", - "integrity": "sha512-dTQ1DCLwl2aEseov7cfQ+kDMNJpM1ebpyMMMwWzBvLbis8Nla/6c9WQcqpPssTwS6Rp/+U6KwlIj8Eapw4bLdA==", - "dev": true, - "requires": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "mlly": "^1.2.0", - "pathe": "^1.1.0", - "picocolors": "^1.0.0", - "vite": "^3.0.0 || ^4.0.0" - } - }, - "vitest": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.32.2.tgz", - "integrity": "sha512-hU8GNNuQfwuQmqTLfiKcqEhZY72Zxb7nnN07koCUNmntNxbKQnVbeIS6sqUgR3eXSlbOpit8+/gr1KpqoMgWCQ==", - "dev": true, - "requires": { - "@types/chai": "^4.3.5", - "@types/chai-subset": "^1.3.3", - "@types/node": "*", - "@vitest/expect": "0.32.2", - "@vitest/runner": "0.32.2", - "@vitest/snapshot": "0.32.2", - "@vitest/spy": "0.32.2", - "@vitest/utils": "0.32.2", - "acorn": "^8.8.2", - "acorn-walk": "^8.2.0", - "cac": "^6.7.14", - "chai": "^4.3.7", - "concordance": "^5.0.4", - "debug": "^4.3.4", - "local-pkg": "^0.4.3", - "magic-string": "^0.30.0", - "pathe": "^1.1.0", - "picocolors": "^1.0.0", - "std-env": "^3.3.2", - "strip-literal": "^1.0.1", - "tinybench": "^2.5.0", - "tinypool": "^0.5.0", - "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.32.2", - "why-is-node-running": "^2.2.2" - } } } }, @@ -23015,25 +22547,24 @@ } }, "@vitest/expect": { - "version": "0.29.8", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.29.8.tgz", - "integrity": "sha512-xlcVXn5I5oTq6NiZSY3ykyWixBxr5mG8HYtjvpgg6KaqHm0mvhX18xuwl5YGxIRNt/A5jidd7CWcNHrSvgaQqQ==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.2.tgz", + "integrity": "sha512-6q5yzweLnyEv5Zz1fqK5u5E83LU+gOMVBDuxBl2d2Jfx1BAp5M+rZgc5mlyqdnxquyoiOXpXmFNkcGcfFnFH3Q==", "dev": true, - "peer": true, "requires": { - "@vitest/spy": "0.29.8", - "@vitest/utils": "0.29.8", + "@vitest/spy": "0.32.2", + "@vitest/utils": "0.32.2", "chai": "^4.3.7" } }, "@vitest/runner": { - "version": "0.29.8", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.29.8.tgz", - "integrity": "sha512-FzdhnRDwEr/A3Oo1jtIk/B952BBvP32n1ObMEb23oEJNO+qO5cBet6M2XWIDQmA7BDKGKvmhUf2naXyp/2JEwQ==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.32.2.tgz", + "integrity": "sha512-06vEL0C1pomOEktGoLjzZw+1Fb+7RBRhmw/06WkDrd1akkT9i12su0ku+R/0QM69dfkIL/rAIDTG+CSuQVDcKw==", "dev": true, - "peer": true, "requires": { - "@vitest/utils": "0.29.8", + "@vitest/utils": "0.32.2", + "concordance": "^5.0.4", "p-limit": "^4.0.0", "pathe": "^1.1.0" } @@ -23069,13 +22600,12 @@ } }, "@vitest/spy": { - "version": "0.29.8", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.29.8.tgz", - "integrity": "sha512-VdjBe9w34vOMl5I5mYEzNX8inTxrZ+tYUVk9jxaZJmHFwmDFC/GV3KBFTA/JKswr3XHvZL+FE/yq5EVhb6pSAw==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.32.2.tgz", + "integrity": "sha512-Q/ZNILJ4ca/VzQbRM8ur3Si5Sardsh1HofatG9wsJY1RfEaw0XKP8IVax2lI1qnrk9YPuG9LA2LkZ0EI/3d4ug==", "dev": true, - "peer": true, "requires": { - "tinyspy": "^1.0.2" + "tinyspy": "^2.1.0" } }, "@vitest/ui": { @@ -23093,31 +22623,27 @@ } }, "@vitest/utils": { - "version": "0.29.8", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.29.8.tgz", - "integrity": "sha512-qGzuf3vrTbnoY+RjjVVIBYfuWMjn3UMUqyQtdGNZ6ZIIyte7B37exj6LaVkrZiUTvzSadVvO/tJm8AEgbGCBPg==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.2.tgz", + "integrity": "sha512-lnJ0T5i03j0IJaeW73hxe2AuVnZ/y1BhhCOuIcl9LIzXnbpXJT9Lrt6brwKHXLOiA7MZ6N5hSJjt0xE1dGNCzQ==", "dev": true, - "peer": true, "requires": { - "cli-truncate": "^3.1.0", - "diff": "^5.1.0", + "diff-sequences": "^29.4.3", "loupe": "^2.3.6", "pretty-format": "^27.5.1" }, "dependencies": { - "diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "dev": true, - "peer": true + "diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true }, "pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, - "peer": true, "requires": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -23128,8 +22654,7 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "peer": true + "dev": true } } }, @@ -23803,55 +23328,6 @@ "version": "2.9.0", "peer": true }, - "cli-truncate": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", - "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", - "dev": true, - "peer": true, - "requires": { - "slice-ansi": "^5.0.0", - "string-width": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "peer": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "peer": true - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "peer": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "peer": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } - } - }, "cli-width": { "version": "3.0.0", "peer": true @@ -24250,13 +23726,6 @@ } } }, - "eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "peer": true - }, "edge-runtime": { "version": "2.1.4", "peer": true, @@ -29156,33 +28625,6 @@ "slash": { "version": "3.0.0" }, - "slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", - "dev": true, - "peer": true, - "requires": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "peer": true - }, - "is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, - "peer": true - } - } - }, "smart-buffer": { "version": "4.2.0", "peer": true @@ -29727,18 +29169,16 @@ "dev": true }, "tinypool": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.4.0.tgz", - "integrity": "sha512-2ksntHOKf893wSAH4z/+JbPpi92esw8Gn9N2deXX+B0EO92hexAVI9GIZZPx7P5aYo5KULfeOSt3kMOmSOy6uA==", - "dev": true, - "peer": true + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.5.0.tgz", + "integrity": "sha512-paHQtnrlS1QZYKF/GnLoOM/DN9fqaGOFbCbxzAhwniySnzl9Ebk8w73/dd34DAhe/obUbPAOldTyYXQZxnPBPQ==", + "dev": true }, "tinyspy": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-1.1.1.tgz", - "integrity": "sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==", - "dev": true, - "peer": true + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", + "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", + "dev": true }, "tmp": { "version": "0.0.33", @@ -30923,153 +30363,131 @@ "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/android-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/android-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/darwin-arm64": { "version": "0.17.19", - "optional": true, - "peer": true + "optional": true }, "@esbuild/darwin-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/freebsd-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/freebsd-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/linux-arm": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/linux-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/linux-ia32": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/linux-loong64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/linux-mips64el": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/linux-ppc64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/linux-riscv64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/linux-s390x": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/linux-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/netbsd-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/openbsd-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/sunos-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/win32-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/win32-ia32": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", - "optional": true, - "peer": true + "optional": true }, "@esbuild/win32-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", - "optional": true, - "peer": true + "optional": true }, "esbuild": { "version": "0.17.19", @@ -31125,48 +30543,47 @@ } }, "vitest": { - "version": "0.29.8", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.29.8.tgz", - "integrity": "sha512-JIAVi2GK5cvA6awGpH0HvH/gEG9PZ0a/WoxdiV3PmqK+3CjQMf8c+J/Vhv4mdZ2nRyXFw66sAg6qz7VNkaHfDQ==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.32.2.tgz", + "integrity": "sha512-hU8GNNuQfwuQmqTLfiKcqEhZY72Zxb7nnN07koCUNmntNxbKQnVbeIS6sqUgR3eXSlbOpit8+/gr1KpqoMgWCQ==", "dev": true, - "peer": true, "requires": { - "@types/chai": "^4.3.4", + "@types/chai": "^4.3.5", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "@vitest/expect": "0.29.8", - "@vitest/runner": "0.29.8", - "@vitest/spy": "0.29.8", - "@vitest/utils": "0.29.8", - "acorn": "^8.8.1", + "@vitest/expect": "0.32.2", + "@vitest/runner": "0.32.2", + "@vitest/snapshot": "0.32.2", + "@vitest/spy": "0.32.2", + "@vitest/utils": "0.32.2", + "acorn": "^8.8.2", "acorn-walk": "^8.2.0", "cac": "^6.7.14", "chai": "^4.3.7", + "concordance": "^5.0.4", "debug": "^4.3.4", - "local-pkg": "^0.4.2", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.0", "pathe": "^1.1.0", "picocolors": "^1.0.0", - "source-map": "^0.6.1", - "std-env": "^3.3.1", - "strip-literal": "^1.0.0", - "tinybench": "^2.3.1", - "tinypool": "^0.4.0", - "tinyspy": "^1.0.2", + "std-env": "^3.3.2", + "strip-literal": "^1.0.1", + "tinybench": "^2.5.0", + "tinypool": "^0.5.0", "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.29.8", + "vite-node": "0.32.2", "why-is-node-running": "^2.2.2" }, "dependencies": { "vite-node": { - "version": "0.29.8", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.29.8.tgz", - "integrity": "sha512-b6OtCXfk65L6SElVM20q5G546yu10/kNrhg08afEoWlFRJXFq9/6glsvSVY+aI6YeC1tu2TtAqI2jHEQmOmsFw==", + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.32.2.tgz", + "integrity": "sha512-dTQ1DCLwl2aEseov7cfQ+kDMNJpM1ebpyMMMwWzBvLbis8Nla/6c9WQcqpPssTwS6Rp/+U6KwlIj8Eapw4bLdA==", "dev": true, - "peer": true, "requires": { "cac": "^6.7.14", "debug": "^4.3.4", - "mlly": "^1.1.0", + "mlly": "^1.2.0", "pathe": "^1.1.0", "picocolors": "^1.0.0", "vite": "^3.0.0 || ^4.0.0" diff --git a/package.json b/package.json index 8d395d7ec..105766999 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "devDependencies": { "@cfpreview/pages-e2e-test-runner-cli": "^0.0.18", "prettier": "^2.8.8", - "turbo": "^1.10.3" + "turbo": "^1.10.3", + "vitest": "^0.32.2" }, "prettier": { "printWidth": 80, diff --git a/packages/next-on-pages/docs/supported.md b/packages/next-on-pages/docs/supported.md index 05beb842b..763d33c9a 100644 --- a/packages/next-on-pages/docs/supported.md +++ b/packages/next-on-pages/docs/supported.md @@ -49,7 +49,7 @@ If you're application is using a package which relies on unsupported Node.js API | routes `missing` | ✅ | | routes `locale` | ✅ | | routes `middlewarePath` | ✅ | -| images1 | 🔄 | +| images1 | ✅ | | wildcard | ✅ | | overrides | ✅ | | cache | ❌ | @@ -59,7 +59,7 @@ If you're application is using a package which relies on unsupported Node.js API - 🔄: Not currently supported, but it's probably possible and we may add support in the future - ❌: Not supported and unlikely to be supported in the future -- _1_ - **images**: If you want to use `next/image`, you can provide your own [custom loader](https://nextjs.org/docs/api-reference/next/image#loader) and use Cloudflare Image Resizing, as per [Cloudflare's Image Resizing documentation](https://developers.cloudflare.com/images/image-resizing/integration-with-frameworks/#nextjs). +- _1_ - **images**: If you want to use `next/image`, there are two options; allow the library to take care of incoming requests, or using a custom loader. Requests are intercepted in the router and image resizing is attempted to be used - if image resizing is not available, it falls back to fetching the normal image URL. Alternatively, you can provide your own [custom loader](https://nextjs.org/docs/api-reference/next/image#loader) and use Cloudflare Image Resizing, as per [Cloudflare's Image Resizing documentation](https://developers.cloudflare.com/images/image-resizing/integration-with-frameworks/#nextjs). ### next.config.js Properties diff --git a/packages/next-on-pages/templates/_worker.js/index.ts b/packages/next-on-pages/templates/_worker.js/index.ts index 4996889c7..a45e5cb72 100644 --- a/packages/next-on-pages/templates/_worker.js/index.ts +++ b/packages/next-on-pages/templates/_worker.js/index.ts @@ -1,5 +1,5 @@ import { handleRequest } from './handleRequest'; -import { adjustRequestForVercel } from './utils'; +import { adjustRequestForVercel, imageResizing } from './utils'; import type { AsyncLocalStorage } from 'node:async_hooks'; declare const __NODE_ENV__: string; @@ -19,18 +19,26 @@ export default { { status: 503 } ); } - return envAsyncLocalStorage.run({ ...env, NODE_ENV: __NODE_ENV__ }, () => { - const adjustedRequest = adjustRequestForVercel(request); + return envAsyncLocalStorage.run( + { ...env, NODE_ENV: __NODE_ENV__ }, + async () => { + const url = new URL(request.url); + if (url.pathname.startsWith('/_next/image')) { + return imageResizing(request, url, __CONFIG__.images); + } - return handleRequest( - { - request: adjustedRequest, - ctx, - assetsFetcher: env.ASSETS, - }, - __CONFIG__, - __BUILD_OUTPUT__ - ); - }); + const adjustedRequest = adjustRequestForVercel(request); + + return handleRequest( + { + request: adjustedRequest, + ctx, + assetsFetcher: env.ASSETS, + }, + __CONFIG__, + __BUILD_OUTPUT__ + ); + } + ); }, } as ExportedHandler<{ ASSETS: Fetcher }>; diff --git a/packages/next-on-pages/templates/_worker.js/utils/images.ts b/packages/next-on-pages/templates/_worker.js/utils/images.ts new file mode 100644 index 000000000..b9617ee69 --- /dev/null +++ b/packages/next-on-pages/templates/_worker.js/utils/images.ts @@ -0,0 +1,184 @@ +/** + * Checks whether the given URL matches the given remote pattern from the Vercel build output + * images configuration. + * + * https://vercel.com/docs/build-output-api/v3/configuration#images + * + * @param url URL to check. + * @param pattern Remote pattern to match against. + * @returns Whether the URL matches the remote pattern. + */ +export function isRemotePatternMatch( + url: URL, + { protocol, hostname, port, pathname }: VercelImageRemotePattern +): boolean { + // Protocol must match if defined. + if (protocol && url.protocol.replace(/:$/, '') !== protocol) return false; + // Hostname must match regexp. + if (!new RegExp(hostname).test(url.hostname)) return false; + // Port must match regexp if defined. + if (port && !new RegExp(port).test(url.port)) return false; + // Pathname must match regexp if defined. + if (pathname && !new RegExp(pathname).test(url.pathname)) return false; + // All checks passed. + return true; +} + +type ResizingProperties = { + imageUrl: URL; + options: RequestInitCfPropertiesImage; +}; + +/** + * Derives the properties to use for image resizing from the incoming request, respecting the + * images configuration spec from the Vercel build output config. + * + * https://vercel.com/docs/build-output-api/v3/configuration#images + * + * @param request Incoming request. + * @param requestUrl Incoming request's URL. + * @param config Images configuration from the Vercel build output. + * @returns Resizing properties if the request is valid, otherwise undefined. + */ +export function getResizingProperties( + request: Request, + requestUrl: URL, + config?: VercelImagesConfig +): ResizingProperties | undefined { + if (request.method !== 'GET') return undefined; + + const { searchParams } = requestUrl; + + const rawUrl = searchParams.get('url'); + const width = Number.parseInt(searchParams.get('w') ?? '', 10); + const quality = Number.parseInt(searchParams.get('q') ?? '75', 10); + + if (!rawUrl || Number.isNaN(width) || Number.isNaN(quality)) return undefined; + if (!config?.sizes?.includes(width)) return undefined; + if (quality < 0 || quality > 100) return undefined; + + const url = new URL(rawUrl, requestUrl.origin); + + // SVGs must be allowed by the config. + if (url.pathname.endsWith('.svg') && !config?.dangerouslyAllowSVG) { + return undefined; + } + + if ( + // Relative URL means same origin as deployment and is allowed. + !(rawUrl.startsWith('/') || rawUrl.startsWith('%2F')) && + // External image URL must be allowed by domains or remote patterns. + !config?.domains?.includes(url.hostname) && + !config?.remotePatterns?.find(pattern => isRemotePatternMatch(url, pattern)) + ) { + return undefined; + } + + const acceptHeader = request.headers.get('Accept') ?? ''; + const format = config?.formats + ?.find(format => acceptHeader.includes(format)) + ?.replace('image/', '') as VercelImageFormatWithoutPrefix; + + return { + imageUrl: url, + options: { width, quality, format }, + }; +} + +/** + * Builds an URL to the Cloudflare CDN image resizing endpoint. + * + * @param requestUrl Incoming request's URL. + * @param imageUrl Image URL to resize. + * @param properties Image resizing properties. + * @returns URL to the Cloudflare CDN image resizing endpoint. + */ +export function buildCdnCgiImageUrl( + requestUrl: URL, + imageUrl: URL, + { width, quality, format }: RequestInitCfPropertiesImage +): string { + const opts = []; + + if (width) opts.push(`width=${width}`); + if (quality) opts.push(`quality=${quality}`); + if (format) opts.push(`format=${format}`); + + const imageHref = + requestUrl.origin === imageUrl.origin + ? imageUrl.pathname.slice(1) + : imageUrl.href; + + return `${requestUrl.origin}/cdn-cgi/image/${opts.join(',')}/${imageHref}`; +} + +/** + * Formats the given response to match the images configuration spec from the Vercel build output + * config. + * + * Applies headers for `Content-Security-Policy` and `Content-Disposition`, if defined in the config. + * + * https://vercel.com/docs/build-output-api/v3/configuration#images + * + * @param resp Response to format. + * @param imageUrl Image URL that was resized. + * @param config Images configuration from the Vercel build output. + * @returns Formatted response. + */ +export function formatResp( + resp: Response, + imageUrl: URL, + config?: VercelImagesConfig +): Response { + const newHeaders = new Headers(resp.headers); + + if (config?.contentSecurityPolicy) { + newHeaders.set('Content-Security-Policy', config.contentSecurityPolicy); + } + + if (config?.contentDispositionType) { + const fileName = imageUrl.pathname.split('/').pop(); + const contentDisposition = fileName + ? `${config.contentDispositionType}; filename="${fileName}"` + : config.contentDispositionType; + + newHeaders.set('Content-Disposition', contentDisposition); + } + + return new Response(resp.body, { headers: newHeaders }); +} + +/** + * Handles image resizing requests. + * + * @param request Incoming request. + * @param requestUrl Incoming request's URL. + * @param config Images configuration from the Vercel build output. + * @returns Resized image response if the request is valid, otherwise a 400 response. + */ +export async function imageResizing( + request: Request, + requestUrl: URL, + config?: VercelImagesConfig +): Promise { + const opts = getResizingProperties(request, requestUrl, config); + + if (!opts) { + return new Response('Invalid image resizing request', { status: 400 }); + } + + const { imageUrl } = opts; + + // NOTE: Pages does not support the RequestInit image resizing yet. + // const imageReq = new Request(imageUrl, { headers: request.headers }); + // const imageResp = await fetch(imageReq, { cf: { image: options } }); + // if (imageResp.status === 200) return formatResp(imageResp, imageUrl, config); + + // NOTE: Pages also doens't seem to support calling the `/cdn-cgi/image` endpoint either. + // const cdnCgiImageUrl = buildCdnCgiImageUrl(requestUrl, imageUrl, options); + // const cdnCgiResp = await fetch(cdnCgiImageUrl, { headers: request.headers }); + // if (cdnCgiResp.status === 200) return formatResp(cdnCgiResp, imageUrl, config); + + const imageResp = await fetch(imageUrl, { headers: request.headers }); + return formatResp(imageResp, imageUrl, config); +} diff --git a/packages/next-on-pages/templates/_worker.js/utils/index.ts b/packages/next-on-pages/templates/_worker.js/utils/index.ts index 16e3bdf04..df2a0ff3f 100644 --- a/packages/next-on-pages/templates/_worker.js/utils/index.ts +++ b/packages/next-on-pages/templates/_worker.js/utils/index.ts @@ -3,3 +3,4 @@ export * from './request'; export * from './http'; export * from './pcre'; export * from './routing'; +export * from './images'; diff --git a/packages/next-on-pages/tests/templates/utils/images.test.ts b/packages/next-on-pages/tests/templates/utils/images.test.ts new file mode 100644 index 000000000..05b7ee7bb --- /dev/null +++ b/packages/next-on-pages/tests/templates/utils/images.test.ts @@ -0,0 +1,286 @@ +import { describe, expect, test } from 'vitest'; +import { + buildCdnCgiImageUrl, + formatResp, + getResizingProperties, + isRemotePatternMatch, +} from '../../../templates/_worker.js/utils'; + +describe('isRemotePatternMatch', () => { + test('hostname matches correctly', () => { + const config: VercelImageRemotePattern = { + hostname: '^via\\.placeholder\\.com$', + }; + + const validUrl = new URL('https://via.placeholder.com/images/1.jpg'); + expect(isRemotePatternMatch(validUrl, config)).toEqual(true); + + const invalidUrl = new URL('https://example.com/images/1.jpg'); + expect(isRemotePatternMatch(invalidUrl, config)).toEqual(false); + }); + + test('protocol matches correctly', () => { + const config: VercelImageRemotePattern = { + protocol: 'https', + hostname: '^via\\.placeholder\\.com$', + }; + + const validUrl = new URL('https://via.placeholder.com/images/1.jpg'); + expect(isRemotePatternMatch(validUrl, config)).toEqual(true); + + const invalidUrl = new URL('http://via.placeholder.com/images/1.jpg'); + expect(isRemotePatternMatch(invalidUrl, config)).toEqual(false); + }); + + test('port matches correctly', () => { + const config: VercelImageRemotePattern = { + hostname: '^via\\.placeholder\\.com$', + port: '9000', + }; + + const validUrl = new URL('https://via.placeholder.com:9000/images/1.jpg'); + expect(isRemotePatternMatch(validUrl, config)).toEqual(true); + + const invalidUrl = new URL('http://via.placeholder.com/images/1.jpg'); + expect(isRemotePatternMatch(invalidUrl, config)).toEqual(false); + }); + + test('pathname matches correctly', () => { + const config: VercelImageRemotePattern = { + hostname: '^via\\.placeholder\\.com$', + pathname: '^/images/.*$', + }; + + const validUrl = new URL('https://via.placeholder.com:9000/images/1.jpg'); + expect(isRemotePatternMatch(validUrl, config)).toEqual(true); + + const invalidUrl = new URL('http://via.placeholder.com/videos/1.mp4'); + expect(isRemotePatternMatch(invalidUrl, config)).toEqual(false); + }); +}); + +const baseUrl = 'https://localhost/_next/image?url='; +const baseValidUrl = `${baseUrl}%2Fimages%2F1.jpg`; +const baseConfig: VercelImagesConfig = { + domains: ['example.com'], + sizes: [640, 750, 828, 1080, 1200], + remotePatterns: [{ hostname: '^via\\.placeholder\\.com$' }], + formats: ['image/avif', 'image/webp'], +}; + +describe('getResizingProperties', () => { + test('invalid method fails', () => { + const url = new URL(baseValidUrl); + const request = new Request(url, { method: 'POST' }); + + expect(getResizingProperties(request, url)).toEqual(undefined); + }); + + describe('request search params', () => { + test('invalid url fails', () => { + const url = new URL(baseUrl); + const req = new Request(url); + + expect(getResizingProperties(req, url)).toEqual(undefined); + }); + + test('invalid width fails', () => { + const url = new URL(`${baseValidUrl}&w=abc`); + const req = new Request(url); + + expect(getResizingProperties(req, url)).toEqual(undefined); + }); + + test('invalid quality fails', () => { + const url = new URL(`${baseValidUrl}&w=100&q=abc`); + const req = new Request(url); + + expect(getResizingProperties(req, url)).toEqual(undefined); + }); + + test('invalid width in images config fails', () => { + const url = new URL(`${baseValidUrl}&w=100`); + const req = new Request(url); + + expect(getResizingProperties(req, url, baseConfig)).toEqual(undefined); + }); + + test('invalid quality (>100) fails', () => { + const url = new URL(`${baseValidUrl}&w=640&q=150`); + const req = new Request(url); + + expect(getResizingProperties(req, url, baseConfig)).toEqual(undefined); + }); + + test('invalid quality (<0) fails', () => { + const url = new URL(`${baseValidUrl}&w=640&q=-1`); + const req = new Request(url); + + expect(getResizingProperties(req, url, baseConfig)).toEqual(undefined); + }); + }); + + describe('relative (same origin) image', () => { + test('image with valid request options succeeds', () => { + const url = new URL(`${baseValidUrl}&w=640`); + const req = new Request(url); + + const result = getResizingProperties(req, url, baseConfig); + expect(result).toEqual({ + imageUrl: new URL('https://localhost/images/1.jpg'), + options: { format: undefined, width: 640, quality: 75 }, + }); + }); + + test('svg image fails when config disallows svgs', () => { + const url = new URL(`${baseValidUrl.replace('jpg', 'svg')}&w=640`); + const req = new Request(url); + const config = { ...baseConfig, dangerouslyAllowSVG: false }; + + expect(getResizingProperties(req, url, config)).toEqual(undefined); + }); + + test('svg image succeeds when config allows svgs', () => { + const url = new URL(`${baseValidUrl.replace('jpg', 'svg')}&w=640`); + const req = new Request(url); + const config = { ...baseConfig, dangerouslyAllowSVG: true }; + + const result = getResizingProperties(req, url, config); + expect(result).toEqual({ + imageUrl: new URL('https://localhost/images/1.svg'), + options: { format: undefined, width: 640, quality: 75 }, + }); + }); + + test('svg image succeeds when config allows them', () => { + const url = new URL(`${baseValidUrl.replace('jpg', 'svg')}&w=640`); + const req = new Request(url); + const config = { ...baseConfig, dangerouslyAllowSVG: true }; + + const result = getResizingProperties(req, url, config); + expect(result).toEqual({ + imageUrl: new URL('https://localhost/images/1.svg'), + options: { format: undefined, width: 640, quality: 75 }, + }); + }); + }); + + describe('external image', () => { + test('external image fails with disallowed domain', () => { + const url = new URL( + `${baseUrl}https%3A%2F%2Finvalid.com%2Fimage.jpg&w=640` + ); + const req = new Request(url); + + expect(getResizingProperties(req, url, baseConfig)).toEqual(undefined); + }); + + test('external image succeeds with allowed domain', () => { + const url = new URL( + `${baseUrl}https%3A%2F%2Fexample.com%2Fimage.jpg&w=640` + ); + const req = new Request(url); + + const result = getResizingProperties(req, url, baseConfig); + expect(result).toEqual({ + imageUrl: new URL('https://example.com/image.jpg'), + options: { format: undefined, width: 640, quality: 75 }, + }); + }); + + test('external image suceeds with allowed remote pattern', () => { + const url = new URL( + `${baseUrl}https%3A%2F%2Fvia.placeholder.com%2Fimage.jpg&w=640` + ); + const req = new Request(url); + + const result = getResizingProperties(req, url, baseConfig); + expect(result).toEqual({ + imageUrl: new URL('https://via.placeholder.com/image.jpg'), + options: { format: undefined, width: 640, quality: 75 }, + }); + }); + }); + + describe('request headers', () => { + test('return correct format for `accept` header (webp)', () => { + const url = new URL(`${baseValidUrl}&w=640`); + const req = new Request(url, { headers: { Accept: 'image/webp' } }); + + const result = getResizingProperties(req, url, baseConfig); + expect(result).toEqual({ + imageUrl: new URL('https://localhost/images/1.jpg'), + options: { format: 'webp', width: 640, quality: 75 }, + }); + }); + + test('return correct format for `accept` header (avif)', () => { + const url = new URL(`${baseValidUrl}&w=640`); + const req = new Request(url, { + headers: { Accept: 'image/avif,image/webp' }, + }); + + const result = getResizingProperties(req, url, baseConfig); + expect(result).toEqual({ + imageUrl: new URL('https://localhost/images/1.jpg'), + options: { format: 'avif', width: 640, quality: 75 }, + }); + }); + }); +}); + +describe('buildCdnCgiImageUrl', () => { + test('builds a valid URL for relative images', () => { + const requestUrl = new URL(`${baseValidUrl}&w=640`); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const { imageUrl, options } = getResizingProperties( + new Request(requestUrl), + requestUrl, + baseConfig + )!; + + const result = buildCdnCgiImageUrl(requestUrl, imageUrl, options); + expect(result).toEqual( + 'https://localhost/cdn-cgi/image/width=640,quality=75/images/1.jpg' + ); + }); + + test('builds a valid URL for external images', () => { + const requestUrl = new URL( + `${baseUrl}https%3A%2F%2Fexample.com%2Fimage.jpg&w=640` + ); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const { imageUrl, options } = getResizingProperties( + new Request(requestUrl), + requestUrl, + baseConfig + )!; + + const result = buildCdnCgiImageUrl(requestUrl, imageUrl, options); + expect(result).toEqual( + 'https://localhost/cdn-cgi/image/width=640,quality=75/https://example.com/image.jpg' + ); + }); +}); + +describe('formatResp', () => { + test('applies content security policy from the config', () => { + const config = { ...baseConfig, contentSecurityPolicy: 'default-src' }; + const imageUrl = new URL('https://localhost/images/1.jpg'); + + const newResp = formatResp(new Response(), imageUrl, config); + expect(newResp.headers.get('Content-Security-Policy')).toEqual( + 'default-src' + ); + }); + + test('applies content disposition from the config', () => { + const config = { ...baseConfig, contentDispositionType: 'inline' }; + const imageUrl = new URL('https://localhost/images/1.jpg'); + + const newResp = formatResp(new Response(), imageUrl, config); + expect(newResp.headers.get('Content-Disposition')).toEqual( + 'inline; filename="1.jpg"' + ); + }); +}); diff --git a/packages/next-on-pages/vercel.types.d.ts b/packages/next-on-pages/vercel.types.d.ts index 0cf48d6df..4433d8ab6 100644 --- a/packages/next-on-pages/vercel.types.d.ts +++ b/packages/next-on-pages/vercel.types.d.ts @@ -85,11 +85,20 @@ type VercelHandler = { }; type VercelImageFormat = 'image/avif' | 'image/webp'; +type VercelImageFormatWithoutPrefix = StripPrefix; +type StripPrefix = T extends `${K}${infer V}` ? V : T; + +type VercelImageRemotePattern = { + protocol?: 'http' | 'https'; + hostname: string; + port?: string; + pathname?: string; +}; type VercelImagesConfig = { sizes: number[]; domains: string[]; - remotePatterns?: string[]; + remotePatterns?: VercelImageRemotePattern[]; minimumCacheTTL?: number; // seconds formats?: VercelImageFormat[]; dangerouslyAllowSVG?: boolean; From 38cf8219a3bbb3f40b040aebf16d0480d9a6fe18 Mon Sep 17 00:00:00 2001 From: James Date: Sun, 2 Jul 2023 19:16:32 +0100 Subject: [PATCH 2/7] undo deps change --- package-lock.json | 933 +++++++++++++++++++++++++++++++++++++--------- package.json | 3 +- 2 files changed, 759 insertions(+), 177 deletions(-) diff --git a/package-lock.json b/package-lock.json index 52dab569a..ec5be1906 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,8 +13,7 @@ "devDependencies": { "@cfpreview/pages-e2e-test-runner-cli": "^0.0.18", "prettier": "^2.8.8", - "turbo": "^1.10.3", - "vitest": "^0.32.2" + "turbo": "^1.10.3" } }, "internal-packages/eslint-config-next-on-pages": { @@ -5266,32 +5265,27 @@ "peer": true }, "node_modules/@vitest/expect": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.2.tgz", - "integrity": "sha512-6q5yzweLnyEv5Zz1fqK5u5E83LU+gOMVBDuxBl2d2Jfx1BAp5M+rZgc5mlyqdnxquyoiOXpXmFNkcGcfFnFH3Q==", + "version": "0.29.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.29.8.tgz", + "integrity": "sha512-xlcVXn5I5oTq6NiZSY3ykyWixBxr5mG8HYtjvpgg6KaqHm0mvhX18xuwl5YGxIRNt/A5jidd7CWcNHrSvgaQqQ==", "dev": true, + "peer": true, "dependencies": { - "@vitest/spy": "0.32.2", - "@vitest/utils": "0.32.2", + "@vitest/spy": "0.29.8", + "@vitest/utils": "0.29.8", "chai": "^4.3.7" - }, - "funding": { - "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.32.2.tgz", - "integrity": "sha512-06vEL0C1pomOEktGoLjzZw+1Fb+7RBRhmw/06WkDrd1akkT9i12su0ku+R/0QM69dfkIL/rAIDTG+CSuQVDcKw==", + "version": "0.29.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.29.8.tgz", + "integrity": "sha512-FzdhnRDwEr/A3Oo1jtIk/B952BBvP32n1ObMEb23oEJNO+qO5cBet6M2XWIDQmA7BDKGKvmhUf2naXyp/2JEwQ==", "dev": true, + "peer": true, "dependencies": { - "@vitest/utils": "0.32.2", - "concordance": "^5.0.4", + "@vitest/utils": "0.29.8", "p-limit": "^4.0.0", "pathe": "^1.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot": { @@ -5329,15 +5323,13 @@ "dev": true }, "node_modules/@vitest/spy": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.32.2.tgz", - "integrity": "sha512-Q/ZNILJ4ca/VzQbRM8ur3Si5Sardsh1HofatG9wsJY1RfEaw0XKP8IVax2lI1qnrk9YPuG9LA2LkZ0EI/3d4ug==", + "version": "0.29.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.29.8.tgz", + "integrity": "sha512-VdjBe9w34vOMl5I5mYEzNX8inTxrZ+tYUVk9jxaZJmHFwmDFC/GV3KBFTA/JKswr3XHvZL+FE/yq5EVhb6pSAw==", "dev": true, + "peer": true, "dependencies": { - "tinyspy": "^2.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "tinyspy": "^1.0.2" } }, "node_modules/@vitest/ui": { @@ -5355,26 +5347,26 @@ } }, "node_modules/@vitest/utils": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.2.tgz", - "integrity": "sha512-lnJ0T5i03j0IJaeW73hxe2AuVnZ/y1BhhCOuIcl9LIzXnbpXJT9Lrt6brwKHXLOiA7MZ6N5hSJjt0xE1dGNCzQ==", + "version": "0.29.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.29.8.tgz", + "integrity": "sha512-qGzuf3vrTbnoY+RjjVVIBYfuWMjn3UMUqyQtdGNZ6ZIIyte7B37exj6LaVkrZiUTvzSadVvO/tJm8AEgbGCBPg==", "dev": true, + "peer": true, "dependencies": { - "diff-sequences": "^29.4.3", + "cli-truncate": "^3.1.0", + "diff": "^5.1.0", "loupe": "^2.3.6", "pretty-format": "^27.5.1" - }, - "funding": { - "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/utils/node_modules/diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "node_modules/@vitest/utils/node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", "dev": true, + "peer": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=0.3.1" } }, "node_modules/@vitest/utils/node_modules/pretty-format": { @@ -5382,6 +5374,7 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, + "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -5395,7 +5388,8 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@web3-storage/multipart-parser": { "version": "1.0.0", @@ -6492,6 +6486,77 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "peer": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "peer": true + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "peer": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/cli-width": { "version": "3.0.0", "license": "ISC", @@ -7125,6 +7190,13 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "peer": true + }, "node_modules/edge-runtime": { "version": "2.1.4", "license": "MPL-2.0", @@ -15044,6 +15116,49 @@ "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/smart-buffer": { "version": "4.2.0", "license": "MIT", @@ -15818,19 +15933,21 @@ "license": "MIT" }, "node_modules/tinypool": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.5.0.tgz", - "integrity": "sha512-paHQtnrlS1QZYKF/GnLoOM/DN9fqaGOFbCbxzAhwniySnzl9Ebk8w73/dd34DAhe/obUbPAOldTyYXQZxnPBPQ==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.4.0.tgz", + "integrity": "sha512-2ksntHOKf893wSAH4z/+JbPpi92esw8Gn9N2deXX+B0EO92hexAVI9GIZZPx7P5aYo5KULfeOSt3kMOmSOy6uA==", "dev": true, + "peer": true, "engines": { "node": ">=14.0.0" } }, "node_modules/tinyspy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", - "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-1.1.1.tgz", + "integrity": "sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==", "dev": true, + "peer": true, "engines": { "node": ">=14.0.0" } @@ -17977,6 +18094,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=12" } @@ -17992,6 +18110,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=12" } @@ -18007,6 +18126,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=12" } @@ -18021,6 +18141,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=12" } @@ -18036,6 +18157,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=12" } @@ -18051,6 +18173,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=12" } @@ -18066,6 +18189,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=12" } @@ -18081,6 +18205,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -18096,6 +18221,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -18111,6 +18237,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -18126,6 +18253,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -18141,6 +18269,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -18156,6 +18285,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -18171,6 +18301,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -18186,6 +18317,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -18201,6 +18333,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -18216,6 +18349,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=12" } @@ -18231,6 +18365,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=12" } @@ -18246,6 +18381,7 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=12" } @@ -18261,6 +18397,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=12" } @@ -18276,6 +18413,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=12" } @@ -18291,6 +18429,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=12" } @@ -18331,45 +18470,45 @@ } }, "node_modules/vitest": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.32.2.tgz", - "integrity": "sha512-hU8GNNuQfwuQmqTLfiKcqEhZY72Zxb7nnN07koCUNmntNxbKQnVbeIS6sqUgR3eXSlbOpit8+/gr1KpqoMgWCQ==", + "version": "0.29.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.29.8.tgz", + "integrity": "sha512-JIAVi2GK5cvA6awGpH0HvH/gEG9PZ0a/WoxdiV3PmqK+3CjQMf8c+J/Vhv4mdZ2nRyXFw66sAg6qz7VNkaHfDQ==", "dev": true, + "peer": true, "dependencies": { - "@types/chai": "^4.3.5", + "@types/chai": "^4.3.4", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "@vitest/expect": "0.32.2", - "@vitest/runner": "0.32.2", - "@vitest/snapshot": "0.32.2", - "@vitest/spy": "0.32.2", - "@vitest/utils": "0.32.2", - "acorn": "^8.8.2", + "@vitest/expect": "0.29.8", + "@vitest/runner": "0.29.8", + "@vitest/spy": "0.29.8", + "@vitest/utils": "0.29.8", + "acorn": "^8.8.1", "acorn-walk": "^8.2.0", "cac": "^6.7.14", "chai": "^4.3.7", - "concordance": "^5.0.4", "debug": "^4.3.4", - "local-pkg": "^0.4.3", - "magic-string": "^0.30.0", + "local-pkg": "^0.4.2", "pathe": "^1.1.0", "picocolors": "^1.0.0", - "std-env": "^3.3.2", - "strip-literal": "^1.0.1", - "tinybench": "^2.5.0", - "tinypool": "^0.5.0", + "source-map": "^0.6.1", + "std-env": "^3.3.1", + "strip-literal": "^1.0.0", + "tinybench": "^2.3.1", + "tinypool": "^0.4.0", + "tinyspy": "^1.0.2", "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.32.2", + "vite-node": "0.29.8", "why-is-node-running": "^2.2.2" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": ">=v14.18.0" + "node": ">=v14.16.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { "@edge-runtime/vm": "*", @@ -18452,14 +18591,15 @@ } }, "node_modules/vitest/node_modules/vite-node": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.32.2.tgz", - "integrity": "sha512-dTQ1DCLwl2aEseov7cfQ+kDMNJpM1ebpyMMMwWzBvLbis8Nla/6c9WQcqpPssTwS6Rp/+U6KwlIj8Eapw4bLdA==", + "version": "0.29.8", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.29.8.tgz", + "integrity": "sha512-b6OtCXfk65L6SElVM20q5G546yu10/kNrhg08afEoWlFRJXFq9/6glsvSVY+aI6YeC1tu2TtAqI2jHEQmOmsFw==", "dev": true, + "peer": true, "dependencies": { "cac": "^6.7.14", "debug": "^4.3.4", - "mlly": "^1.2.0", + "mlly": "^1.1.0", "pathe": "^1.1.0", "picocolors": "^1.0.0", "vite": "^3.0.0 || ^4.0.0" @@ -18468,10 +18608,10 @@ "vite-node": "vite-node.mjs" }, "engines": { - "node": ">=v14.18.0" + "node": ">=v14.16.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "url": "https://github.com/sponsors/antfu" } }, "node_modules/vm2": { @@ -19118,44 +19258,247 @@ "dev": true, "license": "MIT" }, - "packages/next-on-pages/node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "packages/next-on-pages/node_modules/@vitest/expect": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.2.tgz", + "integrity": "sha512-6q5yzweLnyEv5Zz1fqK5u5E83LU+gOMVBDuxBl2d2Jfx1BAp5M+rZgc5mlyqdnxquyoiOXpXmFNkcGcfFnFH3Q==", "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "dependencies": { + "@vitest/spy": "0.32.2", + "@vitest/utils": "0.32.2", + "chai": "^4.3.7" }, - "engines": { - "node": ">=12.20" + "funding": { + "url": "https://opencollective.com/vitest" } - } - }, - "dependencies": { - "@actions/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", - "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", + }, + "packages/next-on-pages/node_modules/@vitest/runner": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.32.2.tgz", + "integrity": "sha512-06vEL0C1pomOEktGoLjzZw+1Fb+7RBRhmw/06WkDrd1akkT9i12su0ku+R/0QM69dfkIL/rAIDTG+CSuQVDcKw==", "dev": true, - "requires": { - "@actions/http-client": "^2.0.1", - "uuid": "^8.3.2" + "dependencies": { + "@vitest/utils": "0.32.2", + "concordance": "^5.0.4", + "p-limit": "^4.0.0", + "pathe": "^1.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "@actions/http-client": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz", - "integrity": "sha512-BonhODnXr3amchh4qkmjPMUO8mFi/zLaaCeCAJZqch8iQqyDnVIkySjB38VHAC8IJ+bnlgfOqlhpyCUZHlQsqw==", + "packages/next-on-pages/node_modules/@vitest/spy": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.32.2.tgz", + "integrity": "sha512-Q/ZNILJ4ca/VzQbRM8ur3Si5Sardsh1HofatG9wsJY1RfEaw0XKP8IVax2lI1qnrk9YPuG9LA2LkZ0EI/3d4ug==", "dev": true, - "requires": { - "tunnel": "^0.0.6" + "dependencies": { + "tinyspy": "^2.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "@ampproject/remapping": { - "version": "2.2.1", - "peer": true, - "requires": { + "packages/next-on-pages/node_modules/@vitest/utils": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.2.tgz", + "integrity": "sha512-lnJ0T5i03j0IJaeW73hxe2AuVnZ/y1BhhCOuIcl9LIzXnbpXJT9Lrt6brwKHXLOiA7MZ6N5hSJjt0xE1dGNCzQ==", + "dev": true, + "dependencies": { + "diff-sequences": "^29.4.3", + "loupe": "^2.3.6", + "pretty-format": "^27.5.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/next-on-pages/node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/next-on-pages/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "packages/next-on-pages/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "packages/next-on-pages/node_modules/tinypool": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.5.0.tgz", + "integrity": "sha512-paHQtnrlS1QZYKF/GnLoOM/DN9fqaGOFbCbxzAhwniySnzl9Ebk8w73/dd34DAhe/obUbPAOldTyYXQZxnPBPQ==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "packages/next-on-pages/node_modules/tinyspy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", + "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "packages/next-on-pages/node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + }, + "packages/next-on-pages/node_modules/vite-node": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.32.2.tgz", + "integrity": "sha512-dTQ1DCLwl2aEseov7cfQ+kDMNJpM1ebpyMMMwWzBvLbis8Nla/6c9WQcqpPssTwS6Rp/+U6KwlIj8Eapw4bLdA==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "mlly": "^1.2.0", + "pathe": "^1.1.0", + "picocolors": "^1.0.0", + "vite": "^3.0.0 || ^4.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": ">=v14.18.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/next-on-pages/node_modules/vitest": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.32.2.tgz", + "integrity": "sha512-hU8GNNuQfwuQmqTLfiKcqEhZY72Zxb7nnN07koCUNmntNxbKQnVbeIS6sqUgR3eXSlbOpit8+/gr1KpqoMgWCQ==", + "dev": true, + "dependencies": { + "@types/chai": "^4.3.5", + "@types/chai-subset": "^1.3.3", + "@types/node": "*", + "@vitest/expect": "0.32.2", + "@vitest/runner": "0.32.2", + "@vitest/snapshot": "0.32.2", + "@vitest/spy": "0.32.2", + "@vitest/utils": "0.32.2", + "acorn": "^8.8.2", + "acorn-walk": "^8.2.0", + "cac": "^6.7.14", + "chai": "^4.3.7", + "concordance": "^5.0.4", + "debug": "^4.3.4", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.0", + "pathe": "^1.1.0", + "picocolors": "^1.0.0", + "std-env": "^3.3.2", + "strip-literal": "^1.0.1", + "tinybench": "^2.5.0", + "tinypool": "^0.5.0", + "vite": "^3.0.0 || ^4.0.0", + "vite-node": "0.32.2", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": ">=v14.18.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@vitest/browser": "*", + "@vitest/ui": "*", + "happy-dom": "*", + "jsdom": "*", + "playwright": "*", + "safaridriver": "*", + "webdriverio": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "playwright": { + "optional": true + }, + "safaridriver": { + "optional": true + }, + "webdriverio": { + "optional": true + } + } + } + }, + "dependencies": { + "@actions/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", + "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", + "dev": true, + "requires": { + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" + } + }, + "@actions/http-client": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz", + "integrity": "sha512-BonhODnXr3amchh4qkmjPMUO8mFi/zLaaCeCAJZqch8iQqyDnVIkySjB38VHAC8IJ+bnlgfOqlhpyCUZHlQsqw==", + "dev": true, + "requires": { + "tunnel": "^0.0.6" + } + }, + "@ampproject/remapping": { + "version": "2.2.1", + "peer": true, + "requires": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" } @@ -20747,11 +21090,136 @@ "version": "20.2.5", "dev": true }, + "@vitest/expect": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.2.tgz", + "integrity": "sha512-6q5yzweLnyEv5Zz1fqK5u5E83LU+gOMVBDuxBl2d2Jfx1BAp5M+rZgc5mlyqdnxquyoiOXpXmFNkcGcfFnFH3Q==", + "dev": true, + "requires": { + "@vitest/spy": "0.32.2", + "@vitest/utils": "0.32.2", + "chai": "^4.3.7" + } + }, + "@vitest/runner": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.32.2.tgz", + "integrity": "sha512-06vEL0C1pomOEktGoLjzZw+1Fb+7RBRhmw/06WkDrd1akkT9i12su0ku+R/0QM69dfkIL/rAIDTG+CSuQVDcKw==", + "dev": true, + "requires": { + "@vitest/utils": "0.32.2", + "concordance": "^5.0.4", + "p-limit": "^4.0.0", + "pathe": "^1.1.0" + } + }, + "@vitest/spy": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.32.2.tgz", + "integrity": "sha512-Q/ZNILJ4ca/VzQbRM8ur3Si5Sardsh1HofatG9wsJY1RfEaw0XKP8IVax2lI1qnrk9YPuG9LA2LkZ0EI/3d4ug==", + "dev": true, + "requires": { + "tinyspy": "^2.1.0" + } + }, + "@vitest/utils": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.2.tgz", + "integrity": "sha512-lnJ0T5i03j0IJaeW73hxe2AuVnZ/y1BhhCOuIcl9LIzXnbpXJT9Lrt6brwKHXLOiA7MZ6N5hSJjt0xE1dGNCzQ==", + "dev": true, + "requires": { + "diff-sequences": "^29.4.3", + "loupe": "^2.3.6", + "pretty-format": "^27.5.1" + } + }, + "diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "tinypool": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.5.0.tgz", + "integrity": "sha512-paHQtnrlS1QZYKF/GnLoOM/DN9fqaGOFbCbxzAhwniySnzl9Ebk8w73/dd34DAhe/obUbPAOldTyYXQZxnPBPQ==", + "dev": true + }, + "tinyspy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", + "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", + "dev": true + }, "typescript": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "dev": true + }, + "vite-node": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.32.2.tgz", + "integrity": "sha512-dTQ1DCLwl2aEseov7cfQ+kDMNJpM1ebpyMMMwWzBvLbis8Nla/6c9WQcqpPssTwS6Rp/+U6KwlIj8Eapw4bLdA==", + "dev": true, + "requires": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "mlly": "^1.2.0", + "pathe": "^1.1.0", + "picocolors": "^1.0.0", + "vite": "^3.0.0 || ^4.0.0" + } + }, + "vitest": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.32.2.tgz", + "integrity": "sha512-hU8GNNuQfwuQmqTLfiKcqEhZY72Zxb7nnN07koCUNmntNxbKQnVbeIS6sqUgR3eXSlbOpit8+/gr1KpqoMgWCQ==", + "dev": true, + "requires": { + "@types/chai": "^4.3.5", + "@types/chai-subset": "^1.3.3", + "@types/node": "*", + "@vitest/expect": "0.32.2", + "@vitest/runner": "0.32.2", + "@vitest/snapshot": "0.32.2", + "@vitest/spy": "0.32.2", + "@vitest/utils": "0.32.2", + "acorn": "^8.8.2", + "acorn-walk": "^8.2.0", + "cac": "^6.7.14", + "chai": "^4.3.7", + "concordance": "^5.0.4", + "debug": "^4.3.4", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.0", + "pathe": "^1.1.0", + "picocolors": "^1.0.0", + "std-env": "^3.3.2", + "strip-literal": "^1.0.1", + "tinybench": "^2.5.0", + "tinypool": "^0.5.0", + "vite": "^3.0.0 || ^4.0.0", + "vite-node": "0.32.2", + "why-is-node-running": "^2.2.2" + } } } }, @@ -22547,24 +23015,25 @@ } }, "@vitest/expect": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.2.tgz", - "integrity": "sha512-6q5yzweLnyEv5Zz1fqK5u5E83LU+gOMVBDuxBl2d2Jfx1BAp5M+rZgc5mlyqdnxquyoiOXpXmFNkcGcfFnFH3Q==", + "version": "0.29.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.29.8.tgz", + "integrity": "sha512-xlcVXn5I5oTq6NiZSY3ykyWixBxr5mG8HYtjvpgg6KaqHm0mvhX18xuwl5YGxIRNt/A5jidd7CWcNHrSvgaQqQ==", "dev": true, + "peer": true, "requires": { - "@vitest/spy": "0.32.2", - "@vitest/utils": "0.32.2", + "@vitest/spy": "0.29.8", + "@vitest/utils": "0.29.8", "chai": "^4.3.7" } }, "@vitest/runner": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.32.2.tgz", - "integrity": "sha512-06vEL0C1pomOEktGoLjzZw+1Fb+7RBRhmw/06WkDrd1akkT9i12su0ku+R/0QM69dfkIL/rAIDTG+CSuQVDcKw==", + "version": "0.29.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.29.8.tgz", + "integrity": "sha512-FzdhnRDwEr/A3Oo1jtIk/B952BBvP32n1ObMEb23oEJNO+qO5cBet6M2XWIDQmA7BDKGKvmhUf2naXyp/2JEwQ==", "dev": true, + "peer": true, "requires": { - "@vitest/utils": "0.32.2", - "concordance": "^5.0.4", + "@vitest/utils": "0.29.8", "p-limit": "^4.0.0", "pathe": "^1.1.0" } @@ -22600,12 +23069,13 @@ } }, "@vitest/spy": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.32.2.tgz", - "integrity": "sha512-Q/ZNILJ4ca/VzQbRM8ur3Si5Sardsh1HofatG9wsJY1RfEaw0XKP8IVax2lI1qnrk9YPuG9LA2LkZ0EI/3d4ug==", + "version": "0.29.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.29.8.tgz", + "integrity": "sha512-VdjBe9w34vOMl5I5mYEzNX8inTxrZ+tYUVk9jxaZJmHFwmDFC/GV3KBFTA/JKswr3XHvZL+FE/yq5EVhb6pSAw==", "dev": true, + "peer": true, "requires": { - "tinyspy": "^2.1.0" + "tinyspy": "^1.0.2" } }, "@vitest/ui": { @@ -22623,27 +23093,31 @@ } }, "@vitest/utils": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.2.tgz", - "integrity": "sha512-lnJ0T5i03j0IJaeW73hxe2AuVnZ/y1BhhCOuIcl9LIzXnbpXJT9Lrt6brwKHXLOiA7MZ6N5hSJjt0xE1dGNCzQ==", + "version": "0.29.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.29.8.tgz", + "integrity": "sha512-qGzuf3vrTbnoY+RjjVVIBYfuWMjn3UMUqyQtdGNZ6ZIIyte7B37exj6LaVkrZiUTvzSadVvO/tJm8AEgbGCBPg==", "dev": true, + "peer": true, "requires": { - "diff-sequences": "^29.4.3", + "cli-truncate": "^3.1.0", + "diff": "^5.1.0", "loupe": "^2.3.6", "pretty-format": "^27.5.1" }, "dependencies": { - "diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true + "diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true, + "peer": true }, "pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, + "peer": true, "requires": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -22654,7 +23128,8 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "dev": true, + "peer": true } } }, @@ -23328,6 +23803,55 @@ "version": "2.9.0", "peer": true }, + "cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "peer": true, + "requires": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "peer": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "peer": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "peer": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, "cli-width": { "version": "3.0.0", "peer": true @@ -23726,6 +24250,13 @@ } } }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "peer": true + }, "edge-runtime": { "version": "2.1.4", "peer": true, @@ -28625,6 +29156,33 @@ "slash": { "version": "3.0.0" }, + "slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "peer": true + }, + "is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "peer": true + } + } + }, "smart-buffer": { "version": "4.2.0", "peer": true @@ -29169,16 +29727,18 @@ "dev": true }, "tinypool": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.5.0.tgz", - "integrity": "sha512-paHQtnrlS1QZYKF/GnLoOM/DN9fqaGOFbCbxzAhwniySnzl9Ebk8w73/dd34DAhe/obUbPAOldTyYXQZxnPBPQ==", - "dev": true + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.4.0.tgz", + "integrity": "sha512-2ksntHOKf893wSAH4z/+JbPpi92esw8Gn9N2deXX+B0EO92hexAVI9GIZZPx7P5aYo5KULfeOSt3kMOmSOy6uA==", + "dev": true, + "peer": true }, "tinyspy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", - "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-1.1.1.tgz", + "integrity": "sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==", + "dev": true, + "peer": true }, "tmp": { "version": "0.0.33", @@ -30363,131 +30923,153 @@ "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/android-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/android-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/darwin-arm64": { "version": "0.17.19", - "optional": true + "optional": true, + "peer": true }, "@esbuild/darwin-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/freebsd-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/freebsd-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-arm": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-ia32": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-loong64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-mips64el": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-ppc64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-riscv64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-s390x": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/netbsd-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/openbsd-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/sunos-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/win32-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/win32-ia32": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", - "optional": true + "optional": true, + "peer": true }, "@esbuild/win32-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", - "optional": true + "optional": true, + "peer": true }, "esbuild": { "version": "0.17.19", @@ -30543,47 +31125,48 @@ } }, "vitest": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.32.2.tgz", - "integrity": "sha512-hU8GNNuQfwuQmqTLfiKcqEhZY72Zxb7nnN07koCUNmntNxbKQnVbeIS6sqUgR3eXSlbOpit8+/gr1KpqoMgWCQ==", + "version": "0.29.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.29.8.tgz", + "integrity": "sha512-JIAVi2GK5cvA6awGpH0HvH/gEG9PZ0a/WoxdiV3PmqK+3CjQMf8c+J/Vhv4mdZ2nRyXFw66sAg6qz7VNkaHfDQ==", "dev": true, + "peer": true, "requires": { - "@types/chai": "^4.3.5", + "@types/chai": "^4.3.4", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "@vitest/expect": "0.32.2", - "@vitest/runner": "0.32.2", - "@vitest/snapshot": "0.32.2", - "@vitest/spy": "0.32.2", - "@vitest/utils": "0.32.2", - "acorn": "^8.8.2", + "@vitest/expect": "0.29.8", + "@vitest/runner": "0.29.8", + "@vitest/spy": "0.29.8", + "@vitest/utils": "0.29.8", + "acorn": "^8.8.1", "acorn-walk": "^8.2.0", "cac": "^6.7.14", "chai": "^4.3.7", - "concordance": "^5.0.4", "debug": "^4.3.4", - "local-pkg": "^0.4.3", - "magic-string": "^0.30.0", + "local-pkg": "^0.4.2", "pathe": "^1.1.0", "picocolors": "^1.0.0", - "std-env": "^3.3.2", - "strip-literal": "^1.0.1", - "tinybench": "^2.5.0", - "tinypool": "^0.5.0", + "source-map": "^0.6.1", + "std-env": "^3.3.1", + "strip-literal": "^1.0.0", + "tinybench": "^2.3.1", + "tinypool": "^0.4.0", + "tinyspy": "^1.0.2", "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.32.2", + "vite-node": "0.29.8", "why-is-node-running": "^2.2.2" }, "dependencies": { "vite-node": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.32.2.tgz", - "integrity": "sha512-dTQ1DCLwl2aEseov7cfQ+kDMNJpM1ebpyMMMwWzBvLbis8Nla/6c9WQcqpPssTwS6Rp/+U6KwlIj8Eapw4bLdA==", + "version": "0.29.8", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.29.8.tgz", + "integrity": "sha512-b6OtCXfk65L6SElVM20q5G546yu10/kNrhg08afEoWlFRJXFq9/6glsvSVY+aI6YeC1tu2TtAqI2jHEQmOmsFw==", "dev": true, + "peer": true, "requires": { "cac": "^6.7.14", "debug": "^4.3.4", - "mlly": "^1.2.0", + "mlly": "^1.1.0", "pathe": "^1.1.0", "picocolors": "^1.0.0", "vite": "^3.0.0 || ^4.0.0" diff --git a/package.json b/package.json index 105766999..8d395d7ec 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,7 @@ "devDependencies": { "@cfpreview/pages-e2e-test-runner-cli": "^0.0.18", "prettier": "^2.8.8", - "turbo": "^1.10.3", - "vitest": "^0.32.2" + "turbo": "^1.10.3" }, "prettier": { "printWidth": 80, From 605f67fe586009205c919a54440ce1f135a6f025 Mon Sep 17 00:00:00 2001 From: James Date: Sun, 2 Jul 2023 19:26:53 +0100 Subject: [PATCH 3/7] cant spell --- packages/next-on-pages/templates/_worker.js/utils/images.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-on-pages/templates/_worker.js/utils/images.ts b/packages/next-on-pages/templates/_worker.js/utils/images.ts index b9617ee69..092db5cc7 100644 --- a/packages/next-on-pages/templates/_worker.js/utils/images.ts +++ b/packages/next-on-pages/templates/_worker.js/utils/images.ts @@ -174,7 +174,7 @@ export async function imageResizing( // const imageResp = await fetch(imageReq, { cf: { image: options } }); // if (imageResp.status === 200) return formatResp(imageResp, imageUrl, config); - // NOTE: Pages also doens't seem to support calling the `/cdn-cgi/image` endpoint either. + // NOTE: Pages also doesn't seem to support calling the `/cdn-cgi/image` endpoint either. // const cdnCgiImageUrl = buildCdnCgiImageUrl(requestUrl, imageUrl, options); // const cdnCgiResp = await fetch(cdnCgiImageUrl, { headers: request.headers }); // if (cdnCgiResp.status === 200) return formatResp(cdnCgiResp, imageUrl, config); From 7295d6d5a7b0b0b70b7158ec0f92b4a1dd948e9b Mon Sep 17 00:00:00 2001 From: James Date: Mon, 3 Jul 2023 17:39:28 +0100 Subject: [PATCH 4/7] Update packages/next-on-pages/templates/_worker.js/utils/images.ts Co-authored-by: Dario Piotrowicz --- packages/next-on-pages/templates/_worker.js/utils/images.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-on-pages/templates/_worker.js/utils/images.ts b/packages/next-on-pages/templates/_worker.js/utils/images.ts index 092db5cc7..b4d76f653 100644 --- a/packages/next-on-pages/templates/_worker.js/utils/images.ts +++ b/packages/next-on-pages/templates/_worker.js/utils/images.ts @@ -86,7 +86,7 @@ export function getResizingProperties( } /** - * Builds an URL to the Cloudflare CDN image resizing endpoint. + * Builds a URL to the Cloudflare CDN image resizing endpoint. * * @param requestUrl Incoming request's URL. * @param imageUrl Image URL to resize. From dea749ad6c0e5ec0ddf98f89f8300a63bc82be7e Mon Sep 17 00:00:00 2001 From: James Date: Mon, 3 Jul 2023 17:48:01 +0100 Subject: [PATCH 5/7] apply suggestions --- .changeset/lemon-pears-burn.md | 2 ++ packages/next-on-pages/docs/supported.md | 2 +- .../templates/_worker.js/index.ts | 4 +-- .../templates/_worker.js/utils/images.ts | 12 +++---- .../tests/templates/utils/images.test.ts | 36 +++++++++---------- 5 files changed, 26 insertions(+), 30 deletions(-) diff --git a/.changeset/lemon-pears-burn.md b/.changeset/lemon-pears-burn.md index 5fb45ab55..5c2370e50 100644 --- a/.changeset/lemon-pears-burn.md +++ b/.changeset/lemon-pears-burn.md @@ -3,3 +3,5 @@ --- Support for images via `/_next/image`, falling back to the raw image URL when image resizing is not available. + +Due to limitations with Cloudflare Pages, it is not currently possible to send requests through image resizing. diff --git a/packages/next-on-pages/docs/supported.md b/packages/next-on-pages/docs/supported.md index 763d33c9a..02be65361 100644 --- a/packages/next-on-pages/docs/supported.md +++ b/packages/next-on-pages/docs/supported.md @@ -59,7 +59,7 @@ If you're application is using a package which relies on unsupported Node.js API - 🔄: Not currently supported, but it's probably possible and we may add support in the future - ❌: Not supported and unlikely to be supported in the future -- _1_ - **images**: If you want to use `next/image`, there are two options; allow the library to take care of incoming requests, or using a custom loader. Requests are intercepted in the router and image resizing is attempted to be used - if image resizing is not available, it falls back to fetching the normal image URL. Alternatively, you can provide your own [custom loader](https://nextjs.org/docs/api-reference/next/image#loader) and use Cloudflare Image Resizing, as per [Cloudflare's Image Resizing documentation](https://developers.cloudflare.com/images/image-resizing/integration-with-frameworks/#nextjs). +- _1_ - **images**: If you want to use `next/image`, there are two options; allow the library to take care of incoming requests, or using a custom loader. Requests are intercepted in the router and image resizing is attempted to be used (due to limitations with Pages, it is not currently possible to use image resizing) - if image resizing is not available, it falls back to fetching the normal image URL. Alternatively, you can provide your own [custom loader](https://nextjs.org/docs/api-reference/next/image#loader) and use Cloudflare Image Resizing, as per [Cloudflare's Image Resizing documentation](https://developers.cloudflare.com/images/image-resizing/integration-with-frameworks/#nextjs). ### next.config.js Properties diff --git a/packages/next-on-pages/templates/_worker.js/index.ts b/packages/next-on-pages/templates/_worker.js/index.ts index a45e5cb72..f3baa3f76 100644 --- a/packages/next-on-pages/templates/_worker.js/index.ts +++ b/packages/next-on-pages/templates/_worker.js/index.ts @@ -1,5 +1,5 @@ import { handleRequest } from './handleRequest'; -import { adjustRequestForVercel, imageResizing } from './utils'; +import { adjustRequestForVercel, handleImageResizingRequest } from './utils'; import type { AsyncLocalStorage } from 'node:async_hooks'; declare const __NODE_ENV__: string; @@ -24,7 +24,7 @@ export default { async () => { const url = new URL(request.url); if (url.pathname.startsWith('/_next/image')) { - return imageResizing(request, url, __CONFIG__.images); + return handleImageResizingRequest(request, __CONFIG__.images); } const adjustedRequest = adjustRequestForVercel(request); diff --git a/packages/next-on-pages/templates/_worker.js/utils/images.ts b/packages/next-on-pages/templates/_worker.js/utils/images.ts index b4d76f653..bf84cd9e7 100644 --- a/packages/next-on-pages/templates/_worker.js/utils/images.ts +++ b/packages/next-on-pages/templates/_worker.js/utils/images.ts @@ -36,18 +36,16 @@ type ResizingProperties = { * https://vercel.com/docs/build-output-api/v3/configuration#images * * @param request Incoming request. - * @param requestUrl Incoming request's URL. * @param config Images configuration from the Vercel build output. * @returns Resizing properties if the request is valid, otherwise undefined. */ export function getResizingProperties( request: Request, - requestUrl: URL, config?: VercelImagesConfig ): ResizingProperties | undefined { if (request.method !== 'GET') return undefined; - const { searchParams } = requestUrl; + const { origin, searchParams } = new URL(request.url); const rawUrl = searchParams.get('url'); const width = Number.parseInt(searchParams.get('w') ?? '', 10); @@ -57,7 +55,7 @@ export function getResizingProperties( if (!config?.sizes?.includes(width)) return undefined; if (quality < 0 || quality > 100) return undefined; - const url = new URL(rawUrl, requestUrl.origin); + const url = new URL(rawUrl, origin); // SVGs must be allowed by the config. if (url.pathname.endsWith('.svg') && !config?.dangerouslyAllowSVG) { @@ -152,16 +150,14 @@ export function formatResp( * Handles image resizing requests. * * @param request Incoming request. - * @param requestUrl Incoming request's URL. * @param config Images configuration from the Vercel build output. * @returns Resized image response if the request is valid, otherwise a 400 response. */ -export async function imageResizing( +export async function handleImageResizingRequest( request: Request, - requestUrl: URL, config?: VercelImagesConfig ): Promise { - const opts = getResizingProperties(request, requestUrl, config); + const opts = getResizingProperties(request, config); if (!opts) { return new Response('Invalid image resizing request', { status: 400 }); diff --git a/packages/next-on-pages/tests/templates/utils/images.test.ts b/packages/next-on-pages/tests/templates/utils/images.test.ts index 05b7ee7bb..09debd119 100644 --- a/packages/next-on-pages/tests/templates/utils/images.test.ts +++ b/packages/next-on-pages/tests/templates/utils/images.test.ts @@ -71,9 +71,9 @@ const baseConfig: VercelImagesConfig = { describe('getResizingProperties', () => { test('invalid method fails', () => { const url = new URL(baseValidUrl); - const request = new Request(url, { method: 'POST' }); + const req = new Request(url, { method: 'POST' }); - expect(getResizingProperties(request, url)).toEqual(undefined); + expect(getResizingProperties(req)).toEqual(undefined); }); describe('request search params', () => { @@ -81,42 +81,42 @@ describe('getResizingProperties', () => { const url = new URL(baseUrl); const req = new Request(url); - expect(getResizingProperties(req, url)).toEqual(undefined); + expect(getResizingProperties(req)).toEqual(undefined); }); test('invalid width fails', () => { const url = new URL(`${baseValidUrl}&w=abc`); const req = new Request(url); - expect(getResizingProperties(req, url)).toEqual(undefined); + expect(getResizingProperties(req)).toEqual(undefined); }); test('invalid quality fails', () => { const url = new URL(`${baseValidUrl}&w=100&q=abc`); const req = new Request(url); - expect(getResizingProperties(req, url)).toEqual(undefined); + expect(getResizingProperties(req)).toEqual(undefined); }); test('invalid width in images config fails', () => { const url = new URL(`${baseValidUrl}&w=100`); const req = new Request(url); - expect(getResizingProperties(req, url, baseConfig)).toEqual(undefined); + expect(getResizingProperties(req, baseConfig)).toEqual(undefined); }); test('invalid quality (>100) fails', () => { const url = new URL(`${baseValidUrl}&w=640&q=150`); const req = new Request(url); - expect(getResizingProperties(req, url, baseConfig)).toEqual(undefined); + expect(getResizingProperties(req, baseConfig)).toEqual(undefined); }); test('invalid quality (<0) fails', () => { const url = new URL(`${baseValidUrl}&w=640&q=-1`); const req = new Request(url); - expect(getResizingProperties(req, url, baseConfig)).toEqual(undefined); + expect(getResizingProperties(req, baseConfig)).toEqual(undefined); }); }); @@ -125,7 +125,7 @@ describe('getResizingProperties', () => { const url = new URL(`${baseValidUrl}&w=640`); const req = new Request(url); - const result = getResizingProperties(req, url, baseConfig); + const result = getResizingProperties(req, baseConfig); expect(result).toEqual({ imageUrl: new URL('https://localhost/images/1.jpg'), options: { format: undefined, width: 640, quality: 75 }, @@ -137,7 +137,7 @@ describe('getResizingProperties', () => { const req = new Request(url); const config = { ...baseConfig, dangerouslyAllowSVG: false }; - expect(getResizingProperties(req, url, config)).toEqual(undefined); + expect(getResizingProperties(req, config)).toEqual(undefined); }); test('svg image succeeds when config allows svgs', () => { @@ -145,7 +145,7 @@ describe('getResizingProperties', () => { const req = new Request(url); const config = { ...baseConfig, dangerouslyAllowSVG: true }; - const result = getResizingProperties(req, url, config); + const result = getResizingProperties(req, config); expect(result).toEqual({ imageUrl: new URL('https://localhost/images/1.svg'), options: { format: undefined, width: 640, quality: 75 }, @@ -157,7 +157,7 @@ describe('getResizingProperties', () => { const req = new Request(url); const config = { ...baseConfig, dangerouslyAllowSVG: true }; - const result = getResizingProperties(req, url, config); + const result = getResizingProperties(req, config); expect(result).toEqual({ imageUrl: new URL('https://localhost/images/1.svg'), options: { format: undefined, width: 640, quality: 75 }, @@ -172,7 +172,7 @@ describe('getResizingProperties', () => { ); const req = new Request(url); - expect(getResizingProperties(req, url, baseConfig)).toEqual(undefined); + expect(getResizingProperties(req, baseConfig)).toEqual(undefined); }); test('external image succeeds with allowed domain', () => { @@ -181,7 +181,7 @@ describe('getResizingProperties', () => { ); const req = new Request(url); - const result = getResizingProperties(req, url, baseConfig); + const result = getResizingProperties(req, baseConfig); expect(result).toEqual({ imageUrl: new URL('https://example.com/image.jpg'), options: { format: undefined, width: 640, quality: 75 }, @@ -194,7 +194,7 @@ describe('getResizingProperties', () => { ); const req = new Request(url); - const result = getResizingProperties(req, url, baseConfig); + const result = getResizingProperties(req, baseConfig); expect(result).toEqual({ imageUrl: new URL('https://via.placeholder.com/image.jpg'), options: { format: undefined, width: 640, quality: 75 }, @@ -207,7 +207,7 @@ describe('getResizingProperties', () => { const url = new URL(`${baseValidUrl}&w=640`); const req = new Request(url, { headers: { Accept: 'image/webp' } }); - const result = getResizingProperties(req, url, baseConfig); + const result = getResizingProperties(req, baseConfig); expect(result).toEqual({ imageUrl: new URL('https://localhost/images/1.jpg'), options: { format: 'webp', width: 640, quality: 75 }, @@ -220,7 +220,7 @@ describe('getResizingProperties', () => { headers: { Accept: 'image/avif,image/webp' }, }); - const result = getResizingProperties(req, url, baseConfig); + const result = getResizingProperties(req, baseConfig); expect(result).toEqual({ imageUrl: new URL('https://localhost/images/1.jpg'), options: { format: 'avif', width: 640, quality: 75 }, @@ -235,7 +235,6 @@ describe('buildCdnCgiImageUrl', () => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const { imageUrl, options } = getResizingProperties( new Request(requestUrl), - requestUrl, baseConfig )!; @@ -252,7 +251,6 @@ describe('buildCdnCgiImageUrl', () => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const { imageUrl, options } = getResizingProperties( new Request(requestUrl), - requestUrl, baseConfig )!; From 67c69f2ebc2afe3a605d16e4612d13c43c49e724 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 3 Jul 2023 17:52:04 +0100 Subject: [PATCH 6/7] comment about default quality --- packages/next-on-pages/templates/_worker.js/utils/images.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/next-on-pages/templates/_worker.js/utils/images.ts b/packages/next-on-pages/templates/_worker.js/utils/images.ts index bf84cd9e7..7a8d3da7e 100644 --- a/packages/next-on-pages/templates/_worker.js/utils/images.ts +++ b/packages/next-on-pages/templates/_worker.js/utils/images.ts @@ -49,6 +49,7 @@ export function getResizingProperties( const rawUrl = searchParams.get('url'); const width = Number.parseInt(searchParams.get('w') ?? '', 10); + // 75 is the default quality - https://nextjs.org/docs/app/api-reference/components/image#quality const quality = Number.parseInt(searchParams.get('q') ?? '75', 10); if (!rawUrl || Number.isNaN(width) || Number.isNaN(quality)) return undefined; From d1aa3534a919c521fe910e5eac592c2e37e600a3 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 3 Jul 2023 17:53:29 +0100 Subject: [PATCH 7/7] remove code for `/cdn-cgi/image` --- .../templates/_worker.js/utils/images.ts | 32 ------------------ .../tests/templates/utils/images.test.ts | 33 ------------------- 2 files changed, 65 deletions(-) diff --git a/packages/next-on-pages/templates/_worker.js/utils/images.ts b/packages/next-on-pages/templates/_worker.js/utils/images.ts index 7a8d3da7e..1d3b3db9e 100644 --- a/packages/next-on-pages/templates/_worker.js/utils/images.ts +++ b/packages/next-on-pages/templates/_worker.js/utils/images.ts @@ -84,33 +84,6 @@ export function getResizingProperties( }; } -/** - * Builds a URL to the Cloudflare CDN image resizing endpoint. - * - * @param requestUrl Incoming request's URL. - * @param imageUrl Image URL to resize. - * @param properties Image resizing properties. - * @returns URL to the Cloudflare CDN image resizing endpoint. - */ -export function buildCdnCgiImageUrl( - requestUrl: URL, - imageUrl: URL, - { width, quality, format }: RequestInitCfPropertiesImage -): string { - const opts = []; - - if (width) opts.push(`width=${width}`); - if (quality) opts.push(`quality=${quality}`); - if (format) opts.push(`format=${format}`); - - const imageHref = - requestUrl.origin === imageUrl.origin - ? imageUrl.pathname.slice(1) - : imageUrl.href; - - return `${requestUrl.origin}/cdn-cgi/image/${opts.join(',')}/${imageHref}`; -} - /** * Formats the given response to match the images configuration spec from the Vercel build output * config. @@ -171,11 +144,6 @@ export async function handleImageResizingRequest( // const imageResp = await fetch(imageReq, { cf: { image: options } }); // if (imageResp.status === 200) return formatResp(imageResp, imageUrl, config); - // NOTE: Pages also doesn't seem to support calling the `/cdn-cgi/image` endpoint either. - // const cdnCgiImageUrl = buildCdnCgiImageUrl(requestUrl, imageUrl, options); - // const cdnCgiResp = await fetch(cdnCgiImageUrl, { headers: request.headers }); - // if (cdnCgiResp.status === 200) return formatResp(cdnCgiResp, imageUrl, config); - const imageResp = await fetch(imageUrl, { headers: request.headers }); return formatResp(imageResp, imageUrl, config); } diff --git a/packages/next-on-pages/tests/templates/utils/images.test.ts b/packages/next-on-pages/tests/templates/utils/images.test.ts index 09debd119..6fe389d34 100644 --- a/packages/next-on-pages/tests/templates/utils/images.test.ts +++ b/packages/next-on-pages/tests/templates/utils/images.test.ts @@ -1,6 +1,5 @@ import { describe, expect, test } from 'vitest'; import { - buildCdnCgiImageUrl, formatResp, getResizingProperties, isRemotePatternMatch, @@ -229,38 +228,6 @@ describe('getResizingProperties', () => { }); }); -describe('buildCdnCgiImageUrl', () => { - test('builds a valid URL for relative images', () => { - const requestUrl = new URL(`${baseValidUrl}&w=640`); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const { imageUrl, options } = getResizingProperties( - new Request(requestUrl), - baseConfig - )!; - - const result = buildCdnCgiImageUrl(requestUrl, imageUrl, options); - expect(result).toEqual( - 'https://localhost/cdn-cgi/image/width=640,quality=75/images/1.jpg' - ); - }); - - test('builds a valid URL for external images', () => { - const requestUrl = new URL( - `${baseUrl}https%3A%2F%2Fexample.com%2Fimage.jpg&w=640` - ); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const { imageUrl, options } = getResizingProperties( - new Request(requestUrl), - baseConfig - )!; - - const result = buildCdnCgiImageUrl(requestUrl, imageUrl, options); - expect(result).toEqual( - 'https://localhost/cdn-cgi/image/width=640,quality=75/https://example.com/image.jpg' - ); - }); -}); - describe('formatResp', () => { test('applies content security policy from the config', () => { const config = { ...baseConfig, contentSecurityPolicy: 'default-src' };