From 8c8faa02abef86db23d3ea65e3bf2380bffcb52e Mon Sep 17 00:00:00 2001
From: Matt Kane
Date: Tue, 2 Apr 2024 16:13:18 +0100
Subject: [PATCH 1/9] chore: annotate all skipped tests (#378)
* chore: annotate all skipped tests
* chore: generate test config from JSON file
* chore: generate JSON results
* chore: more annotation
* chore: add more test explanations
* chore: more test config
* chore: more test config
* chore: use reason
---------
Co-authored-by: Michal Piechowiak
---
.github/workflows/test-e2e.yml | 7 +-
tests/netlify-e2e.cjs | 239 ++------------------
tests/test-config.json | 387 +++++++++++++++++++++++++++++++++
tools/deno/junit2json.ts | 182 ++++++++++++++++
4 files changed, 599 insertions(+), 216 deletions(-)
create mode 100644 tests/test-config.json
create mode 100644 tools/deno/junit2json.ts
diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml
index 1fd77b2610..5941b836ef 100644
--- a/.github/workflows/test-e2e.yml
+++ b/.github/workflows/test-e2e.yml
@@ -241,7 +241,12 @@ jobs:
echo "slackEvent<> $GITHUB_OUTPUT
deno run -A tools/deno/junit2slack.ts --dir artifacts --version ${{matrix.version}} --runUrl ${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}} >> $GITHUB_OUTPUT
echo "NETLIFY_EOF" >> $GITHUB_OUTPUT
-
+ deno run -A tools/deno/junit2json.ts artifacts > report/test-results.json
+ - name: Upload Test JSON
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{matrix.version}}-test-results.json
+ path: report/test-results.json
- name: Notify Slack
if: success() || failure()
uses: slackapi/slack-github-action@v1.24.0
diff --git a/tests/netlify-e2e.cjs b/tests/netlify-e2e.cjs
index 209e848a96..c02495c92b 100644
--- a/tests/netlify-e2e.cjs
+++ b/tests/netlify-e2e.cjs
@@ -1,220 +1,29 @@
-module.exports = {
+// @ts-check
+const config = {
version: 2,
- suites: {
- 'test/e2e/app-dir/app-static/app-static.test.ts': {
- failed: ['app-dir static/dynamic handling should warn for too many cache tags'],
- },
- 'test/e2e/app-dir/headers-static-bailout/headers-static-bailout.test.ts': {
- failed: [
- // Uses cli output
- 'headers-static-bailout it provides a helpful link in case static generation bailout is uncaught',
- ],
- },
- 'test/e2e/app-dir/parallel-routes-and-interception/parallel-routes-and-interception.test.ts': {
- failed: [],
- flakey: [
- // Uses patch file
- 'parallel-routes-and-interception parallel routes should gracefully handle when two page segments match the `children` parallel slot',
- ],
- },
- 'test/e2e/opentelemetry/opentelemetry.test.ts': {
- failed: [
- 'opentelemetry root context app router should handle RSC with fetch',
- 'opentelemetry incoming context propagation app router should handle RSC with fetch',
- 'opentelemetry incoming context propagation app router should handle route handlers in app router',
- ],
- },
- 'test/e2e/app-dir/rsc-basic/rsc-basic.test.ts': {
- failed: [
- 'app dir - rsc basics should render initial styles of css-in-js in edge SSR correctly',
- 'app dir - rsc basics should render initial styles of css-in-js in nodejs SSR correctly',
- 'app dir - rsc basics should render server components correctly',
- ],
- flakey: [
- 'app dir - rsc basics react@experimental should opt into the react@experimental when enabling ppr',
- 'app dir - rsc basics react@experimental should opt into the react@experimental when enabling taint',
- ],
- },
- 'test/e2e/app-dir/navigation/navigation.test.ts': {
- failed: [
- 'app dir - navigation redirect status code should respond with 308 status code if permanent flag is set',
- 'app dir - navigation redirect status code should respond with 307 status code in client component',
- 'app dir - navigation redirect status code should respond with 307 status code in server component',
- 'app dir - navigation bots should block rendering for bots and return 404 status',
- 'app dir - navigation navigation between pages and app should not continously initiate a mpa navigation to the same URL when router state changes',
- ],
- },
- 'test/production/app-dir/unexpected-error/unexpected-error.test.ts': {
- failed: [
- 'unexpected-error should set response status to 500 for unexpected errors in ssr app route',
- 'unexpected-error should set response status to 500 for unexpected errors in isr app route',
- ],
- },
- 'test/e2e/skip-trailing-slash-redirect/index.test.ts': {
- flakey: [
- 'skip-trailing-slash-redirect should merge cookies from middleware and API routes correctly',
- 'skip-trailing-slash-redirect should merge cookies from middleware and edge API routes correctly',
- 'skip-trailing-slash-redirect should handle external rewrite correctly /chained-rewrite-ssr',
- 'skip-trailing-slash-redirect should handle external rewrite correctly /chained-rewrite-static',
- 'skip-trailing-slash-redirect should handle external rewrite correctly /chained-rewrite-ssg',
- ],
- },
- 'test/e2e/module-layer/index.test.ts': {
- flakey: [
- 'module layer no server-only in server targets should render routes marked with restriction marks without errors',
- 'module layer with server-only in server targets should render routes marked with restriction marks without errors',
- ],
- },
- 'test/e2e/getserversideprops/test/index.test.ts': {
- flakey: [
- 'getServerSideProps should set default caching header',
- 'getServerSideProps should respect custom caching header',
- ],
- },
- 'test/e2e/app-dir/metadata-dynamic-routes/index.test.ts': {
- pending: [],
- flakey: [
- 'app dir - metadata dynamic routes text routes should handle robots.[ext] dynamic routes',
- 'app dir - metadata dynamic routes text routes should handle sitemap.[ext] dynamic routes',
- 'app dir - metadata dynamic routes social image routes should handle manifest.[ext] dynamic routes',
- 'app dir - metadata dynamic routes social image routes should render og image with opengraph-image dynamic routes',
- 'app dir - metadata dynamic routes social image routes should render og image with twitter-image dynamic routes',
- 'app dir - metadata dynamic routes icon image routes should render icon with dynamic routes',
- 'app dir - metadata dynamic routes icon image routes should render apple icon with dynamic routes',
- 'app dir - metadata dynamic routes should inject dynamic metadata properly to head',
- 'app dir - metadata dynamic routes should use localhost for local prod and fallback to deployment url when metadataBase is falsy',
- ],
- },
- 'test/e2e/app-dir/metadata/metadata.test.ts': {
- flakey: [
- 'app dir - metadata opengraph should pick up opengraph-image and twitter-image as static metadata files',
- 'app dir - metadata static routes should have /favicon.ico as route',
- 'app dir - metadata static routes should have icons as route',
- ],
- },
- 'test/e2e/basepath.test.ts': {
- flakey: [
- 'basePath should not update URL for a 404',
- 'basePath should handle 404 urls that start with basePath',
- 'basePath should show 404 for page not under the /docs prefix',
- ],
- },
- 'test/e2e/app-dir/app/index.test.ts': {
- flakey: [
- 'app dir - basic should return the `vary` header from edge runtime',
- 'app dir - basic should return the `vary` header from pages for flight requests',
- ],
- },
- 'test/e2e/app-dir/conflicting-page-segments/conflicting-page-segments.test.ts': {
- flakey: [
- 'conflicting-page-segments should throw an error when a route groups causes a conflict with a parallel segment',
- ],
- },
- 'test/e2e/app-dir/actions-navigation/index.test.ts': {
- flakey: [
- 'app-dir action handling should handle actions correctly after following a relative link',
- ],
- },
- 'test/e2e/middleware-general/test/index.test.ts': {
- flakey: [
- 'Middleware Runtime with i18n should redirect the same for direct visit and client-transition',
- 'Middleware Runtime without i18n should redirect the same for direct visit and client-transition',
- // These rely on Cloudflare-specific error wording
- 'Middleware Runtime with i18n should allow to abort a fetch request',
- 'Middleware Runtime without i18n should allow to abort a fetch request',
- ],
- },
- 'test/e2e/prerender.test.ts': {
- flakey: [
- 'Prerender should handle on-demand revalidate for fallback: blocking',
- // Header whitespace mismatch
- 'Prerender should use correct caching headers for a revalidate page',
- // Header whitespace mismatch
- 'Prerender should use correct caching headers for a no-revalidate page',
- ],
- },
- 'test/e2e/app-dir/app-routes/app-custom-route-base-path.test.ts': {
- flakey: [
- // Uses cli output
- 'app-custom-routes no response returned should print an error when no response is returned',
- 'app-custom-routes error conditions responds with 400 (Bad Request) when the requested method is not a valid HTTP method',
- ],
- },
- 'test/e2e/app-dir/app-routes/app-custom-routes.test.ts': {
- flakey: [
- // Uses cli output
- 'app-custom-routes no response returned should print an error when no response is returned',
- 'app-custom-routes error conditions responds with 400 (Bad Request) when the requested method is not a valid HTTP method',
- ],
- },
- 'test/e2e/app-dir/actions/app-action.test.ts': {
- flakey: [
- // Uses cli output
- 'app-dir action handling should log a warning when a server action is not found but an id is provided',
- 'app-dir action handling should work with interception routes',
- ],
- },
- },
+ suites: {},
rules: {
include: ['test/e2e/**/*.test.{t,j}s{,x}'],
- exclude: [
- // This is a template, not a real test file
- 'test/e2e/test-template/{{ toFileName name }}/{{ toFileName name }}.test.ts',
- 'test/e2e/app-dir/next-font/**/*',
- // We don't support PPR
- 'test/e2e/app-dir/ppr/**/*',
- 'test/e2e/app-dir/ppr-*/**/*',
- 'test/e2e/app-dir/app-prefetch*/**/*',
- 'test/e2e/app-dir/app-esm-js/index.test.ts',
- 'test/e2e/app-dir/interception-middleware-rewrite/interception-middleware-rewrite.test.ts',
- 'test/e2e/app-dir/searchparams-static-bailout/searchparams-static-bailout.test.ts',
- 'test/e2e/app-dir/app-compilation/index.test.ts',
- 'test/e2e/cancel-request/stream-cancel.test.ts',
- 'test/e2e/favicon-short-circuit/favicon-short-circuit.test.ts',
- 'test/e2e/edge-pages-support/edge-document.test.ts',
- 'test/e2e/third-parties/index.test.ts',
- // Uses cli output
- 'test/e2e/swc-warnings/index.test.ts',
- 'test/e2e/app-dir/externals/externals.test.ts',
- 'test/e2e/app-dir/use-selected-layout-segment-s/use-selected-layout-segment-s.test.ts',
- 'test/e2e/repeated-forward-slashes-error/repeated-forward-slashes-error.test.ts',
- 'test/e2e/app-dir/with-exported-function-config/with-exported-function-config.test.ts',
- 'test/e2e/app-dir/x-forwarded-headers/x-forwarded-headers.test.ts',
- 'test/e2e/app-dir/third-parties/basic.test.ts',
- 'test/e2e/app-dir/conflicting-page-segments/conflicting-page-segments.test.ts',
- 'test/e2e/404-page-router/index.test.ts',
- 'test/e2e/app-dir/app-client-cache/client-cache.test.ts',
- 'test/e2e/app-dir/app-fetch-deduping/app-fetch-deduping.test.ts',
- 'test/e2e/app-dir/app/experimental-compile.test.ts',
- 'test/e2e/app-dir/app/standalone-gsp.test.ts',
- 'test/e2e/app-dir/app/standalone.test.ts',
- 'test/e2e/app-dir/app/vercel-speed-insights.test.ts',
- 'test/e2e/app-dir/build-size/index.test.ts',
- 'test/e2e/app-dir/create-root-layout/create-root-layout.test.ts',
- 'test/e2e/app-dir/headers-static-bailout/headers-static-bailout.test.ts',
- 'test/e2e/app-dir/rewrites-redirects/rewrites-redirects.test.ts',
- 'test/e2e/edge-compiler-can-import-blob-assets/index.test.ts',
- 'test/e2e/i18n-data-fetching-redirect/index.test.ts',
- 'test/e2e/manual-client-base-path/index.test.ts',
- 'test/e2e/no-eslint-warn-with-no-eslint-config/index.test.ts',
- 'test/e2e/switchable-runtime/index.test.ts',
- 'test/e2e/trailingslash-with-rewrite/index.test.ts',
- 'test/e2e/transpile-packages/index.test.ts',
- 'test/e2e/typescript-version-no-warning/typescript-version-no-warning.test.ts',
- 'test/e2e/typescript-version-warning/typescript-version-warning.test.ts',
- 'test/e2e/app-dir/app/useReportWebVitals.test.ts',
- 'test/e2e/app-dir/app-static/app-static-custom-handler.test.ts',
- // Tries to patch deployed files
- 'test/e2e/app-dir/missing-suspense-with-csr-bailout/missing-suspense-with-csr-bailout.test.ts',
- // Tries to patch deployed files
- 'test/e2e/module-layer/module-layer.test.ts',
- // Hard-coded localhost URL
- 'test/e2e/app-dir/next-image/next-image-proxy.test.ts',
- 'test/e2e/proxy-request-with-middleware/test/index.test.ts',
- // Uses invalid WASM syntax
- 'test/e2e/edge-can-use-wasm-files/index.test.ts',
- // Expected behaviour does not match next start
- 'test/e2e/i18n-data-route/i18n-data-route.test.ts',
- ],
+ /** @type {string[]} */
+ exclude: [],
},
}
+
+const rules = require('./test-config.json')
+
+// Skip non-deploy tests
+config.rules.exclude.push(...rules.ignored)
+
+for (const rule of rules.skipped) {
+ // Individually-skipped tests
+ if (rule.tests?.length) {
+ config.suites[rule.file] = {
+ failed: rule.tests,
+ }
+ } else {
+ // Entire suite skipped
+ config.rules.exclude.push(rule.file)
+ }
+}
+
+module.exports = config
diff --git a/tests/test-config.json b/tests/test-config.json
new file mode 100644
index 0000000000..036c458468
--- /dev/null
+++ b/tests/test-config.json
@@ -0,0 +1,387 @@
+{
+ "ignored": [
+ "test/e2e/test-template/{{ toFileName name }}/{{ toFileName name }}.test.ts",
+ "test/e2e/app-dir/app-validation/validation.test.ts",
+ "test/e2e/app-dir/app/standalone-gsp.test.ts",
+ "test/e2e/app-dir/app/standalone.test.ts",
+ "test/e2e/app-dir/ppr-errors/ppr-errors.test.ts",
+ "test/e2e/app-dir/interception-middleware-rewrite/interception-middleware-rewrite.test.ts",
+ "test/e2e/app-dir/app-compilation/index.test.ts",
+ "test/e2e/favicon-short-circuit/favicon-short-circuit.test.ts",
+ "test/e2e/app-dir/with-exported-function-config/with-exported-function-config.test.ts",
+ "test/e2e/app-dir/conflicting-page-segments/conflicting-page-segments.test.ts",
+ "test/e2e/404-page-router/index.test.ts",
+ "test/e2e/app-dir/app-fetch-deduping/app-fetch-deduping.test.ts",
+ "test/e2e/app-dir/app/experimental-compile.test.ts",
+ "test/e2e/app-dir/app/standalone-gsp.test.ts",
+ "test/e2e/app-dir/app/standalone.test.ts",
+ "test/e2e/app-dir/build-size/index.test.ts",
+ "test/e2e/app-dir/create-root-layout/create-root-layout.test.ts",
+ "test/e2e/app-dir/rewrites-redirects/rewrites-redirects.test.ts",
+ "test/e2e/edge-compiler-can-import-blob-assets/index.test.ts",
+ "test/e2e/i18n-data-fetching-redirect/index.test.ts",
+ "test/e2e/manual-client-base-path/index.test.ts",
+ "test/e2e/no-eslint-warn-with-no-eslint-config/index.test.ts",
+ "test/e2e/switchable-runtime/index.test.ts",
+ "test/e2e/trailingslash-with-rewrite/index.test.ts",
+ "test/e2e/transpile-packages/index.test.ts",
+ "test/e2e/typescript-version-no-warning/typescript-version-no-warning.test.ts",
+ "test/e2e/typescript-version-warning/typescript-version-warning.test.ts"
+ ],
+ "skipped": [
+ {
+ "file": "test/e2e/proxy-request-with-middleware/test/index.test.ts",
+ "reason": "Hard-coded localhost URL"
+ },
+ {
+ "file": "test/e2e/app-dir/ppr/**/*",
+ "reason": "Relies on local test server"
+ },
+ {
+ "file": "test/e2e/app-dir/ppr-*/**/*",
+ "reason": "Relies on local test server"
+ },
+ {
+ "file": "test/e2e/app-dir/app-prefetch-false-loading/app-prefetch-false-loading.test.ts",
+ "reason": "Uses CLI output"
+ },
+ {
+ "file": "test/e2e/cancel-request/stream-cancel.test.ts",
+ "reason": "Doesn't work for HTTPS URLs"
+ },
+ {
+ "file": "test/e2e/edge-pages-support/edge-document.test.ts",
+ "reason": "Tries to patch deployed files"
+ },
+ {
+ "file": "test/e2e/third-parties/index.test.ts",
+ "reason": "npm install doesn't work in this repo"
+ },
+ {
+ "file": "test/e2e/swc-warnings/index.test.ts",
+ "reason": "Uses CLI output"
+ },
+ {
+ "file": "test/e2e/repeated-forward-slashes-error/repeated-forward-slashes-error.test.ts",
+ "reason": "Uses CLI output"
+ },
+ {
+ "file": "test/e2e/app-dir/x-forwarded-headers/x-forwarded-headers.test.ts",
+ "reason": "Whitespace mismatch"
+ },
+ {
+ "file": "test/e2e/app-dir/third-parties/basic.test.ts",
+ "reason": "npm install doesn't work in this repo"
+ },
+ {
+ "file": "test/e2e/app-dir/app/vercel-speed-insights.test.ts",
+ "reason": "Vercel-specific"
+ },
+ {
+ "file": "test/e2e/app-dir/headers-static-bailout/headers-static-bailout.test.ts",
+ "reason": "Tries to patch deployed files"
+ },
+ {
+ "file": "test/e2e/app-dir/app/useReportWebVitals.test.ts",
+ "reason": "Vercel-specific"
+ },
+ {
+ "file": "test/e2e/app-dir/app-static/app-static-custom-handler.test.ts",
+ "reason": "Test not compatible"
+ },
+ {
+ "file": "test/e2e/app-dir/missing-suspense-with-csr-bailout/missing-suspense-with-csr-bailout.test.ts",
+ "reason": "Tries to patch deployed files"
+ },
+ {
+ "file": "test/e2e/module-layer/module-layer.test.ts",
+ "reason": "Tries to patch deployed files"
+ },
+ {
+ "file": "test/e2e/next-image/next-image-proxy.test.ts",
+ "reason": "Hard-coded localhost URL"
+ },
+ {
+ "file": "test/e2e/app-dir/next-image/next-image-proxy.test.ts",
+ "reason": "Hard-coded localhost URL"
+ },
+ {
+ "file": "test/e2e/edge-can-use-wasm-files/index.test.ts",
+ "reason": "Uses invalid WASM syntax"
+ },
+ {
+ "file": "test/e2e/i18n-data-route/i18n-data-route.test.ts",
+ "reason": "Expected behaviour does not match next start"
+ },
+ {
+ "file": "test/e2e/app-dir/app-static/app-static.test.ts",
+ "reason": "Uses CLI output",
+ "tests": ["app-dir static/dynamic handling should warn for too many cache tags"]
+ },
+ {
+ "file": "test/e2e/app-dir/parallel-routes-and-interception/parallel-routes-and-interception.test.ts",
+ "reason": "Tries to patch deployed files",
+ "tests": [
+ "parallel-routes-and-interception parallel routes should gracefully handle when two page segments match the `children` parallel slot"
+ ]
+ },
+ {
+ "file": "test/e2e/app-dir/rsc-basic/rsc-basic.test.ts",
+ "reason": "Tries to patch deployed files",
+ "tests": [
+ "app dir - rsc basics react@experimental should opt into the react@experimental when enabling ppr",
+ "app dir - rsc basics react@experimental should opt into the react@experimental when enabling taint"
+ ]
+ },
+ {
+ "file": "test/e2e/skip-trailing-slash-redirect/index.test.ts",
+ "reason": "Header whitespace mismatch",
+ "tests": [
+ "skip-trailing-slash-redirect should merge cookies from middleware and API routes correctly",
+ "skip-trailing-slash-redirect should merge cookies from middleware and edge API routes correctly",
+ "skip-trailing-slash-redirect should handle external rewrite correctly /chained-rewrite-ssr",
+ "skip-trailing-slash-redirect should handle external rewrite correctly /chained-rewrite-static",
+ "skip-trailing-slash-redirect should handle external rewrite correctly /chained-rewrite-ssg"
+ ]
+ },
+ {
+ "file": "test/e2e/module-layer/index.test.ts",
+ "reason": "Tries to patch deployed files",
+ "tests": [
+ "module layer no server-only in server targets should render routes marked with restriction marks without errors",
+ "module layer with server-only in server targets should render routes marked with restriction marks without errors"
+ ]
+ },
+ {
+ "file": "test/e2e/getserversideprops/test/index.test.ts",
+ "reason": "Header whitespace mismatch",
+ "tests": [
+ "getServerSideProps should set default caching header",
+ "getServerSideProps should respect custom caching header"
+ ]
+ },
+ {
+ "file": "test/e2e/app-dir/metadata-dynamic-routes/index.test.ts",
+ "reason": "Header whitespace mismatch",
+ "tests": [
+ "app dir - metadata dynamic routes text routes should handle robots.[ext] dynamic routes",
+ "app dir - metadata dynamic routes text routes should handle sitemap.[ext] dynamic routes",
+ "app dir - metadata dynamic routes social image routes should handle manifest.[ext] dynamic routes",
+ "app dir - metadata dynamic routes social image routes should render og image with opengraph-image dynamic routes",
+ "app dir - metadata dynamic routes social image routes should render og image with twitter-image dynamic routes",
+ "app dir - metadata dynamic routes icon image routes should render icon with dynamic routes",
+ "app dir - metadata dynamic routes icon image routes should render apple icon with dynamic routes",
+ "app dir - metadata dynamic routes should inject dynamic metadata properly to head",
+ "app dir - metadata dynamic routes should use localhost for local prod and fallback to deployment url when metadataBase is falsy"
+ ]
+ },
+ {
+ "file": "test/e2e/app-dir/metadata/metadata.test.ts",
+ "reason": "Hard-coded Vercel URL",
+ "tests": [
+ "app dir - metadata opengraph should pick up opengraph-image and twitter-image as static metadata files",
+ "app dir - metadata static routes should have /favicon.ico as route",
+ "app dir - metadata static routes should have icons as route"
+ ]
+ },
+ {
+ "file": "test/e2e/basepath.test.ts",
+ "reason": "Hard-coded Vercel error message",
+ "tests": [
+ "basePath should not update URL for a 404",
+ "basePath should handle 404 urls that start with basePath",
+ "basePath should show 404 for page not under the /docs prefix"
+ ]
+ },
+ {
+ "file": "test/e2e/app-dir/app/index.test.ts",
+ "reason": "Whitespace mismatch",
+ "tests": [
+ "app dir - basic should return the `vary` header from edge runtime",
+ "app dir - basic should return the `vary` header from pages for flight requests"
+ ]
+ },
+ {
+ "file": "test/e2e/app-dir/conflicting-page-segments/conflicting-page-segments.test.ts",
+ "reason": "Uses CLI output",
+ "tests": [
+ "conflicting-page-segments should throw an error when a route groups causes a conflict with a parallel segment"
+ ]
+ },
+ {
+ "file": "test/e2e/app-dir/actions-navigation/index.test.ts",
+ "reason": "Uses CLI output",
+ "tests": [
+ "app-dir action handling should handle actions correctly after following a relative link"
+ ]
+ },
+ {
+ "file": "test/e2e/middleware-general/test/index.test.ts",
+ "reason": "Uses CLI output",
+ "tests": [
+ "Middleware Runtime with i18n should redirect the same for direct visit and client-transition",
+ "Middleware Runtime without i18n should redirect the same for direct visit and client-transition",
+ {
+ "name": "Middleware Runtime with i18n should allow to abort a fetch request",
+ "reason": "Mismatched wording in runtime error message"
+ },
+ {
+ "name": "Middleware Runtime without i18n should allow to abort a fetch request",
+ "reason": "Mismatched wording in runtime error message"
+ },
+ {
+ "name": "Middleware Runtime with i18n with i18n allows to access env variables",
+ "reason": "Disabled for deploy tests"
+ },
+ {
+ "name": "Middleware Runtime without i18n with i18n allows to access env variables",
+ "reason": "Disabled for deploy tests"
+ }
+ ]
+ },
+ {
+ "file": "test/e2e/prerender.test.ts",
+ "reason": "Header whitespace mismatch",
+ "tests": [
+ "Prerender should handle on-demand revalidate for fallback: blocking",
+ "Prerender should use correct caching headers for a revalidate page",
+ "Prerender should use correct caching headers for a no-revalidate page",
+ {
+ "name": "Prerender should show warning when large amount of page data is returned",
+ "reason": "Uses CLI output"
+ }
+ ]
+ },
+ {
+ "file": "test/e2e/app-dir/app-routes/app-custom-route-base-path.test.ts",
+ "reason": "Uses CLI output",
+ "tests": [
+ "app-custom-routes no response returned should print an error when no response is returned",
+ "app-custom-routes error conditions responds with 400 (Bad Request) when the requested method is not a valid HTTP method"
+ ]
+ },
+ {
+ "file": "test/e2e/app-dir/app-routes/app-custom-routes.test.ts",
+ "reason": "Uses CLI output",
+ "tests": [
+ "app-custom-routes no response returned should print an error when no response is returned",
+ "app-custom-routes error conditions responds with 400 (Bad Request) when the requested method is not a valid HTTP method"
+ ]
+ },
+ {
+ "file": "test/e2e/app-dir/actions/app-action.test.ts",
+ "reason": "Uses CLI output",
+ "tests": [
+ "app-dir action handling should log a warning when a server action is not found but an id is provided",
+ "app-dir action handling should work with interception routes"
+ ]
+ }
+ ],
+ "failures": [
+ {
+ "name": "Middleware Runtime without i18n should trigger middleware for data requests",
+ "reason": "Requests for page data on pages router sites with middleware return HTML unless x-nextjs-data header is set",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/380"
+ },
+ {
+ "name": "Middleware Runtime with i18n should trigger middleware for data requests",
+ "reason": "Requests for page data on pages router sites with middleware return HTML unless x-nextjs-data header is set",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/380"
+ },
+ {
+ "name": "app dir - basic bootstrap scripts should successfully bootstrap even when using CSP",
+ "reason": "Nonce not automatically set in script tags when using CSP",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/381"
+ },
+ {
+ "name": "Middleware Runtime with i18n should validate & parse request url from a dynamic route with params",
+ "reason": "Middleware in sites with i18n generating incorrect request.url pathname",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/382"
+ },
+ {
+ "name": "Middleware Runtime with i18n should validate & parse request url from a dynamic route with params and no query",
+ "reason": "Middleware in sites with i18n generating incorrect request.url pathname",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/382"
+ },
+ {
+ "name": "i18n-ignore-rewrite-source-locale with basepath get public file by skipping locale in rewrite, locale: ",
+ "reason": "Middleware on sites with i18n cannot rewrite to static files",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/383"
+ },
+ {
+ "name": "i18n-ignore-rewrite-source-locale with basepath get public file by skipping locale in rewrite, locale: /en",
+ "reason": "Middleware on sites with i18n cannot rewrite to static files",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/383"
+ },
+ {
+ "name": "i18n-ignore-rewrite-source-locale with basepath get public file by skipping locale in rewrite, locale: /nl",
+ "reason": "Middleware on sites with i18n cannot rewrite to static files",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/383"
+ },
+ {
+ "name": "i18n-ignore-rewrite-source-locale with basepath get public file by skipping locale in rewrite, locale: /sv",
+ "reason": "Middleware on sites with i18n cannot rewrite to static files",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/383"
+ },
+ {
+ "name": "i18n-ignore-rewrite-source-locale get public file by skipping locale in rewrite, locale: ",
+ "reason": "Middleware on sites with i18n cannot rewrite to static files",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/383"
+ },
+ {
+ "name": "i18n-ignore-rewrite-source-locale get public file by skipping locale in rewrite, locale: /en",
+ "reason": "Middleware on sites with i18n cannot rewrite to static files",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/383"
+ },
+ {
+ "name": "i18n-ignore-rewrite-source-locale get public file by skipping locale in rewrite, locale: /nl",
+ "reason": "Middleware on sites with i18n cannot rewrite to static files",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/383"
+ },
+ {
+ "name": "i18n-ignore-rewrite-source-locale get public file by skipping locale in rewrite, locale: /sv",
+ "reason": "Middleware on sites with i18n cannot rewrite to static files",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/383"
+ },
+ {
+ "name": "Middleware Runtime trailing slash should keep non data requests in their original shape",
+ "reason": "Middleware should not add trailing slashes to non-data requests in static dir",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/385"
+ },
+ {
+ "name": "Middleware Redirect should implement internal redirects",
+ "reason": "Pages router middleware should return 302 status for redirected data requests",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/386"
+ },
+ {
+ "name": "Middleware Redirect /fr should implement internal redirects",
+ "reason": "Pages router middleware should return 302 status for redirected data requests",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/386"
+ },
+ {
+ "name": "Middleware Redirect should redirect to api route with locale",
+ "reason": "Pages router middleware should return 302 status for redirected data requests",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/386"
+ },
+ {
+ "name": "Middleware Redirect /fr should redirect to api route with locale",
+ "reason": "Pages router middleware should return 302 status for redirected data requests",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/386"
+ },
+ {
+ "name": "getServerSideProps should handle throw ENOENT correctly",
+ "reason": "Server error pages return encoded data without content-encoding header if accept-encoding is gzip",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/387"
+ },
+ {
+ "name": "app-custom-routes works with generateStaticParams correctly responds correctly on /static/three/data.json",
+ "reason": "First request for generateStaticParams fallback route handler returns base64-encoded content",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/388"
+ },
+ {
+ "name": "app-custom-routes works with generateStaticParams correctly revalidates correctly on /revalidate-1/three/data.json",
+ "reason": "First request for generateStaticParams fallback route handler returns base64-encoded content",
+ "link": "https://github.com/netlify/next-runtime-minimal/issues/388"
+ }
+ ]
+}
diff --git a/tools/deno/junit2json.ts b/tools/deno/junit2json.ts
new file mode 100644
index 0000000000..0337b5d09f
--- /dev/null
+++ b/tools/deno/junit2json.ts
@@ -0,0 +1,182 @@
+import { expandGlob } from 'https://deno.land/std/fs/mod.ts'
+import { parse } from 'https://deno.land/x/xml/mod.ts'
+
+import testConfig from '../../tests/test-config.json' with { type: 'json' }
+
+interface JUnitTestCase {
+ '@classname': string
+ '@name': string
+ '@time': number
+ '@file': string
+ failure?: string
+}
+
+interface JUnitTestSuite {
+ '@name': string
+ '@errors': number
+ '@failures': number
+ '@skipped': number
+ '@timestamp': string
+ '@time': number
+ '@tests': number
+ testcase: JUnitTestCase[]
+}
+
+interface JUnitTestSuites {
+ '@name': string
+ '@tests': number
+ '@failures': number
+ '@errors': number
+ '@time': number
+ testsuite: JUnitTestSuite[]
+}
+
+interface TestSuite {
+ name: string
+ file: string
+ passed: number
+ failed: number
+ skipped: number
+ testCases: TestCase[]
+}
+
+interface SkippedTestSuite {
+ file: string
+ reason: string
+ skipped: true
+}
+
+interface TestCase {
+ name: string
+ status: 'passed' | 'failed' | 'skipped'
+ reason?: string
+ link?: string
+}
+
+async function parseXMLFile(filePath: string): Promise<{ testsuites: JUnitTestSuites }> {
+ const xmlContent = await Deno.readTextFile(filePath)
+ return parse(xmlContent) as unknown as { testsuites: JUnitTestSuites }
+}
+
+const testCount = {
+ failed: 0,
+ skipped: 0,
+ passed: 0,
+}
+
+function junitToJson(xmlData: {
+ testsuites: JUnitTestSuites
+}): Array {
+ if (!xmlData.testsuites) {
+ return []
+ }
+
+ const testSuites = Array.isArray(xmlData.testsuites.testsuite)
+ ? xmlData.testsuites.testsuite
+ : [xmlData.testsuites.testsuite]
+
+ return testSuites.map((suite) => {
+ const { '@tests': tests, '@failures': failed, '@name': name } = suite
+
+ const passed = tests - failed - suite['@skipped']
+
+ const testCases = Array.isArray(suite.testcase) ? suite.testcase : [suite.testcase]
+
+ const testSuite: TestSuite = {
+ name,
+ file: testCases[0]?.['@file'],
+ passed,
+ failed,
+ skipped: 0,
+ testCases: [],
+ }
+ const skippedTests = testConfig.skipped.find(
+ (skippedTest) => skippedTest.file === testSuite.file,
+ )
+
+ testSuite.skipped = skippedTests?.tests?.length ?? 0
+
+ for (const testCase of testCases) {
+ if ('skipped' in testCase) {
+ continue
+ }
+ const status = testCase.failure ? 'failed' : 'passed'
+ testCount[status]++
+ const test: TestCase = {
+ name: testCase['@name'],
+ status,
+ }
+ if (status === 'failed') {
+ const failure = testConfig.failures.find((conf) => conf.name === test.name)
+ if (failure) {
+ test.reason = failure.reason
+ test.link = failure.link
+ }
+ }
+ testSuite.testCases.push(test)
+ }
+
+ if (skippedTests?.tests) {
+ testCount.skipped += skippedTests.tests.length
+ testSuite.testCases.push(
+ ...skippedTests.tests.map((test): TestCase => {
+ if (typeof test === 'string') {
+ return {
+ name: test,
+ status: 'skipped',
+ reason: skippedTests.reason,
+ }
+ }
+ return {
+ name: test.name,
+ status: 'skipped',
+ reason: test.reason,
+ }
+ }),
+ )
+ }
+ return testSuite
+ })
+}
+
+async function processJUnitFiles(
+ directoryPath: string,
+): Promise> {
+ const results = []
+ for await (const file of expandGlob(`${directoryPath}/**/*.xml`)) {
+ const xmlData = await parseXMLFile(file.path)
+ results.push(...junitToJson(xmlData))
+ }
+ const skippedSuites = testConfig.skipped.map(
+ ({ file, reason }): SkippedTestSuite => ({
+ file,
+ reason,
+ skipped: true,
+ }),
+ )
+
+ testCount.skipped += skippedSuites.length
+ results.push(...skippedSuites)
+ return results
+}
+
+// Get the directory path from the command-line arguments
+const directoryPath = Deno.args[0]
+
+// Check if the directory path is provided
+if (!directoryPath) {
+ console.error('Please provide a directory path.')
+ Deno.exit(1)
+}
+
+// Process the JUnit files in the provided directory
+const results = await processJUnitFiles(directoryPath)
+
+const testResults = {
+ ...testCount,
+ total: testCount.passed + testCount.failed + testCount.skipped,
+ passRate: ((testCount.passed / (testCount.passed + testCount.failed)) * 100).toFixed(2) + '%',
+ results,
+}
+
+console.log(JSON.stringify(testResults, undefined, 2))
From 035d0cc6e025ed851721a46a385f879eba9472c0 Mon Sep 17 00:00:00 2001
From: Michal Piechowiak
Date: Wed, 3 Apr 2024 11:26:50 +0200
Subject: [PATCH 2/9] chore: use separate GHA job for smoke tests (#393)
* chore: use separate GHA job for smoke tests
* chore: upgrade vitest
* chore: install deno for smoke tests job
* chore: actually run smoke tests in smoke tests job
---------
Co-authored-by: Rob Stanford
---
.github/workflows/run-tests.yml | 52 +-
package-lock.json | 1044 ++++++++-----------------------
package.json | 17 +-
vitest.config.ts | 12 +-
vitest.workspace.ts | 25 +
5 files changed, 327 insertions(+), 823 deletions(-)
create mode 100644 vitest.workspace.ts
diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml
index d50752a5c9..33126f12d5 100644
--- a/.github/workflows/run-tests.yml
+++ b/.github/workflows/run-tests.yml
@@ -95,7 +95,7 @@ jobs:
echo "version=$RESOLVED_VERSION" >> $GITHUB_OUTPUT
echo "Resolved Next.js version for 'next@${{ matrix.version }}' is '$RESOLVED_VERSION'"
- name: Run Playwright tests
- run: npm run e2e:ci -- --shard=${{ matrix.shard }}/4
+ run: npm run test:ci:e2e -- --shard=${{ matrix.shard }}/4
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_TOKEN }}
NEXT_VERSION: ${{ matrix.version }}
@@ -137,12 +137,6 @@ jobs:
run: npm ci
- name: 'Build'
run: npm run build
- - name: 'Netlify Login'
- env:
- NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_TOKEN }}
- run: |
- npm i -g netlify-cli
- netlify login
- name: Resolve Next.js version
id: resolve-next-version
shell: bash
@@ -172,13 +166,53 @@ jobs:
env:
NEXT_VERSION: ${{ matrix.version }}
NEXT_RESOLVED_VERSION: ${{ steps.resolve-next-version.outputs.version }}
- - name: 'Test'
- run: npm run test:ci -- --shard=${{ matrix.shard }}/8
+ - name: 'Unit and integration tests'
+ run: npm run test:ci:unit-and-integration -- --shard=${{ matrix.shard }}/8
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_TOKEN }}
NEXT_VERSION: ${{ matrix.version }}
NEXT_RESOLVED_VERSION: ${{ steps.resolve-next-version.outputs.version }}
TEMP: ${{ github.workspace }}/..
+
+ smoke:
+ if: always()
+ needs: setup
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ version: ${{ fromJson(needs.setup.outputs.matrix) }}
+ steps:
+ - uses: actions/checkout@v4
+ - name: 'Install Node'
+ uses: actions/setup-node@v4
+ with:
+ node-version: '18.x'
+ cache: 'npm'
+ cache-dependency-path: '**/package-lock.json'
+ - name: setup pnpm/yarn
+ run: corepack enable
+ shell: bash
+ - name: Install Deno
+ uses: denoland/setup-deno@v1
+ with:
+ # Should match the `DENO_VERSION_RANGE` from https://github.com/netlify/edge-bundler/blob/main/node/bridge.ts#L17
+ deno-version: v1.37.0
+ - name: 'Install dependencies'
+ run: npm ci
+ - name: 'Build'
+ run: npm run build
+ - name: 'Netlify Login'
+ env:
+ NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_TOKEN }}
+ run: |
+ npm i -g netlify-cli
+ netlify login
+ - name: 'Smoke tests'
+ run: npm run test:ci:smoke
+ env:
+ NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_TOKEN }}
+
merge-reports:
if: always()
needs: [setup,e2e]
diff --git a/package-lock.json b/package-lock.json
index d94d986ff7..4456a21a00 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -51,7 +51,7 @@
"typescript": "^5.1.6",
"unionfs": "^4.5.1",
"uuid": "^9.0.1",
- "vitest": "^1.2.2"
+ "vitest": "^1.4.0"
},
"engines": {
"node": ">=18.0.0"
@@ -5516,9 +5516,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.10.0.tgz",
- "integrity": "sha512-/MeDQmcD96nVoRumKUljsYOLqfv1YFJps+0pTrb2Z9Nl/w5qNUysMaWQsrd1mvAlNT4yza1iVyIu4Q4AgF6V3A==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.2.tgz",
+ "integrity": "sha512-3XFIDKWMFZrMnao1mJhnOT1h2g0169Os848NhhmGweEcfJ4rCi+3yMCOLG4zA61rbJdkcrM/DjVZm9Hg5p5w7g==",
"cpu": [
"arm"
],
@@ -5529,9 +5529,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.10.0.tgz",
- "integrity": "sha512-lvu0jK97mZDJdpZKDnZI93I0Om8lSDaiPx3OiCk0RXn3E8CMPJNS/wxjAvSJJzhhZpfjXsjLWL8LnS6qET4VNQ==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.2.tgz",
+ "integrity": "sha512-GdxxXbAuM7Y/YQM9/TwwP+L0omeE/lJAR1J+olu36c3LqqZEBdsIWeQ91KBe6nxwOnb06Xh7JS2U5ooWU5/LgQ==",
"cpu": [
"arm64"
],
@@ -5542,9 +5542,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.10.0.tgz",
- "integrity": "sha512-uFpayx8I8tyOvDkD7X6n0PriDRWxcqEjqgtlxnUA/G9oS93ur9aZ8c8BEpzFmsed1TH5WZNG5IONB8IiW90TQg==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.2.tgz",
+ "integrity": "sha512-mCMlpzlBgOTdaFs83I4XRr8wNPveJiJX1RLfv4hggyIVhfB5mJfN4P8Z6yKh+oE4Luz+qq1P3kVdWrCKcMYrrA==",
"cpu": [
"arm64"
],
@@ -5555,9 +5555,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.10.0.tgz",
- "integrity": "sha512-nIdCX03qFKoR/MwQegQBK+qZoSpO3LESurVAC6s6jazLA1Mpmgzo3Nj3H1vydXp/JM29bkCiuF7tDuToj4+U9Q==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.2.tgz",
+ "integrity": "sha512-yUoEvnH0FBef/NbB1u6d3HNGyruAKnN74LrPAfDQL3O32e3k3OSfLrPgSJmgb3PJrBZWfPyt6m4ZhAFa2nZp2A==",
"cpu": [
"x64"
],
@@ -5568,9 +5568,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.10.0.tgz",
- "integrity": "sha512-Fz7a+y5sYhYZMQFRkOyCs4PLhICAnxRX/GnWYReaAoruUzuRtcf+Qnw+T0CoAWbHCuz2gBUwmWnUgQ67fb3FYw==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.2.tgz",
+ "integrity": "sha512-GYbLs5ErswU/Xs7aGXqzc3RrdEjKdmoCrgzhJWyFL0r5fL3qd1NPcDKDowDnmcoSiGJeU68/Vy+OMUluRxPiLQ==",
"cpu": [
"arm"
],
@@ -5581,9 +5581,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.10.0.tgz",
- "integrity": "sha512-yPtF9jIix88orwfTi0lJiqINnlWo6p93MtZEoaehZnmCzEmLL0eqjA3eGVeyQhMtxdV+Mlsgfwhh0+M/k1/V7Q==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.2.tgz",
+ "integrity": "sha512-L1+D8/wqGnKQIlh4Zre9i4R4b4noxzH5DDciyahX4oOz62CphY7WDWqJoQ66zNR4oScLNOqQJfNSIAe/6TPUmQ==",
"cpu": [
"arm64"
],
@@ -5594,9 +5594,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.10.0.tgz",
- "integrity": "sha512-9GW9yA30ib+vfFiwjX+N7PnjTnCMiUffhWj4vkG4ukYv1kJ4T9gHNg8zw+ChsOccM27G9yXrEtMScf1LaCuoWQ==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.2.tgz",
+ "integrity": "sha512-tK5eoKFkXdz6vjfkSTCupUzCo40xueTOiOO6PeEIadlNBkadH1wNOH8ILCPIl8by/Gmb5AGAeQOFeLev7iZDOA==",
"cpu": [
"arm64"
],
@@ -5606,10 +5606,23 @@
"linux"
]
},
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.13.2.tgz",
+ "integrity": "sha512-zvXvAUGGEYi6tYhcDmb9wlOckVbuD+7z3mzInCSTACJ4DQrdSLPNUeDIcAQW39M3q6PDquqLWu7pnO39uSMRzQ==",
+ "cpu": [
+ "ppc64le"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.10.0.tgz",
- "integrity": "sha512-X1ES+V4bMq2ws5fF4zHornxebNxMXye0ZZjUrzOrf7UMx1d6wMQtfcchZ8SqUnQPPHdOyOLW6fTcUiFgHFadRA==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.2.tgz",
+ "integrity": "sha512-C3GSKvMtdudHCN5HdmAMSRYR2kkhgdOfye4w0xzyii7lebVr4riCgmM6lRiSCnJn2w1Xz7ZZzHKuLrjx5620kw==",
"cpu": [
"riscv64"
],
@@ -5619,10 +5632,23 @@
"linux"
]
},
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.13.2.tgz",
+ "integrity": "sha512-l4U0KDFwzD36j7HdfJ5/TveEQ1fUTjFFQP5qIt9gBqBgu1G8/kCaq5Ok05kd5TG9F8Lltf3MoYsUMw3rNlJ0Yg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.10.0.tgz",
- "integrity": "sha512-w/5OpT2EnI/Xvypw4FIhV34jmNqU5PZjZue2l2Y3ty1Ootm3SqhI+AmfhlUYGBTd9JnpneZCDnt3uNOiOBkMyw==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.2.tgz",
+ "integrity": "sha512-xXMLUAMzrtsvh3cZ448vbXqlUa7ZL8z0MwHp63K2IIID2+DeP5iWIT6g1SN7hg1VxPzqx0xZdiDM9l4n9LRU1A==",
"cpu": [
"x64"
],
@@ -5633,9 +5659,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.10.0.tgz",
- "integrity": "sha512-q/meftEe3QlwQiGYxD9rWwB21DoKQ9Q8wA40of/of6yGHhZuGfZO0c3WYkN9dNlopHlNT3mf5BPsUSxoPuVQaw==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.2.tgz",
+ "integrity": "sha512-M/JYAWickafUijWPai4ehrjzVPKRCyDb1SLuO+ZyPfoXgeCEAlgPkNXewFZx0zcnoIe3ay4UjXIMdXQXOZXWqA==",
"cpu": [
"x64"
],
@@ -5646,9 +5672,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.10.0.tgz",
- "integrity": "sha512-NrR6667wlUfP0BHaEIKgYM/2va+Oj+RjZSASbBMnszM9k+1AmliRjHc3lJIiOehtSSjqYiO7R6KLNrWOX+YNSQ==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.2.tgz",
+ "integrity": "sha512-2YWwoVg9KRkIKaXSh0mz3NmfurpmYoBBTAXA9qt7VXk0Xy12PoOP40EFuau+ajgALbbhi4uTj3tSG3tVseCjuA==",
"cpu": [
"arm64"
],
@@ -5659,9 +5685,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.10.0.tgz",
- "integrity": "sha512-FV0Tpt84LPYDduIDcXvEC7HKtyXxdvhdAOvOeWMWbQNulxViH2O07QXkT/FffX4FqEI02jEbCJbr+YcuKdyyMg==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.2.tgz",
+ "integrity": "sha512-2FSsE9aQ6OWD20E498NYKEQLneShWes0NGMPQwxWOdws35qQXH+FplabOSP5zEe1pVjurSDOGEVCE2agFwSEsw==",
"cpu": [
"ia32"
],
@@ -5672,9 +5698,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.10.0.tgz",
- "integrity": "sha512-OZoJd+o5TaTSQeFFQ6WjFCiltiYVjIdsXxwu/XZ8qRpsvMQr4UsVrE5UyT9RIvsnuF47DqkJKhhVZ2Q9YW9IpQ==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.2.tgz",
+ "integrity": "sha512-7h7J2nokcdPePdKykd8wtc8QqqkqxIrUz7MHj6aNr8waBRU//NLDVnNjQnqQO6fqtjrtCdftpbTuOKAyrAQETQ==",
"cpu": [
"x64"
],
@@ -6202,13 +6228,13 @@
}
},
"node_modules/@vitest/expect": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz",
- "integrity": "sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.4.0.tgz",
+ "integrity": "sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==",
"dev": true,
"dependencies": {
- "@vitest/spy": "1.3.1",
- "@vitest/utils": "1.3.1",
+ "@vitest/spy": "1.4.0",
+ "@vitest/utils": "1.4.0",
"chai": "^4.3.10"
},
"funding": {
@@ -6216,12 +6242,12 @@
}
},
"node_modules/@vitest/runner": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.1.tgz",
- "integrity": "sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.4.0.tgz",
+ "integrity": "sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==",
"dev": true,
"dependencies": {
- "@vitest/utils": "1.3.1",
+ "@vitest/utils": "1.4.0",
"p-limit": "^5.0.0",
"pathe": "^1.1.1"
},
@@ -6245,9 +6271,9 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.1.tgz",
- "integrity": "sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.4.0.tgz",
+ "integrity": "sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==",
"dev": true,
"dependencies": {
"magic-string": "^0.30.5",
@@ -6291,9 +6317,9 @@
"dev": true
},
"node_modules/@vitest/spy": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz",
- "integrity": "sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.4.0.tgz",
+ "integrity": "sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==",
"dev": true,
"dependencies": {
"tinyspy": "^2.2.0"
@@ -6303,9 +6329,9 @@
}
},
"node_modules/@vitest/utils": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.1.tgz",
- "integrity": "sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.4.0.tgz",
+ "integrity": "sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==",
"dev": true,
"dependencies": {
"diff-sequences": "^29.6.3",
@@ -15818,9 +15844,9 @@
}
},
"node_modules/rollup": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.10.0.tgz",
- "integrity": "sha512-t2v9G2AKxcQ8yrG+WGxctBes1AomT0M4ND7jTFBCVPXQ/WFTvNSefIrNSmLKhIKBrvN8SG+CZslimJcT3W2u2g==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.2.tgz",
+ "integrity": "sha512-MIlLgsdMprDBXC+4hsPgzWUasLO9CE4zOkj/u6j+Z6j5A4zRY+CtiXAdJyPtgCsc42g658Aeh1DlrdVEJhsL2g==",
"dev": true,
"dependencies": {
"@types/estree": "1.0.5"
@@ -15833,19 +15859,21 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.10.0",
- "@rollup/rollup-android-arm64": "4.10.0",
- "@rollup/rollup-darwin-arm64": "4.10.0",
- "@rollup/rollup-darwin-x64": "4.10.0",
- "@rollup/rollup-linux-arm-gnueabihf": "4.10.0",
- "@rollup/rollup-linux-arm64-gnu": "4.10.0",
- "@rollup/rollup-linux-arm64-musl": "4.10.0",
- "@rollup/rollup-linux-riscv64-gnu": "4.10.0",
- "@rollup/rollup-linux-x64-gnu": "4.10.0",
- "@rollup/rollup-linux-x64-musl": "4.10.0",
- "@rollup/rollup-win32-arm64-msvc": "4.10.0",
- "@rollup/rollup-win32-ia32-msvc": "4.10.0",
- "@rollup/rollup-win32-x64-msvc": "4.10.0",
+ "@rollup/rollup-android-arm-eabi": "4.13.2",
+ "@rollup/rollup-android-arm64": "4.13.2",
+ "@rollup/rollup-darwin-arm64": "4.13.2",
+ "@rollup/rollup-darwin-x64": "4.13.2",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.13.2",
+ "@rollup/rollup-linux-arm64-gnu": "4.13.2",
+ "@rollup/rollup-linux-arm64-musl": "4.13.2",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.13.2",
+ "@rollup/rollup-linux-riscv64-gnu": "4.13.2",
+ "@rollup/rollup-linux-s390x-gnu": "4.13.2",
+ "@rollup/rollup-linux-x64-gnu": "4.13.2",
+ "@rollup/rollup-linux-x64-musl": "4.13.2",
+ "@rollup/rollup-win32-arm64-msvc": "4.13.2",
+ "@rollup/rollup-win32-ia32-msvc": "4.13.2",
+ "@rollup/rollup-win32-x64-msvc": "4.13.2",
"fsevents": "~2.3.2"
}
},
@@ -16131,9 +16159,9 @@
}
},
"node_modules/source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
+ "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@@ -17246,14 +17274,14 @@
}
},
"node_modules/vite": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.1.tgz",
- "integrity": "sha512-wclpAgY3F1tR7t9LL5CcHC41YPkQIpKUGeIuT8MdNwNZr6OqOTLs7JX5vIHAtzqLWXts0T+GDrh9pN2arneKqg==",
+ "version": "5.2.7",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.7.tgz",
+ "integrity": "sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA==",
"dev": true,
"dependencies": {
- "esbuild": "^0.19.3",
- "postcss": "^8.4.35",
- "rollup": "^4.2.0"
+ "esbuild": "^0.20.1",
+ "postcss": "^8.4.38",
+ "rollup": "^4.13.0"
},
"bin": {
"vite": "bin/vite.js"
@@ -17301,9 +17329,9 @@
}
},
"node_modules/vite-node": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.1.tgz",
- "integrity": "sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.4.0.tgz",
+ "integrity": "sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==",
"dev": true,
"dependencies": {
"cac": "^6.7.14",
@@ -17322,416 +17350,10 @@
"url": "https://opencollective.com/vitest"
}
},
- "node_modules/vite/node_modules/@esbuild/aix-ppc64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
- "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "aix"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/android-arm": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz",
- "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/android-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz",
- "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/android-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz",
- "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/darwin-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz",
- "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/darwin-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz",
- "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/freebsd-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz",
- "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/freebsd-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz",
- "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-arm": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz",
- "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz",
- "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-ia32": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz",
- "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-loong64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz",
- "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-mips64el": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz",
- "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==",
- "cpu": [
- "mips64el"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-ppc64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz",
- "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-riscv64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz",
- "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-s390x": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz",
- "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz",
- "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/netbsd-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz",
- "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/openbsd-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz",
- "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/sunos-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz",
- "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/win32-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz",
- "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/win32-ia32": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz",
- "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/win32-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz",
- "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/esbuild": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
- "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
- "dev": true,
- "hasInstallScript": true,
- "bin": {
- "esbuild": "bin/esbuild"
- },
- "engines": {
- "node": ">=12"
- },
- "optionalDependencies": {
- "@esbuild/aix-ppc64": "0.19.12",
- "@esbuild/android-arm": "0.19.12",
- "@esbuild/android-arm64": "0.19.12",
- "@esbuild/android-x64": "0.19.12",
- "@esbuild/darwin-arm64": "0.19.12",
- "@esbuild/darwin-x64": "0.19.12",
- "@esbuild/freebsd-arm64": "0.19.12",
- "@esbuild/freebsd-x64": "0.19.12",
- "@esbuild/linux-arm": "0.19.12",
- "@esbuild/linux-arm64": "0.19.12",
- "@esbuild/linux-ia32": "0.19.12",
- "@esbuild/linux-loong64": "0.19.12",
- "@esbuild/linux-mips64el": "0.19.12",
- "@esbuild/linux-ppc64": "0.19.12",
- "@esbuild/linux-riscv64": "0.19.12",
- "@esbuild/linux-s390x": "0.19.12",
- "@esbuild/linux-x64": "0.19.12",
- "@esbuild/netbsd-x64": "0.19.12",
- "@esbuild/openbsd-x64": "0.19.12",
- "@esbuild/sunos-x64": "0.19.12",
- "@esbuild/win32-arm64": "0.19.12",
- "@esbuild/win32-ia32": "0.19.12",
- "@esbuild/win32-x64": "0.19.12"
- }
- },
"node_modules/vite/node_modules/postcss": {
- "version": "8.4.35",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
- "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
+ "version": "8.4.38",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
+ "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
"dev": true,
"funding": [
{
@@ -17750,23 +17372,23 @@
"dependencies": {
"nanoid": "^3.3.7",
"picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
+ "source-map-js": "^1.2.0"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/vitest": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz",
- "integrity": "sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.4.0.tgz",
+ "integrity": "sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==",
"dev": true,
"dependencies": {
- "@vitest/expect": "1.3.1",
- "@vitest/runner": "1.3.1",
- "@vitest/snapshot": "1.3.1",
- "@vitest/spy": "1.3.1",
- "@vitest/utils": "1.3.1",
+ "@vitest/expect": "1.4.0",
+ "@vitest/runner": "1.4.0",
+ "@vitest/snapshot": "1.4.0",
+ "@vitest/spy": "1.4.0",
+ "@vitest/utils": "1.4.0",
"acorn-walk": "^8.3.2",
"chai": "^4.3.10",
"debug": "^4.3.4",
@@ -17780,7 +17402,7 @@
"tinybench": "^2.5.1",
"tinypool": "^0.8.2",
"vite": "^5.0.0",
- "vite-node": "1.3.1",
+ "vite-node": "1.4.0",
"why-is-node-running": "^2.2.2"
},
"bin": {
@@ -17795,8 +17417,8 @@
"peerDependencies": {
"@edge-runtime/vm": "*",
"@types/node": "^18.0.0 || >=20.0.0",
- "@vitest/browser": "1.3.1",
- "@vitest/ui": "1.3.1",
+ "@vitest/browser": "1.4.0",
+ "@vitest/ui": "1.4.0",
"happy-dom": "*",
"jsdom": "*"
},
@@ -22165,93 +21787,107 @@
}
},
"@rollup/rollup-android-arm-eabi": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.10.0.tgz",
- "integrity": "sha512-/MeDQmcD96nVoRumKUljsYOLqfv1YFJps+0pTrb2Z9Nl/w5qNUysMaWQsrd1mvAlNT4yza1iVyIu4Q4AgF6V3A==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.2.tgz",
+ "integrity": "sha512-3XFIDKWMFZrMnao1mJhnOT1h2g0169Os848NhhmGweEcfJ4rCi+3yMCOLG4zA61rbJdkcrM/DjVZm9Hg5p5w7g==",
"dev": true,
"optional": true
},
"@rollup/rollup-android-arm64": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.10.0.tgz",
- "integrity": "sha512-lvu0jK97mZDJdpZKDnZI93I0Om8lSDaiPx3OiCk0RXn3E8CMPJNS/wxjAvSJJzhhZpfjXsjLWL8LnS6qET4VNQ==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.2.tgz",
+ "integrity": "sha512-GdxxXbAuM7Y/YQM9/TwwP+L0omeE/lJAR1J+olu36c3LqqZEBdsIWeQ91KBe6nxwOnb06Xh7JS2U5ooWU5/LgQ==",
"dev": true,
"optional": true
},
"@rollup/rollup-darwin-arm64": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.10.0.tgz",
- "integrity": "sha512-uFpayx8I8tyOvDkD7X6n0PriDRWxcqEjqgtlxnUA/G9oS93ur9aZ8c8BEpzFmsed1TH5WZNG5IONB8IiW90TQg==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.2.tgz",
+ "integrity": "sha512-mCMlpzlBgOTdaFs83I4XRr8wNPveJiJX1RLfv4hggyIVhfB5mJfN4P8Z6yKh+oE4Luz+qq1P3kVdWrCKcMYrrA==",
"dev": true,
"optional": true
},
"@rollup/rollup-darwin-x64": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.10.0.tgz",
- "integrity": "sha512-nIdCX03qFKoR/MwQegQBK+qZoSpO3LESurVAC6s6jazLA1Mpmgzo3Nj3H1vydXp/JM29bkCiuF7tDuToj4+U9Q==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.2.tgz",
+ "integrity": "sha512-yUoEvnH0FBef/NbB1u6d3HNGyruAKnN74LrPAfDQL3O32e3k3OSfLrPgSJmgb3PJrBZWfPyt6m4ZhAFa2nZp2A==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.10.0.tgz",
- "integrity": "sha512-Fz7a+y5sYhYZMQFRkOyCs4PLhICAnxRX/GnWYReaAoruUzuRtcf+Qnw+T0CoAWbHCuz2gBUwmWnUgQ67fb3FYw==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.2.tgz",
+ "integrity": "sha512-GYbLs5ErswU/Xs7aGXqzc3RrdEjKdmoCrgzhJWyFL0r5fL3qd1NPcDKDowDnmcoSiGJeU68/Vy+OMUluRxPiLQ==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-arm64-gnu": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.10.0.tgz",
- "integrity": "sha512-yPtF9jIix88orwfTi0lJiqINnlWo6p93MtZEoaehZnmCzEmLL0eqjA3eGVeyQhMtxdV+Mlsgfwhh0+M/k1/V7Q==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.2.tgz",
+ "integrity": "sha512-L1+D8/wqGnKQIlh4Zre9i4R4b4noxzH5DDciyahX4oOz62CphY7WDWqJoQ66zNR4oScLNOqQJfNSIAe/6TPUmQ==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-arm64-musl": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.10.0.tgz",
- "integrity": "sha512-9GW9yA30ib+vfFiwjX+N7PnjTnCMiUffhWj4vkG4ukYv1kJ4T9gHNg8zw+ChsOccM27G9yXrEtMScf1LaCuoWQ==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.2.tgz",
+ "integrity": "sha512-tK5eoKFkXdz6vjfkSTCupUzCo40xueTOiOO6PeEIadlNBkadH1wNOH8ILCPIl8by/Gmb5AGAeQOFeLev7iZDOA==",
+ "dev": true,
+ "optional": true
+ },
+ "@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.13.2.tgz",
+ "integrity": "sha512-zvXvAUGGEYi6tYhcDmb9wlOckVbuD+7z3mzInCSTACJ4DQrdSLPNUeDIcAQW39M3q6PDquqLWu7pnO39uSMRzQ==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.10.0.tgz",
- "integrity": "sha512-X1ES+V4bMq2ws5fF4zHornxebNxMXye0ZZjUrzOrf7UMx1d6wMQtfcchZ8SqUnQPPHdOyOLW6fTcUiFgHFadRA==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.2.tgz",
+ "integrity": "sha512-C3GSKvMtdudHCN5HdmAMSRYR2kkhgdOfye4w0xzyii7lebVr4riCgmM6lRiSCnJn2w1Xz7ZZzHKuLrjx5620kw==",
+ "dev": true,
+ "optional": true
+ },
+ "@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.13.2.tgz",
+ "integrity": "sha512-l4U0KDFwzD36j7HdfJ5/TveEQ1fUTjFFQP5qIt9gBqBgu1G8/kCaq5Ok05kd5TG9F8Lltf3MoYsUMw3rNlJ0Yg==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-x64-gnu": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.10.0.tgz",
- "integrity": "sha512-w/5OpT2EnI/Xvypw4FIhV34jmNqU5PZjZue2l2Y3ty1Ootm3SqhI+AmfhlUYGBTd9JnpneZCDnt3uNOiOBkMyw==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.2.tgz",
+ "integrity": "sha512-xXMLUAMzrtsvh3cZ448vbXqlUa7ZL8z0MwHp63K2IIID2+DeP5iWIT6g1SN7hg1VxPzqx0xZdiDM9l4n9LRU1A==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-x64-musl": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.10.0.tgz",
- "integrity": "sha512-q/meftEe3QlwQiGYxD9rWwB21DoKQ9Q8wA40of/of6yGHhZuGfZO0c3WYkN9dNlopHlNT3mf5BPsUSxoPuVQaw==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.2.tgz",
+ "integrity": "sha512-M/JYAWickafUijWPai4ehrjzVPKRCyDb1SLuO+ZyPfoXgeCEAlgPkNXewFZx0zcnoIe3ay4UjXIMdXQXOZXWqA==",
"dev": true,
"optional": true
},
"@rollup/rollup-win32-arm64-msvc": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.10.0.tgz",
- "integrity": "sha512-NrR6667wlUfP0BHaEIKgYM/2va+Oj+RjZSASbBMnszM9k+1AmliRjHc3lJIiOehtSSjqYiO7R6KLNrWOX+YNSQ==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.2.tgz",
+ "integrity": "sha512-2YWwoVg9KRkIKaXSh0mz3NmfurpmYoBBTAXA9qt7VXk0Xy12PoOP40EFuau+ajgALbbhi4uTj3tSG3tVseCjuA==",
"dev": true,
"optional": true
},
"@rollup/rollup-win32-ia32-msvc": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.10.0.tgz",
- "integrity": "sha512-FV0Tpt84LPYDduIDcXvEC7HKtyXxdvhdAOvOeWMWbQNulxViH2O07QXkT/FffX4FqEI02jEbCJbr+YcuKdyyMg==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.2.tgz",
+ "integrity": "sha512-2FSsE9aQ6OWD20E498NYKEQLneShWes0NGMPQwxWOdws35qQXH+FplabOSP5zEe1pVjurSDOGEVCE2agFwSEsw==",
"dev": true,
"optional": true
},
"@rollup/rollup-win32-x64-msvc": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.10.0.tgz",
- "integrity": "sha512-OZoJd+o5TaTSQeFFQ6WjFCiltiYVjIdsXxwu/XZ8qRpsvMQr4UsVrE5UyT9RIvsnuF47DqkJKhhVZ2Q9YW9IpQ==",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.2.tgz",
+ "integrity": "sha512-7h7J2nokcdPePdKykd8wtc8QqqkqxIrUz7MHj6aNr8waBRU//NLDVnNjQnqQO6fqtjrtCdftpbTuOKAyrAQETQ==",
"dev": true,
"optional": true
},
@@ -22646,23 +22282,23 @@
}
},
"@vitest/expect": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz",
- "integrity": "sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.4.0.tgz",
+ "integrity": "sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==",
"dev": true,
"requires": {
- "@vitest/spy": "1.3.1",
- "@vitest/utils": "1.3.1",
+ "@vitest/spy": "1.4.0",
+ "@vitest/utils": "1.4.0",
"chai": "^4.3.10"
}
},
"@vitest/runner": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.1.tgz",
- "integrity": "sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.4.0.tgz",
+ "integrity": "sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==",
"dev": true,
"requires": {
- "@vitest/utils": "1.3.1",
+ "@vitest/utils": "1.4.0",
"p-limit": "^5.0.0",
"pathe": "^1.1.1"
},
@@ -22679,9 +22315,9 @@
}
},
"@vitest/snapshot": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.1.tgz",
- "integrity": "sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.4.0.tgz",
+ "integrity": "sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==",
"dev": true,
"requires": {
"magic-string": "^0.30.5",
@@ -22715,18 +22351,18 @@
}
},
"@vitest/spy": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz",
- "integrity": "sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.4.0.tgz",
+ "integrity": "sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==",
"dev": true,
"requires": {
"tinyspy": "^2.2.0"
}
},
"@vitest/utils": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.1.tgz",
- "integrity": "sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.4.0.tgz",
+ "integrity": "sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==",
"dev": true,
"requires": {
"diff-sequences": "^29.6.3",
@@ -29514,24 +29150,26 @@
}
},
"rollup": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.10.0.tgz",
- "integrity": "sha512-t2v9G2AKxcQ8yrG+WGxctBes1AomT0M4ND7jTFBCVPXQ/WFTvNSefIrNSmLKhIKBrvN8SG+CZslimJcT3W2u2g==",
- "dev": true,
- "requires": {
- "@rollup/rollup-android-arm-eabi": "4.10.0",
- "@rollup/rollup-android-arm64": "4.10.0",
- "@rollup/rollup-darwin-arm64": "4.10.0",
- "@rollup/rollup-darwin-x64": "4.10.0",
- "@rollup/rollup-linux-arm-gnueabihf": "4.10.0",
- "@rollup/rollup-linux-arm64-gnu": "4.10.0",
- "@rollup/rollup-linux-arm64-musl": "4.10.0",
- "@rollup/rollup-linux-riscv64-gnu": "4.10.0",
- "@rollup/rollup-linux-x64-gnu": "4.10.0",
- "@rollup/rollup-linux-x64-musl": "4.10.0",
- "@rollup/rollup-win32-arm64-msvc": "4.10.0",
- "@rollup/rollup-win32-ia32-msvc": "4.10.0",
- "@rollup/rollup-win32-x64-msvc": "4.10.0",
+ "version": "4.13.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.2.tgz",
+ "integrity": "sha512-MIlLgsdMprDBXC+4hsPgzWUasLO9CE4zOkj/u6j+Z6j5A4zRY+CtiXAdJyPtgCsc42g658Aeh1DlrdVEJhsL2g==",
+ "dev": true,
+ "requires": {
+ "@rollup/rollup-android-arm-eabi": "4.13.2",
+ "@rollup/rollup-android-arm64": "4.13.2",
+ "@rollup/rollup-darwin-arm64": "4.13.2",
+ "@rollup/rollup-darwin-x64": "4.13.2",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.13.2",
+ "@rollup/rollup-linux-arm64-gnu": "4.13.2",
+ "@rollup/rollup-linux-arm64-musl": "4.13.2",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.13.2",
+ "@rollup/rollup-linux-riscv64-gnu": "4.13.2",
+ "@rollup/rollup-linux-s390x-gnu": "4.13.2",
+ "@rollup/rollup-linux-x64-gnu": "4.13.2",
+ "@rollup/rollup-linux-x64-musl": "4.13.2",
+ "@rollup/rollup-win32-arm64-msvc": "4.13.2",
+ "@rollup/rollup-win32-ia32-msvc": "4.13.2",
+ "@rollup/rollup-win32-x64-msvc": "4.13.2",
"@types/estree": "1.0.5",
"fsevents": "~2.3.2"
}
@@ -29740,9 +29378,9 @@
"dev": true
},
"source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
+ "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
"dev": true
},
"source-map-support": {
@@ -30579,226 +30217,34 @@
}
},
"vite": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.1.tgz",
- "integrity": "sha512-wclpAgY3F1tR7t9LL5CcHC41YPkQIpKUGeIuT8MdNwNZr6OqOTLs7JX5vIHAtzqLWXts0T+GDrh9pN2arneKqg==",
+ "version": "5.2.7",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.7.tgz",
+ "integrity": "sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA==",
"dev": true,
"requires": {
- "esbuild": "^0.19.3",
+ "esbuild": "^0.20.1",
"fsevents": "~2.3.3",
- "postcss": "^8.4.35",
- "rollup": "^4.2.0"
+ "postcss": "^8.4.38",
+ "rollup": "^4.13.0"
},
"dependencies": {
- "@esbuild/aix-ppc64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
- "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/android-arm": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz",
- "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==",
- "dev": true,
- "optional": true
- },
- "@esbuild/android-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz",
- "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/android-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz",
- "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==",
- "dev": true,
- "optional": true
- },
- "@esbuild/darwin-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz",
- "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==",
- "dev": true,
- "optional": true
- },
- "@esbuild/darwin-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz",
- "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==",
- "dev": true,
- "optional": true
- },
- "@esbuild/freebsd-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz",
- "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/freebsd-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz",
- "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-arm": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz",
- "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz",
- "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-ia32": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz",
- "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-loong64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz",
- "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-mips64el": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz",
- "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-ppc64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz",
- "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-riscv64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz",
- "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-s390x": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz",
- "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz",
- "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/netbsd-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz",
- "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/openbsd-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz",
- "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==",
- "dev": true,
- "optional": true
- },
- "@esbuild/sunos-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz",
- "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/win32-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz",
- "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==",
- "dev": true,
- "optional": true
- },
- "@esbuild/win32-ia32": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz",
- "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/win32-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz",
- "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==",
- "dev": true,
- "optional": true
- },
- "esbuild": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
- "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
- "dev": true,
- "requires": {
- "@esbuild/aix-ppc64": "0.19.12",
- "@esbuild/android-arm": "0.19.12",
- "@esbuild/android-arm64": "0.19.12",
- "@esbuild/android-x64": "0.19.12",
- "@esbuild/darwin-arm64": "0.19.12",
- "@esbuild/darwin-x64": "0.19.12",
- "@esbuild/freebsd-arm64": "0.19.12",
- "@esbuild/freebsd-x64": "0.19.12",
- "@esbuild/linux-arm": "0.19.12",
- "@esbuild/linux-arm64": "0.19.12",
- "@esbuild/linux-ia32": "0.19.12",
- "@esbuild/linux-loong64": "0.19.12",
- "@esbuild/linux-mips64el": "0.19.12",
- "@esbuild/linux-ppc64": "0.19.12",
- "@esbuild/linux-riscv64": "0.19.12",
- "@esbuild/linux-s390x": "0.19.12",
- "@esbuild/linux-x64": "0.19.12",
- "@esbuild/netbsd-x64": "0.19.12",
- "@esbuild/openbsd-x64": "0.19.12",
- "@esbuild/sunos-x64": "0.19.12",
- "@esbuild/win32-arm64": "0.19.12",
- "@esbuild/win32-ia32": "0.19.12",
- "@esbuild/win32-x64": "0.19.12"
- }
- },
"postcss": {
- "version": "8.4.35",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
- "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
+ "version": "8.4.38",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
+ "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
"dev": true,
"requires": {
"nanoid": "^3.3.7",
"picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
+ "source-map-js": "^1.2.0"
}
}
}
},
"vite-node": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.1.tgz",
- "integrity": "sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.4.0.tgz",
+ "integrity": "sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==",
"dev": true,
"requires": {
"cac": "^6.7.14",
@@ -30809,16 +30255,16 @@
}
},
"vitest": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz",
- "integrity": "sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.4.0.tgz",
+ "integrity": "sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==",
"dev": true,
"requires": {
- "@vitest/expect": "1.3.1",
- "@vitest/runner": "1.3.1",
- "@vitest/snapshot": "1.3.1",
- "@vitest/spy": "1.3.1",
- "@vitest/utils": "1.3.1",
+ "@vitest/expect": "1.4.0",
+ "@vitest/runner": "1.4.0",
+ "@vitest/snapshot": "1.4.0",
+ "@vitest/spy": "1.4.0",
+ "@vitest/utils": "1.4.0",
"acorn-walk": "^8.3.2",
"chai": "^4.3.10",
"debug": "^4.3.4",
@@ -30832,7 +30278,7 @@
"tinybench": "^2.5.1",
"tinypool": "^0.8.2",
"vite": "^5.0.0",
- "vite-node": "1.3.1",
+ "vite-node": "1.4.0",
"why-is-node-running": "^2.2.2"
}
},
diff --git a/package.json b/package.json
index 188a42b1f5..d25524958f 100644
--- a/package.json
+++ b/package.json
@@ -15,17 +15,22 @@
"scripts": {
"prepack": "clean-package",
"postpack": "clean-package restore",
- "pretest": "npm run build && node tests/prepare.mjs",
+ "pretest": "npm run pretest:integration",
+ "pretest:integration": "npm run build && node tests/prepare.mjs",
"build": "node ./tools/build.js",
"build:watch": "node ./tools/build.js --watch",
"lint": "eslint --cache --format=codeframe --max-warnings=0 --ext .ts,.cts,.js src",
"format:fix": "prettier --write .",
"format:check": "prettier --check .",
"test": "vitest",
- "test:ci": "vitest run --reporter=default --retry=3",
- "typecheck": "tsc --noEmit",
- "e2e": "playwright test",
- "e2e:ci": "playwright test"
+ "test:unit": "vitest run --project unit",
+ "test:integration": "vitest run --project integration",
+ "test:smoke": "vitest run --project smoke",
+ "test:e2e": "playwright test",
+ "test:ci:unit-and-integration": "vitest run --reporter=default --retry=3 --project=unit --project=integration",
+ "test:ci:smoke": "vitest run --reporter=default --retry=3 --project=smoke",
+ "test:ci:e2e": "playwright test",
+ "typecheck": "tsc --noEmit"
},
"repository": {
"type": "git",
@@ -85,7 +90,7 @@
"typescript": "^5.1.6",
"unionfs": "^4.5.1",
"uuid": "^9.0.1",
- "vitest": "^1.2.2"
+ "vitest": "^1.4.0"
},
"clean-package": {
"indent": 2,
diff --git a/vitest.config.ts b/vitest.config.ts
index 54e601b49b..c16ca3e575 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -1,5 +1,4 @@
import { join, relative } from 'node:path'
-import { platform } from 'node:process'
import { defineConfig } from 'vitest/config'
import { BaseSequencer, WorkspaceSpec } from 'vitest/node'
@@ -12,11 +11,8 @@ const RUN_ISOLATED = new Set([
join('tests', 'integration', 'revalidate-path.test.ts'),
join('tests', 'integration', 'cache-handler.test.ts'),
join('tests', 'integration', 'edge-handler.test.ts'),
- join('tests', 'smoke', 'deploy.test.ts'),
])
-const SKIP = new Set(platform === 'win32' ? [join('tests', 'smoke', 'deploy.test.ts')] : [])
-
class Sequencer extends BaseSequencer {
async shard(projects: WorkspaceSpec[]): Promise {
const {
@@ -36,12 +32,10 @@ Increasing the node count of the sharding to --shard 1/${RUN_ISOLATED.size}`,
)
}
- const notSkipped = projects.filter((project) => !SKIP.has(relative(process.cwd(), project[1])))
-
- const specialTests = notSkipped.filter((project) =>
+ const specialTests = projects.filter((project) =>
RUN_ISOLATED.has(relative(process.cwd(), project[1])),
)
- const regularTests = notSkipped.filter(
+ const regularTests = projects.filter(
(project) => !RUN_ISOLATED.has(relative(process.cwd(), project[1])),
)
@@ -66,7 +60,7 @@ Increasing the node count of the sharding to --shard 1/${RUN_ISOLATED.size}`,
export default defineConfig({
root: '.',
test: {
- include: ['{tests/integration,tests/smoke,src}/**/*.test.ts'],
+ include: [],
globals: true,
restoreMocks: true,
clearMocks: true,
diff --git a/vitest.workspace.ts b/vitest.workspace.ts
new file mode 100644
index 0000000000..5418c5ecef
--- /dev/null
+++ b/vitest.workspace.ts
@@ -0,0 +1,25 @@
+import { defineWorkspace } from 'vitest/config'
+
+export default defineWorkspace([
+ {
+ extends: './vitest.config.ts',
+ test: {
+ name: 'unit',
+ include: ['src/**/*.test.ts'],
+ },
+ },
+ {
+ extends: './vitest.config.ts',
+ test: {
+ name: 'integration',
+ include: ['tests/integration/**/*.test.ts'],
+ },
+ },
+ {
+ extends: './vitest.config.ts',
+ test: {
+ name: 'smoke',
+ include: ['tests/smoke/**/*.test.ts'],
+ },
+ },
+])
From 3578bf1a42b311c40825ff258c678fa093b5ec9c Mon Sep 17 00:00:00 2001
From: Michal Piechowiak
Date: Wed, 3 Apr 2024 17:15:53 +0200
Subject: [PATCH 3/9] test: add integration tests for pages router custom 404
(#379)
* test: add integration tests for pages router custom 404
* test: more detailed test name and some extra comments explaining locale assertions
* test: add assertion failure messages to provide more contextual information
---
.../page-router-base-path-i18n/pages/404.js | 16 +++++++
tests/integration/page-router.test.ts | 44 +++++++++++++++++++
2 files changed, 60 insertions(+)
create mode 100644 tests/fixtures/page-router-base-path-i18n/pages/404.js
diff --git a/tests/fixtures/page-router-base-path-i18n/pages/404.js b/tests/fixtures/page-router-base-path-i18n/pages/404.js
new file mode 100644
index 0000000000..0f42ed27ed
--- /dev/null
+++ b/tests/fixtures/page-router-base-path-i18n/pages/404.js
@@ -0,0 +1,16 @@
+export default function NotFound({ locale }) {
+ return (
+
+ Custom 404 page for locale:
{locale}
+
+ )
+}
+
+/** @type {import('next').GetStaticProps} */
+export const getStaticProps = ({ locale }) => {
+ return {
+ props: {
+ locale,
+ },
+ }
+}
diff --git a/tests/integration/page-router.test.ts b/tests/integration/page-router.test.ts
index 5ea9bb6ff2..121dbe7ad0 100644
--- a/tests/integration/page-router.test.ts
+++ b/tests/integration/page-router.test.ts
@@ -129,3 +129,47 @@ test.skipIf(platform === 'win32')(
expect(response.headers?.['cache-control']).toBe('public, max-age=0, must-revalidate')
},
)
+
+test('Should serve correct locale-aware custom 404 pages', async (ctx) => {
+ await createFixture('page-router-base-path-i18n', ctx)
+ await runPlugin(ctx)
+
+ const responseImplicitDefaultLocale = await invokeFunction(ctx, {
+ url: '/base/path/not-existing-page',
+ })
+
+ expect(
+ responseImplicitDefaultLocale.statusCode,
+ 'Response for not existing route if locale is not explicitly used in pathname (after basePath) should have 404 status',
+ ).toBe(404)
+ expect(
+ load(responseImplicitDefaultLocale.body)('[data-testid="locale"]').text(),
+ 'Served 404 page content should use default locale if locale is not explicitly used in pathname (after basePath)',
+ ).toBe('en')
+
+ const responseExplicitDefaultLocale = await invokeFunction(ctx, {
+ url: '/base/path/en/not-existing-page',
+ })
+
+ expect(
+ responseExplicitDefaultLocale.statusCode,
+ 'Response for not existing route if default locale is explicitly used in pathname (after basePath) should have 404 status',
+ ).toBe(404)
+ expect(
+ load(responseExplicitDefaultLocale.body)('[data-testid="locale"]').text(),
+ 'Served 404 page content should use default locale if default locale is explicitly used in pathname (after basePath)',
+ ).toBe('en')
+
+ const responseNonDefaultLocale = await invokeFunction(ctx, {
+ url: '/base/path/fr/not-existing-page',
+ })
+
+ expect(
+ responseNonDefaultLocale.statusCode,
+ 'Response for not existing route if non-default locale is explicitly used in pathname (after basePath) should have 404 status',
+ ).toBe(404)
+ expect(
+ load(responseNonDefaultLocale.body)('[data-testid="locale"]').text(),
+ 'Served 404 page content should use non-default locale if non-default locale is explicitly used in pathname (after basePath)',
+ ).toBe('fr')
+})
From f4c588c2aa01bebf36a87e8a3800b775a638e543 Mon Sep 17 00:00:00 2001
From: Michal Piechowiak
Date: Mon, 8 Apr 2024 19:52:00 +0200
Subject: [PATCH 4/9] feat: add cdn-cache-control headers to cacheable route
handler responses (#399)
* test: add test cases for cacheable route handlers
* refactor: add cache related types modules and adjust ROUTE variant to match our current usage
* feat: add cdn-cache-control headers to cacheable route handler responses
* fix: set revalidate setting on request context for Route responses and set cdn-cache-control header based on that
* chore: format with prettier
* chore: pass just revalidate time not entire meta
---------
Co-authored-by: pieh
---
src/build/content/prerendered.ts | 30 ++++++----
src/run/handlers/cache.cts | 57 ++++++++++++-------
src/run/handlers/request-context.cts | 3 +
src/run/headers.ts | 19 +++++++
src/shared/cache-types.cts | 34 +++++++++++
.../app/api/cached-permanent/route.js | 11 ++++
.../app/api/cached-revalidate/route.js | 11 ++++
tests/integration/simple-app.test.ts | 31 ++++++++++
8 files changed, 166 insertions(+), 30 deletions(-)
create mode 100644 src/shared/cache-types.cts
create mode 100644 tests/fixtures/simple-next-app/app/api/cached-permanent/route.js
create mode 100644 tests/fixtures/simple-next-app/app/api/cached-revalidate/route.js
diff --git a/src/build/content/prerendered.ts b/src/build/content/prerendered.ts
index 309f09fbe3..d8d514d74a 100644
--- a/src/build/content/prerendered.ts
+++ b/src/build/content/prerendered.ts
@@ -5,17 +5,18 @@ import { join } from 'node:path'
import { trace } from '@opentelemetry/api'
import { wrapTracer } from '@opentelemetry/api/experimental'
import { glob } from 'fast-glob'
-import type { CacheHandlerValue } from 'next/dist/server/lib/incremental-cache/index.js'
-import type { IncrementalCacheValue } from 'next/dist/server/response-cache/types.js'
import pLimit from 'p-limit'
import { encodeBlobKey } from '../../shared/blobkey.js'
+import type {
+ CachedFetchValue,
+ CachedPageValue,
+ NetlifyCacheHandlerValue,
+ NetlifyCachedRouteValue,
+ NetlifyIncrementalCacheValue,
+} from '../../shared/cache-types.cjs'
import type { PluginContext } from '../plugin-context.js'
-type CachedPageValue = Extract
-type CachedRouteValue = Extract
-type CachedFetchValue = Extract
-
const tracer = wrapTracer(trace.getTracer('Next runtime'))
/**
@@ -23,7 +24,7 @@ const tracer = wrapTracer(trace.getTracer('Next runtime'))
*/
const writeCacheEntry = async (
route: string,
- value: IncrementalCacheValue,
+ value: NetlifyIncrementalCacheValue,
lastModified: number,
ctx: PluginContext,
): Promise => {
@@ -31,7 +32,7 @@ const writeCacheEntry = async (
const entry = JSON.stringify({
lastModified,
value,
- } satisfies CacheHandlerValue)
+ } satisfies NetlifyCacheHandlerValue)
await writeFile(path, entry, 'utf-8')
}
@@ -68,10 +69,14 @@ const buildAppCacheValue = async (path: string): Promise => {
}
}
-const buildRouteCacheValue = async (path: string): Promise => ({
+const buildRouteCacheValue = async (
+ path: string,
+ initialRevalidateSeconds: number | false,
+): Promise => ({
kind: 'ROUTE',
body: await readFile(`${path}.body`, 'base64'),
...JSON.parse(await readFile(`${path}.meta`, 'utf-8')),
+ revalidate: initialRevalidateSeconds,
})
const buildFetchCacheValue = async (path: string): Promise => ({
@@ -100,7 +105,7 @@ export const copyPrerenderedContent = async (ctx: PluginContext): Promise
? Date.now() - 31536000000
: Date.now()
const key = routeToFilePath(route)
- let value: IncrementalCacheValue
+ let value: NetlifyIncrementalCacheValue
switch (true) {
// Parallel route default layout has no prerendered page
case meta.dataRoute?.endsWith('/default.rsc') &&
@@ -117,7 +122,10 @@ export const copyPrerenderedContent = async (ctx: PluginContext): Promise
value = await buildAppCacheValue(join(ctx.publishDir, 'server/app', key))
break
case meta.dataRoute === null:
- value = await buildRouteCacheValue(join(ctx.publishDir, 'server/app', key))
+ value = await buildRouteCacheValue(
+ join(ctx.publishDir, 'server/app', key),
+ meta.initialRevalidateSeconds,
+ )
break
default:
throw new Error(`Unrecognized content: ${route}`)
diff --git a/src/run/handlers/cache.cts b/src/run/handlers/cache.cts
index 71210d6e9a..0e232e474a 100644
--- a/src/run/handlers/cache.cts
+++ b/src/run/handlers/cache.cts
@@ -7,12 +7,15 @@ import { getDeployStore, Store } from '@netlify/blobs'
import { purgeCache } from '@netlify/functions'
import { type Span } from '@opentelemetry/api'
import { NEXT_CACHE_TAGS_HEADER } from 'next/dist/lib/constants.js'
+
import type {
CacheHandler,
CacheHandlerContext,
- CacheHandlerValue,
IncrementalCache,
-} from 'next/dist/server/lib/incremental-cache/index.js'
+ NetlifyCachedRouteValue,
+ NetlifyCacheHandlerValue,
+ NetlifyIncrementalCacheValue,
+} from '../../shared/cache-types.cjs'
import { getRequestContext } from './request-context.cjs'
import { getTracer } from './tracer.cjs'
@@ -43,7 +46,7 @@ export class NetlifyCacheHandler implements CacheHandler {
}
private captureResponseCacheLastModified(
- cacheValue: CacheHandlerValue,
+ cacheValue: NetlifyCacheHandlerValue,
key: string,
getCacheKeySpan: Span,
) {
@@ -90,6 +93,19 @@ export class NetlifyCacheHandler implements CacheHandler {
}
}
+ private captureRouteRevalidateAndRemoveFromObject(
+ cacheValue: NetlifyCachedRouteValue,
+ ): Omit {
+ const { revalidate, ...restOfRouteValue } = cacheValue
+
+ const requestContext = getRequestContext()
+ if (requestContext) {
+ requestContext.routeHandlerRevalidate = revalidate
+ }
+
+ return restOfRouteValue
+ }
+
async get(...args: Parameters): ReturnType {
return this.tracer.withActiveSpan('get cache key', async (span) => {
const [key, ctx = {}] = args
@@ -103,7 +119,7 @@ export class NetlifyCacheHandler implements CacheHandler {
return await this.blobStore.get(blobKey, {
type: 'json',
})
- })) as CacheHandlerValue | null
+ })) as NetlifyCacheHandlerValue | null
// if blob is null then we don't have a cache entry
if (!blob) {
@@ -128,15 +144,19 @@ export class NetlifyCacheHandler implements CacheHandler {
value: blob.value,
}
- case 'ROUTE':
+ case 'ROUTE': {
span.addEvent('ROUTE', { lastModified: blob.lastModified, status: blob.value.status })
+
+ const valueWithoutRevalidate = this.captureRouteRevalidateAndRemoveFromObject(blob.value)
+
return {
lastModified: blob.lastModified,
value: {
- ...blob.value,
- body: Buffer.from(blob.value.body as unknown as string, 'base64'),
+ ...valueWithoutRevalidate,
+ body: Buffer.from(valueWithoutRevalidate.body as unknown as string, 'base64'),
},
}
+ }
case 'PAGE':
span.addEvent('PAGE', { lastModified: blob.lastModified })
return {
@@ -152,23 +172,22 @@ export class NetlifyCacheHandler implements CacheHandler {
async set(...args: Parameters) {
return this.tracer.withActiveSpan('set cache key', async (span) => {
- const [key, data] = args
+ const [key, data, context] = args
const blobKey = await this.encodeBlobKey(key)
const lastModified = Date.now()
span.setAttributes({ key, lastModified, blobKey })
console.debug(`[NetlifyCacheHandler.set]: ${key}`)
- let value = data
-
- if (data?.kind === 'ROUTE') {
- // don't mutate data, as it's used for the initial response - instead create a new object
- value = {
- ...data,
- // @ts-expect-error gotta find a better solution for this
- body: data.body.toString('base64'),
- }
- }
+ const value: NetlifyIncrementalCacheValue | null =
+ data?.kind === 'ROUTE'
+ ? // don't mutate data, as it's used for the initial response - instead create a new object
+ {
+ ...data,
+ revalidate: context.revalidate,
+ body: data.body.toString('base64'),
+ }
+ : data
await this.blobStore.setJSON(blobKey, {
lastModified,
@@ -217,7 +236,7 @@ export class NetlifyCacheHandler implements CacheHandler {
* Checks if a cache entry is stale through on demand revalidated tags
*/
private async checkCacheEntryStaleByTags(
- cacheEntry: CacheHandlerValue,
+ cacheEntry: NetlifyCacheHandlerValue,
tags: string[] = [],
softTags: string[] = [],
) {
diff --git a/src/run/handlers/request-context.cts b/src/run/handlers/request-context.cts
index a2d9902214..28747a7d86 100644
--- a/src/run/handlers/request-context.cts
+++ b/src/run/handlers/request-context.cts
@@ -1,5 +1,7 @@
import { AsyncLocalStorage } from 'node:async_hooks'
+import type { NetlifyCachedRouteValue } from '../../shared/cache-types.cjs'
+
export type RequestContext = {
debug: boolean
responseCacheGetLastModified?: number
@@ -7,6 +9,7 @@ export type RequestContext = {
usedFsRead?: boolean
didPagesRouterOnDemandRevalidate?: boolean
serverTiming?: string
+ routeHandlerRevalidate?: NetlifyCachedRouteValue['revalidate']
}
type RequestContextAsyncLocalStorage = AsyncLocalStorage
diff --git a/src/run/headers.ts b/src/run/headers.ts
index e2f5ea092f..7af5522cb8 100644
--- a/src/run/headers.ts
+++ b/src/run/headers.ts
@@ -179,6 +179,22 @@ export const setCacheControlHeaders = (
request: Request,
requestContext: RequestContext,
) => {
+ if (
+ typeof requestContext.routeHandlerRevalidate !== 'undefined' &&
+ ['GET', 'HEAD'].includes(request.method) &&
+ !headers.has('netlify-cdn-cache-control')
+ ) {
+ // handle CDN Cache Control on Route Handler responses
+ const cdnCacheControl =
+ // if we are serving already stale response, instruct edge to not attempt to cache that response
+ headers.get('x-nextjs-cache') === 'STALE'
+ ? 'public, max-age=0, must-revalidate'
+ : `s-maxage=${requestContext.routeHandlerRevalidate === false ? 31536000 : requestContext.routeHandlerRevalidate}, stale-while-revalidate=31536000`
+
+ headers.set('netlify-cdn-cache-control', cdnCacheControl)
+ return
+ }
+
const cacheControl = headers.get('cache-control')
if (
cacheControl !== null &&
@@ -186,6 +202,7 @@ export const setCacheControlHeaders = (
!headers.has('cdn-cache-control') &&
!headers.has('netlify-cdn-cache-control')
) {
+ // handle CDN Cache Control on ISR and App Router page responses
const browserCacheControl = omitHeaderValues(cacheControl, [
's-maxage',
'stale-while-revalidate',
@@ -200,6 +217,7 @@ export const setCacheControlHeaders = (
headers.set('cache-control', browserCacheControl || 'public, max-age=0, must-revalidate')
headers.set('netlify-cdn-cache-control', cdnCacheControl)
+ return
}
if (
@@ -208,6 +226,7 @@ export const setCacheControlHeaders = (
!headers.has('netlify-cdn-cache-control') &&
requestContext.usedFsRead
) {
+ // handle CDN Cache Control on static files
headers.set('cache-control', 'public, max-age=0, must-revalidate')
headers.set('netlify-cdn-cache-control', `max-age=31536000`)
}
diff --git a/src/shared/cache-types.cts b/src/shared/cache-types.cts
new file mode 100644
index 0000000000..ee7b14fbfc
--- /dev/null
+++ b/src/shared/cache-types.cts
@@ -0,0 +1,34 @@
+import type {
+ CacheHandlerValue,
+ IncrementalCache,
+} from 'next/dist/server/lib/incremental-cache/index.js'
+import type {
+ IncrementalCacheValue,
+ CachedRouteValue,
+} from 'next/dist/server/response-cache/types.js'
+
+export type {
+ CacheHandler,
+ CacheHandlerContext,
+ IncrementalCache,
+} from 'next/dist/server/lib/incremental-cache/index.js'
+
+export type NetlifyCachedRouteValue = Omit & {
+ // Next.js stores body as buffer, while we store it as base64 encoded string
+ body: string
+ // Next.js doesn't produce cache-control tag we use to generate cdn cache control
+ // so store needed values as part of cached response data
+ revalidate: Parameters[2]['revalidate']
+}
+
+export type CachedPageValue = Extract
+export type CachedFetchValue = Extract
+
+export type NetlifyIncrementalCacheValue =
+ | Exclude
+ | NetlifyCachedRouteValue
+
+type CachedRouteValueToNetlify = T extends CachedRouteValue ? NetlifyCachedRouteValue : T
+type MapCachedRouteValueToNetlify = { [K in keyof T]: CachedRouteValueToNetlify }
+
+export type NetlifyCacheHandlerValue = MapCachedRouteValueToNetlify
diff --git a/tests/fixtures/simple-next-app/app/api/cached-permanent/route.js b/tests/fixtures/simple-next-app/app/api/cached-permanent/route.js
new file mode 100644
index 0000000000..15aefbaa6a
--- /dev/null
+++ b/tests/fixtures/simple-next-app/app/api/cached-permanent/route.js
@@ -0,0 +1,11 @@
+import { NextResponse } from 'next/server'
+
+export async function GET() {
+ return NextResponse.json({
+ message:
+ 'Route handler not using request and using force-static dynamic strategy with permanent caching',
+ })
+}
+export const revalidate = false
+
+export const dynamic = 'force-static'
diff --git a/tests/fixtures/simple-next-app/app/api/cached-revalidate/route.js b/tests/fixtures/simple-next-app/app/api/cached-revalidate/route.js
new file mode 100644
index 0000000000..e26c645379
--- /dev/null
+++ b/tests/fixtures/simple-next-app/app/api/cached-revalidate/route.js
@@ -0,0 +1,11 @@
+import { NextResponse } from 'next/server'
+
+export async function GET() {
+ return NextResponse.json({
+ message:
+ 'Route handler not using request and using force-static dynamic strategy with 15 seconds revalidate',
+ })
+}
+export const revalidate = 15
+
+export const dynamic = 'force-static'
diff --git a/tests/integration/simple-app.test.ts b/tests/integration/simple-app.test.ts
index da9ffa18f0..3fcf831b8b 100644
--- a/tests/integration/simple-app.test.ts
+++ b/tests/integration/simple-app.test.ts
@@ -57,6 +57,8 @@ test('Test that the simple next app is working', async (ctx)
const blobEntries = await getBlobEntries(ctx)
expect(blobEntries.map(({ key }) => decodeBlobKey(key)).sort()).toEqual([
'/404',
+ '/api/cached-permanent',
+ '/api/cached-revalidate',
'/image/local',
'/image/migration-from-v4-runtime',
'/image/remote-domain',
@@ -170,6 +172,35 @@ test('handlers can add cookies in route handlers with the co
expect(setCookieHeader).toContain('test2=value2; Path=/handler; HttpOnly')
})
+test('cacheable route handler is cached on cdn (revalidate=false / permanent caching)', async (ctx) => {
+ await createFixture('simple-next-app', ctx)
+ await runPlugin(ctx)
+
+ const permanentlyCachedResponse = await invokeFunction(ctx, { url: '/api/cached-permanent' })
+ expect(permanentlyCachedResponse.headers['netlify-cdn-cache-control']).toBe(
+ 's-maxage=31536000, stale-while-revalidate=31536000',
+ )
+})
+
+test('cacheable route handler is cached on cdn (revalidate=15)', async (ctx) => {
+ await createFixture('simple-next-app', ctx)
+ await runPlugin(ctx)
+
+ const firstTimeCachedResponse = await invokeFunction(ctx, { url: '/api/cached-revalidate' })
+ // this will be "stale" response from build
+ expect(firstTimeCachedResponse.headers['netlify-cdn-cache-control']).toBe(
+ 'public, max-age=0, must-revalidate',
+ )
+
+ // allow server to regenerate fresh response in background
+ await new Promise((res) => setTimeout(res, 1_000))
+
+ const secondTimeCachedResponse = await invokeFunction(ctx, { url: '/api/cached-revalidate' })
+ expect(secondTimeCachedResponse.headers['netlify-cdn-cache-control']).toBe(
+ 's-maxage=15, stale-while-revalidate=31536000',
+ )
+})
+
// there's a bug where requests accept-encoding header
// result in corrupted bodies
// while that bug stands, we want to ignore accept-encoding
From db5d4518bc98987db6ff682be38ec0f6670d7f9f Mon Sep 17 00:00:00 2001
From: Michal Piechowiak
Date: Wed, 10 Apr 2024 17:33:16 +0200
Subject: [PATCH 5/9] chore: add rule to prevent 'floating' promises (#375)
---
.eslintrc.cjs | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index dfd9cd09f8..2ea9578a7a 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -1,5 +1,6 @@
const { overrides } = require('@netlify/eslint-config-node')
+/** @type {import('eslint').Linter.Config} */
module.exports = {
extends: '@netlify/eslint-config-node',
parserOptions: {
@@ -33,6 +34,18 @@ module.exports = {
},
overrides: [
...overrides,
+ {
+ files: ['*.cts', '*mts', '*.ts', '*.tsx'],
+ excludedFiles: ['*.test.ts'],
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ ecmaVersion: 'latest',
+ project: true,
+ },
+ rules: {
+ '@typescript-eslint/no-floating-promises': 'error',
+ },
+ },
{
files: ['src/run/**'],
rules: {
From de18110a7367a7ead8e7cd0b1d9ce1c5cab9570a Mon Sep 17 00:00:00 2001
From: Michal Piechowiak
Date: Fri, 12 Apr 2024 14:01:13 +0200
Subject: [PATCH 6/9] test: adjust cleanup for next change (#405)
---
tests/utils/fixture.ts | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/tests/utils/fixture.ts b/tests/utils/fixture.ts
index c8c6da07d3..ec7e0c9dab 100644
--- a/tests/utils/fixture.ts
+++ b/tests/utils/fixture.ts
@@ -76,9 +76,17 @@ export const createFixture = async (fixture: string, ctx: FixtureTestContext) =>
// invocations would not use fetch-cache at all - this restores the original fetch
// and makes globalThis.fetch.__nextPatched falsy which will allow Next.js to apply
// needed patch
- // @ts-ignore fetch doesn't have __nextPatched property in types
- if (globalThis.fetch.__nextPatched && globalThis._nextOriginalFetch) {
- globalThis.fetch = globalThis._nextOriginalFetch
+ if (
+ // @ts-ignore fetch doesn't have __nextPatched property in types
+ globalThis.fetch.__nextPatched &&
+ // before https://github.com/vercel/next.js/pull/64088 original fetch was set on globalThis._nextOriginalFetch
+ // after it it is being set on globalThis.fetch._nextOriginalFetch
+ // so we check both to make sure tests continue to work regardless of next version
+ // @ts-ignore fetch doesn't have _nextOriginalFetch property in types
+ (globalThis._nextOriginalFetch || globalThis.fetch._nextOriginalFetch)
+ ) {
+ // @ts-ignore fetch doesn't have _nextOriginalFetch property in types
+ globalThis.fetch = globalThis._nextOriginalFetch || globalThis.fetch._nextOriginalFetch
}
ctx.cwd = await mkdtemp(join(tmpdir(), 'netlify-next-runtime-'))
From 9445b79ce658b94121a01831432ca4a281ff304c Mon Sep 17 00:00:00 2001
From: Tatyana <43764894+taty2010@users.noreply.github.com>
Date: Fri, 12 Apr 2024 13:03:30 -0500
Subject: [PATCH 7/9] test: update e2e skipped tests (#406)
* update skipped testt
* moved skipped test
---
tests/test-config.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/tests/test-config.json b/tests/test-config.json
index 036c458468..c6977ba353 100644
--- a/tests/test-config.json
+++ b/tests/test-config.json
@@ -26,7 +26,8 @@
"test/e2e/trailingslash-with-rewrite/index.test.ts",
"test/e2e/transpile-packages/index.test.ts",
"test/e2e/typescript-version-no-warning/typescript-version-no-warning.test.ts",
- "test/e2e/typescript-version-warning/typescript-version-warning.test.ts"
+ "test/e2e/typescript-version-warning/typescript-version-warning.test.ts",
+ "/test/e2e/revalidate-reason/revalidate-reason.test.ts"
],
"skipped": [
{
From 275f488de53b4eb1041812dd813ca2528e48bc02 Mon Sep 17 00:00:00 2001
From: Michal Piechowiak
Date: Tue, 16 Apr 2024 14:55:13 +0200
Subject: [PATCH 8/9] feat: fail the build when advanced api routes are used
(#403)
* test: add advanced routes fixture
* feat: fail the build when advanced api routes are used
* chore: update failBuild message with mention of migration and link to example
* test: add integration test for build failing error message when advanced api routes are used
* chore: drop console.logs inherited from v4 advanced api routes handling code
* fix: lint
* chore: use shortened link for migration example
* test: update assertion
* test: unrelated smoke test update
---
src/build/advanced-api-routes.ts | 188 ++++++++++++++++++
src/build/verification.ts | 18 ++
src/index.ts | 8 +-
.../advanced-api-routes/next-env.d.ts | 5 +
.../advanced-api-routes/next.config.js | 10 +
.../fixtures/advanced-api-routes/package.json | 19 ++
.../pages/api/hello-background.ts | 9 +
.../pages/api/hello-scheduled.js | 10 +
.../advanced-api-routes/tsconfig.json | 28 +++
tests/integration/advanced-api-routes.test.ts | 43 ++++
tests/utils/create-e2e-fixture.ts | 1 +
11 files changed, 338 insertions(+), 1 deletion(-)
create mode 100644 src/build/advanced-api-routes.ts
create mode 100644 tests/fixtures/advanced-api-routes/next-env.d.ts
create mode 100644 tests/fixtures/advanced-api-routes/next.config.js
create mode 100644 tests/fixtures/advanced-api-routes/package.json
create mode 100644 tests/fixtures/advanced-api-routes/pages/api/hello-background.ts
create mode 100644 tests/fixtures/advanced-api-routes/pages/api/hello-scheduled.js
create mode 100644 tests/fixtures/advanced-api-routes/tsconfig.json
create mode 100644 tests/integration/advanced-api-routes.test.ts
diff --git a/src/build/advanced-api-routes.ts b/src/build/advanced-api-routes.ts
new file mode 100644
index 0000000000..6cd024424f
--- /dev/null
+++ b/src/build/advanced-api-routes.ts
@@ -0,0 +1,188 @@
+import { existsSync } from 'node:fs'
+import { readFile } from 'node:fs/promises'
+import { join } from 'node:path'
+
+import type { PluginContext } from './plugin-context.js'
+
+interface FunctionsConfigManifest {
+ version: number
+ functions: Record>
+}
+
+// eslint-disable-next-line no-shadow
+export const enum ApiRouteType {
+ SCHEDULED = 'experimental-scheduled',
+ BACKGROUND = 'experimental-background',
+}
+
+interface ApiStandardConfig {
+ type?: never
+ runtime?: 'nodejs' | 'experimental-edge' | 'edge'
+ schedule?: never
+}
+
+interface ApiScheduledConfig {
+ type: ApiRouteType.SCHEDULED
+ runtime?: 'nodejs'
+ schedule: string
+}
+
+interface ApiBackgroundConfig {
+ type: ApiRouteType.BACKGROUND
+ runtime?: 'nodejs'
+ schedule?: never
+}
+
+type ApiConfig = ApiStandardConfig | ApiScheduledConfig | ApiBackgroundConfig
+
+export async function getAPIRoutesConfigs(ctx: PluginContext) {
+ const functionsConfigManifestPath = join(
+ ctx.publishDir,
+ 'server',
+ 'functions-config-manifest.json',
+ )
+ if (!existsSync(functionsConfigManifestPath)) {
+ // before https://github.com/vercel/next.js/pull/60163 this file might not have been produced if there were no API routes at all
+ return []
+ }
+
+ const functionsConfigManifest = JSON.parse(
+ await readFile(functionsConfigManifestPath, 'utf-8'),
+ ) as FunctionsConfigManifest
+
+ const appDir = ctx.resolveFromSiteDir('.')
+ const pagesDir = join(appDir, 'pages')
+ const srcPagesDir = join(appDir, 'src', 'pages')
+ const { pageExtensions } = ctx.requiredServerFiles.config
+
+ return Promise.all(
+ Object.keys(functionsConfigManifest.functions).map(async (apiRoute) => {
+ const filePath = getSourceFileForPage(apiRoute, [pagesDir, srcPagesDir], pageExtensions)
+
+ const sharedFields = {
+ apiRoute,
+ filePath,
+ config: {} as ApiConfig,
+ }
+
+ if (filePath) {
+ const config = await extractConfigFromFile(filePath, appDir)
+ return {
+ ...sharedFields,
+ config,
+ }
+ }
+
+ return sharedFields
+ }),
+ )
+}
+
+// Next.js already defines a default `pageExtensions` array in its `required-server-files.json` file
+// In case it gets `undefined`, this is a fallback
+const SOURCE_FILE_EXTENSIONS = ['js', 'jsx', 'ts', 'tsx']
+
+/**
+ * Find the source file for a given page route
+ */
+const getSourceFileForPage = (
+ page: string,
+ roots: string[],
+ pageExtensions = SOURCE_FILE_EXTENSIONS,
+) => {
+ for (const root of roots) {
+ for (const extension of pageExtensions) {
+ const file = join(root, `${page}.${extension}`)
+ if (existsSync(file)) {
+ return file
+ }
+
+ const fileAtFolderIndex = join(root, page, `index.${extension}`)
+ if (existsSync(fileAtFolderIndex)) {
+ return fileAtFolderIndex
+ }
+ }
+ }
+}
+
+/**
+ * Given an array of base paths and candidate modules, return the first one that exists
+ */
+const findModuleFromBase = ({
+ paths,
+ candidates,
+}: {
+ paths: string[]
+ candidates: string[]
+}): string | null => {
+ for (const candidate of candidates) {
+ try {
+ const modulePath = require.resolve(candidate, { paths })
+ if (modulePath) {
+ return modulePath
+ }
+ } catch {
+ // Ignore the error
+ }
+ }
+ // if we couldn't find a module from paths, let's try to resolve from here
+ for (const candidate of candidates) {
+ try {
+ const modulePath = require.resolve(candidate)
+ if (modulePath) {
+ return modulePath
+ }
+ } catch {
+ // Ignore the error
+ }
+ }
+ return null
+}
+
+let extractConstValue: typeof import('next/dist/build/analysis/extract-const-value.js')
+let parseModule: typeof import('next/dist/build/analysis/parse-module.js').parseModule
+
+const extractConfigFromFile = async (apiFilePath: string, appDir: string): Promise => {
+ if (!apiFilePath || !existsSync(apiFilePath)) {
+ return {}
+ }
+
+ const extractConstValueModulePath = findModuleFromBase({
+ paths: [appDir],
+ candidates: ['next/dist/build/analysis/extract-const-value'],
+ })
+
+ const parseModulePath = findModuleFromBase({
+ paths: [appDir],
+ candidates: ['next/dist/build/analysis/parse-module'],
+ })
+
+ if (!extractConstValueModulePath || !parseModulePath) {
+ // Old Next.js version
+ return {}
+ }
+
+ if (!extractConstValue && extractConstValueModulePath) {
+ // eslint-disable-next-line import/no-dynamic-require, n/global-require
+ extractConstValue = require(extractConstValueModulePath)
+ }
+ if (!parseModule && parseModulePath) {
+ // eslint-disable-next-line prefer-destructuring, @typescript-eslint/no-var-requires, import/no-dynamic-require, n/global-require
+ parseModule = require(parseModulePath).parseModule
+ }
+
+ const { extractExportedConstValue } = extractConstValue
+
+ const fileContent = await readFile(apiFilePath, 'utf8')
+ // No need to parse if there's no "config"
+ if (!fileContent.includes('config')) {
+ return {}
+ }
+ const ast = await parseModule(apiFilePath, fileContent)
+
+ try {
+ return extractExportedConstValue(ast, 'config') as ApiConfig
+ } catch {
+ return {}
+ }
+}
diff --git a/src/build/verification.ts b/src/build/verification.ts
index 50ac7a0bb0..658d712311 100644
--- a/src/build/verification.ts
+++ b/src/build/verification.ts
@@ -2,6 +2,7 @@ import { existsSync } from 'node:fs'
import { satisfies } from 'semver'
+import { ApiRouteType, getAPIRoutesConfigs } from './advanced-api-routes.js'
import type { PluginContext } from './plugin-context.js'
const SUPPORTED_NEXT_VERSIONS = '>=13.5.0'
@@ -66,3 +67,20 @@ export function verifyBuildConfig(ctx: PluginContext) {
)
}
}
+
+export async function verifyNoAdvancedAPIRoutes(ctx: PluginContext) {
+ const apiRoutesConfigs = await getAPIRoutesConfigs(ctx)
+
+ const unsupportedAPIRoutes = apiRoutesConfigs.filter((apiRouteConfig) => {
+ return (
+ apiRouteConfig.config.type === ApiRouteType.BACKGROUND ||
+ apiRouteConfig.config.type === ApiRouteType.SCHEDULED
+ )
+ })
+
+ if (unsupportedAPIRoutes.length !== 0) {
+ ctx.failBuild(
+ `@netlify/plugin-next@5 does not support advanced API routes. The following API routes should be migrated to Netlify background or scheduled functions:\n${unsupportedAPIRoutes.map((apiRouteConfig) => ` - ${apiRouteConfig.apiRoute} (type: "${apiRouteConfig.config.type}")`).join('\n')}\n\nRefer to https://ntl.fyi/next-scheduled-bg-function-migration as migration example.`,
+ )
+ }
+}
diff --git a/src/index.ts b/src/index.ts
index a9f312aa44..315a80af58 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -15,7 +15,11 @@ import { createEdgeHandlers } from './build/functions/edge.js'
import { createServerHandler } from './build/functions/server.js'
import { setImageConfig } from './build/image-cdn.js'
import { PluginContext } from './build/plugin-context.js'
-import { verifyBuildConfig, verifyPublishDir } from './build/verification.js'
+import {
+ verifyBuildConfig,
+ verifyNoAdvancedAPIRoutes,
+ verifyPublishDir,
+} from './build/verification.js'
const tracer = wrapTracer(trace.getTracer('Next.js runtime'))
@@ -48,6 +52,8 @@ export const onBuild = async (options: NetlifyPluginOptions) => {
return copyStaticExport(ctx)
}
+ await verifyNoAdvancedAPIRoutes(ctx)
+
await Promise.all([
copyStaticAssets(ctx),
copyStaticContent(ctx),
diff --git a/tests/fixtures/advanced-api-routes/next-env.d.ts b/tests/fixtures/advanced-api-routes/next-env.d.ts
new file mode 100644
index 0000000000..4f11a03dc6
--- /dev/null
+++ b/tests/fixtures/advanced-api-routes/next-env.d.ts
@@ -0,0 +1,5 @@
+///
+///
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/basic-features/typescript for more information.
diff --git a/tests/fixtures/advanced-api-routes/next.config.js b/tests/fixtures/advanced-api-routes/next.config.js
new file mode 100644
index 0000000000..6346ab0742
--- /dev/null
+++ b/tests/fixtures/advanced-api-routes/next.config.js
@@ -0,0 +1,10 @@
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+ output: 'standalone',
+ eslint: {
+ ignoreDuringBuilds: true,
+ },
+ generateBuildId: () => 'build-id',
+}
+
+module.exports = nextConfig
diff --git a/tests/fixtures/advanced-api-routes/package.json b/tests/fixtures/advanced-api-routes/package.json
new file mode 100644
index 0000000000..7cb8720db3
--- /dev/null
+++ b/tests/fixtures/advanced-api-routes/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "advanced-api-routes",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "postinstall": "next build",
+ "dev": "next dev",
+ "build": "next build"
+ },
+ "dependencies": {
+ "@netlify/functions": "^2.5.1",
+ "next": "latest",
+ "react": "18.2.0",
+ "react-dom": "18.2.0"
+ },
+ "devDependencies": {
+ "@types/react": "18.2.75"
+ }
+}
diff --git a/tests/fixtures/advanced-api-routes/pages/api/hello-background.ts b/tests/fixtures/advanced-api-routes/pages/api/hello-background.ts
new file mode 100644
index 0000000000..58d17922a7
--- /dev/null
+++ b/tests/fixtures/advanced-api-routes/pages/api/hello-background.ts
@@ -0,0 +1,9 @@
+export default (req, res) => {
+ res.setHeader('Content-Type', 'application/json')
+ res.status(200)
+ res.json({ message: 'hello world :)' })
+}
+
+export const config = {
+ type: 'experimental-background',
+}
diff --git a/tests/fixtures/advanced-api-routes/pages/api/hello-scheduled.js b/tests/fixtures/advanced-api-routes/pages/api/hello-scheduled.js
new file mode 100644
index 0000000000..e415230508
--- /dev/null
+++ b/tests/fixtures/advanced-api-routes/pages/api/hello-scheduled.js
@@ -0,0 +1,10 @@
+export default (req, res) => {
+ res.setHeader('Content-Type', 'application/json')
+ res.status(200)
+ res.json({ message: 'hello world :)' })
+}
+
+export const config = {
+ type: 'experimental-scheduled',
+ schedule: '@hourly',
+}
diff --git a/tests/fixtures/advanced-api-routes/tsconfig.json b/tests/fixtures/advanced-api-routes/tsconfig.json
new file mode 100644
index 0000000000..65348e831c
--- /dev/null
+++ b/tests/fixtures/advanced-api-routes/tsconfig.json
@@ -0,0 +1,28 @@
+{
+ "compilerOptions": {
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": false,
+ "noEmit": true,
+ "incremental": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve"
+ },
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
diff --git a/tests/integration/advanced-api-routes.test.ts b/tests/integration/advanced-api-routes.test.ts
new file mode 100644
index 0000000000..7eb66199b0
--- /dev/null
+++ b/tests/integration/advanced-api-routes.test.ts
@@ -0,0 +1,43 @@
+import { getLogger } from 'lambda-local'
+import { v4 } from 'uuid'
+import { beforeEach, vi, it, expect } from 'vitest'
+import { createFixture, runPlugin, type FixtureTestContext } from '../utils/fixture.js'
+import { generateRandomObjectID, startMockBlobStore } from '../utils/helpers.js'
+
+getLogger().level = 'alert'
+
+beforeEach(async (ctx) => {
+ // set for each test a new deployID and siteID
+ ctx.deployID = generateRandomObjectID()
+ ctx.siteID = v4()
+ vi.stubEnv('SITE_ID', ctx.siteID)
+ vi.stubEnv('DEPLOY_ID', ctx.deployID)
+ vi.stubEnv('NETLIFY_PURGE_API_TOKEN', 'fake-token')
+ // hide debug logs in tests
+ // vi.spyOn(console, 'debug').mockImplementation(() => {})
+
+ await startMockBlobStore(ctx)
+})
+
+it('test', async (ctx) => {
+ await createFixture('advanced-api-routes', ctx)
+
+ const runPluginPromise = runPlugin(ctx)
+
+ await expect(runPluginPromise).rejects.toThrow(
+ '@netlify/plugin-next@5 does not support advanced API routes. The following API routes should be migrated to Netlify background or scheduled functions:',
+ )
+
+ // list API routes to migrate
+ await expect(runPluginPromise).rejects.toThrow(
+ '/api/hello-scheduled (type: "experimental-scheduled")',
+ )
+ await expect(runPluginPromise).rejects.toThrow(
+ '/api/hello-background (type: "experimental-background")',
+ )
+
+ // links to migration example
+ await expect(runPluginPromise).rejects.toThrow(
+ 'Refer to https://ntl.fyi/next-scheduled-bg-function-migration as migration example.',
+ )
+})
diff --git a/tests/utils/create-e2e-fixture.ts b/tests/utils/create-e2e-fixture.ts
index a0a5d67f54..bec4dd56b4 100644
--- a/tests/utils/create-e2e-fixture.ts
+++ b/tests/utils/create-e2e-fixture.ts
@@ -318,6 +318,7 @@ export const fixtureFactories = {
buildCommand: 'yarn build',
publishDirectory: 'apps/site/.next',
smoke: true,
+ runtimeInstallationPath: '',
}),
npmMonorepoEmptyBaseNoPackagePath: () =>
createE2EFixture('npm-monorepo-empty-base', {
From e087bf70aef689fc7057ee2d5088473b278e5533 Mon Sep 17 00:00:00 2001
From: "token-generator-app[bot]"
<82042599+token-generator-app[bot]@users.noreply.github.com>
Date: Tue, 16 Apr 2024 15:43:50 +0200
Subject: [PATCH 9/9] chore(main): release 5.1.0 (#401)
Co-authored-by: token-generator-app[bot] <82042599+token-generator-app[bot]@users.noreply.github.com>
---
CHANGELOG.md | 8 ++++++++
package-lock.json | 4 ++--
package.json | 2 +-
3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e2b367cdbc..f9d1544b29 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## [5.1.0](https://github.com/netlify/next-runtime-minimal/compare/v5.0.0...v5.1.0) (2024-04-16)
+
+
+### Features
+
+* add cdn-cache-control headers to cacheable route handler responses ([#399](https://github.com/netlify/next-runtime-minimal/issues/399)) ([f4c588c](https://github.com/netlify/next-runtime-minimal/commit/f4c588c2aa01bebf36a87e8a3800b775a638e543))
+* fail the build when advanced api routes are used ([#403](https://github.com/netlify/next-runtime-minimal/issues/403)) ([275f488](https://github.com/netlify/next-runtime-minimal/commit/275f488de53b4eb1041812dd813ca2528e48bc02))
+
## [5.0.0](https://github.com/netlify/next-runtime-minimal/compare/v5.0.0-alpha.25...v5.0.0) (2024-04-02)
diff --git a/package-lock.json b/package-lock.json
index 4456a21a00..458fccd2fe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@netlify/plugin-nextjs",
- "version": "5.0.0",
+ "version": "5.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@netlify/plugin-nextjs",
- "version": "5.0.0",
+ "version": "5.1.0",
"license": "MIT",
"devDependencies": {
"@fastly/http-compute-js": "1.1.4",
diff --git a/package.json b/package.json
index d25524958f..b3bd6768f7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@netlify/plugin-nextjs",
- "version": "5.0.0",
+ "version": "5.1.0",
"description": "Run Next.js seamlessly on Netlify",
"main": "./dist/index.js",
"type": "module",