vinext 0.0.30 → 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -6
- package/dist/build/prerender.d.ts +188 -0
- package/dist/build/prerender.js +675 -0
- package/dist/build/prerender.js.map +1 -0
- package/dist/build/report.d.ts +45 -46
- package/dist/build/report.js +247 -276
- package/dist/build/report.js.map +1 -1
- package/dist/build/run-prerender.d.ts +62 -0
- package/dist/build/run-prerender.js +183 -0
- package/dist/build/run-prerender.js.map +1 -0
- package/dist/build/server-manifest.d.ts +19 -0
- package/dist/build/server-manifest.js +29 -0
- package/dist/build/server-manifest.js.map +1 -0
- package/dist/build/static-export.d.ts +51 -66
- package/dist/build/static-export.js +51 -545
- package/dist/build/static-export.js.map +1 -1
- package/dist/check.d.ts +26 -24
- package/dist/check.js +591 -571
- package/dist/check.js.map +1 -1
- package/dist/cli.d.ts +1 -15
- package/dist/cli.js +430 -491
- package/dist/cli.js.map +1 -1
- package/dist/client/entry.d.ts +1 -2
- package/dist/client/entry.js +49 -62
- package/dist/client/entry.js.map +1 -1
- package/dist/client/validate-module-path.d.ts +4 -1
- package/dist/client/validate-module-path.js +23 -28
- package/dist/client/validate-module-path.js.map +1 -1
- package/dist/client/vinext-next-data.d.ts +15 -20
- package/dist/client/vinext-next-data.js +0 -1
- package/dist/cloudflare/index.d.ts +3 -8
- package/dist/cloudflare/index.js +3 -8
- package/dist/cloudflare/kv-cache-handler.d.ts +95 -105
- package/dist/cloudflare/kv-cache-handler.js +354 -380
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/cloudflare/tpr.d.ts +36 -34
- package/dist/cloudflare/tpr.js +460 -603
- package/dist/cloudflare/tpr.js.map +1 -1
- package/dist/config/config-matchers.d.ts +31 -40
- package/dist/config/config-matchers.js +727 -936
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/config/dotenv.d.ts +18 -11
- package/dist/config/dotenv.js +79 -84
- package/dist/config/dotenv.js.map +1 -1
- package/dist/config/next-config.d.ts +156 -146
- package/dist/config/next-config.js +374 -464
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.d.ts +87 -96
- package/dist/deploy.js +490 -628
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-browser-entry.d.ts +4 -1
- package/dist/entries/app-browser-entry.js +12 -8
- package/dist/entries/app-browser-entry.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +33 -20
- package/dist/entries/app-rsc-entry.js +442 -211
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-ssr-entry.d.ts +9 -1
- package/dist/entries/app-ssr-entry.js +61 -28
- package/dist/entries/app-ssr-entry.js.map +1 -1
- package/dist/entries/pages-client-entry.d.ts +6 -2
- package/dist/entries/pages-client-entry.js +30 -33
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-entry-helpers.d.ts +5 -1
- package/dist/entries/pages-entry-helpers.js +17 -14
- package/dist/entries/pages-entry-helpers.js.map +1 -1
- package/dist/entries/pages-server-entry.d.ts +6 -2
- package/dist/entries/pages-server-entry.js +84 -113
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/index.d.ts +82 -62
- package/dist/index.js +2172 -3133
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +40 -37
- package/dist/init.js +201 -258
- package/dist/init.js.map +1 -1
- package/dist/plugins/async-hooks-stub.d.ts +7 -3
- package/dist/plugins/async-hooks-stub.js +39 -42
- package/dist/plugins/async-hooks-stub.js.map +1 -1
- package/dist/plugins/client-reference-dedup.d.ts +7 -3
- package/dist/plugins/client-reference-dedup.js +63 -88
- package/dist/plugins/client-reference-dedup.js.map +1 -1
- package/dist/routing/app-router.d.ts +100 -96
- package/dist/routing/app-router.js +560 -670
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.d.ts +18 -15
- package/dist/routing/file-matcher.js +65 -65
- package/dist/routing/file-matcher.js.map +1 -1
- package/dist/routing/pages-router.d.ts +23 -24
- package/dist/routing/pages-router.js +147 -172
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/routing/route-trie.d.ts +23 -20
- package/dist/routing/route-trie.js +131 -151
- package/dist/routing/route-trie.js.map +1 -1
- package/dist/routing/route-validation.d.ts +5 -2
- package/dist/routing/route-validation.js +98 -130
- package/dist/routing/route-validation.js.map +1 -1
- package/dist/routing/utils.d.ts +10 -7
- package/dist/routing/utils.js +75 -111
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.d.ts +8 -13
- package/dist/server/api-handler.js +161 -193
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-router-entry.d.ts +6 -16
- package/dist/server/app-router-entry.js +26 -54
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/dev-module-runner.d.ts +11 -64
- package/dist/server/dev-module-runner.js +89 -101
- package/dist/server/dev-module-runner.js.map +1 -1
- package/dist/server/dev-origin-check.d.ts +12 -10
- package/dist/server/dev-origin-check.js +98 -108
- package/dist/server/dev-origin-check.js.map +1 -1
- package/dist/server/dev-server.d.ts +17 -14
- package/dist/server/dev-server.js +542 -869
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/html.d.ts +4 -1
- package/dist/server/html.js +25 -26
- package/dist/server/html.js.map +1 -1
- package/dist/server/image-optimization.d.ts +31 -28
- package/dist/server/image-optimization.js +181 -210
- package/dist/server/image-optimization.js.map +1 -1
- package/dist/server/instrumentation.d.ts +25 -22
- package/dist/server/instrumentation.js +110 -122
- package/dist/server/instrumentation.js.map +1 -1
- package/dist/server/isr-cache.d.ts +16 -26
- package/dist/server/isr-cache.js +106 -128
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/metadata-routes.d.ts +85 -88
- package/dist/server/metadata-routes.js +270 -317
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-codegen.d.ts +7 -4
- package/dist/server/middleware-codegen.js +61 -61
- package/dist/server/middleware-codegen.js.map +1 -1
- package/dist/server/middleware-request-headers.d.ts +8 -6
- package/dist/server/middleware-request-headers.js +47 -65
- package/dist/server/middleware-request-headers.js.map +1 -1
- package/dist/server/middleware.d.ts +31 -47
- package/dist/server/middleware.js +273 -404
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/normalize-path.d.ts +4 -1
- package/dist/server/normalize-path.js +33 -47
- package/dist/server/normalize-path.js.map +1 -1
- package/dist/server/pages-i18n.d.ts +38 -30
- package/dist/server/pages-i18n.js +112 -139
- package/dist/server/pages-i18n.js.map +1 -1
- package/dist/server/prod-server.d.ts +19 -31
- package/dist/server/prod-server.js +714 -945
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-log.d.ts +18 -12
- package/dist/server/request-log.js +45 -52
- package/dist/server/request-log.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +9 -17
- package/dist/server/request-pipeline.js +133 -184
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/server/worker-utils.d.ts +4 -1
- package/dist/server/worker-utils.js +31 -37
- package/dist/server/worker-utils.js.map +1 -1
- package/dist/shims/amp.d.ts +5 -2
- package/dist/shims/amp.js +19 -15
- package/dist/shims/amp.js.map +1 -1
- package/dist/shims/app.d.ts +8 -10
- package/dist/shims/app.js +0 -1
- package/dist/shims/cache-runtime.d.ts +20 -45
- package/dist/shims/cache-runtime.js +271 -422
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +130 -121
- package/dist/shims/cache.js +339 -427
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/client-only.d.ts +1 -18
- package/dist/shims/client-only.js +0 -17
- package/dist/shims/compat-router.d.ts +4 -1
- package/dist/shims/compat-router.js +23 -19
- package/dist/shims/compat-router.js.map +1 -1
- package/dist/shims/config.d.ts +7 -5
- package/dist/shims/config.js +16 -23
- package/dist/shims/config.js.map +1 -1
- package/dist/shims/constants.d.ts +119 -118
- package/dist/shims/constants.js +159 -164
- package/dist/shims/constants.js.map +1 -1
- package/dist/shims/document.d.ts +20 -16
- package/dist/shims/document.js +41 -22
- package/dist/shims/document.js.map +1 -1
- package/dist/shims/dynamic.d.ts +13 -22
- package/dist/shims/dynamic.js +122 -136
- package/dist/shims/dynamic.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +22 -15
- package/dist/shims/error-boundary.js +81 -79
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/error.d.ts +11 -12
- package/dist/shims/error.js +35 -39
- package/dist/shims/error.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts +16 -14
- package/dist/shims/fetch-cache.js +437 -645
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/font-google-base.d.ts +28 -26
- package/dist/shims/font-google-base.js +238 -325
- package/dist/shims/font-google-base.js.map +1 -1
- package/dist/shims/font-google.d.ts +3 -3
- package/dist/shims/font-google.generated.d.ts +1928 -1924
- package/dist/shims/font-google.generated.js +1928 -2133
- package/dist/shims/font-google.generated.js.map +1 -1
- package/dist/shims/font-google.js +3 -3
- package/dist/shims/font-local.d.ts +28 -26
- package/dist/shims/font-local.js +204 -260
- package/dist/shims/font-local.js.map +1 -1
- package/dist/shims/form.d.ts +13 -27
- package/dist/shims/form.js +128 -180
- package/dist/shims/form.js.map +1 -1
- package/dist/shims/head-state.d.ts +8 -13
- package/dist/shims/head-state.js +25 -42
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/head.d.ts +16 -20
- package/dist/shims/head.js +172 -250
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/headers.d.ts +84 -78
- package/dist/shims/headers.js +447 -575
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/i18n-context.d.ts +16 -20
- package/dist/shims/i18n-context.js +35 -48
- package/dist/shims/i18n-context.js.map +1 -1
- package/dist/shims/i18n-state.d.ts +8 -14
- package/dist/shims/i18n-state.js +34 -42
- package/dist/shims/i18n-state.js.map +1 -1
- package/dist/shims/image-config.d.ts +11 -8
- package/dist/shims/image-config.js +50 -83
- package/dist/shims/image-config.js.map +1 -1
- package/dist/shims/image.d.ts +37 -46
- package/dist/shims/image.js +283 -308
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/api-utils.d.ts +7 -4
- package/dist/shims/internal/api-utils.js +0 -6
- package/dist/shims/internal/app-router-context.d.ts +22 -17
- package/dist/shims/internal/app-router-context.js +17 -13
- package/dist/shims/internal/app-router-context.js.map +1 -1
- package/dist/shims/internal/cookies.d.ts +2 -9
- package/dist/shims/internal/cookies.js +2 -9
- package/dist/shims/internal/parse-cookie-header.d.ts +4 -1
- package/dist/shims/internal/parse-cookie-header.js +29 -29
- package/dist/shims/internal/parse-cookie-header.js.map +1 -1
- package/dist/shims/internal/router-context.d.ts +6 -1
- package/dist/shims/internal/router-context.js +11 -7
- package/dist/shims/internal/router-context.js.map +1 -1
- package/dist/shims/internal/utils.d.ts +40 -37
- package/dist/shims/internal/utils.js +24 -30
- package/dist/shims/internal/utils.js.map +1 -1
- package/dist/shims/internal/work-unit-async-storage.d.ts +6 -10
- package/dist/shims/internal/work-unit-async-storage.js +14 -11
- package/dist/shims/internal/work-unit-async-storage.js.map +1 -1
- package/dist/shims/layout-segment-context.d.ts +11 -14
- package/dist/shims/layout-segment-context.js +24 -23
- package/dist/shims/layout-segment-context.js.map +1 -1
- package/dist/shims/legacy-image.d.ts +39 -46
- package/dist/shims/legacy-image.js +47 -42
- package/dist/shims/legacy-image.js.map +1 -1
- package/dist/shims/link.d.ts +32 -36
- package/dist/shims/link.js +255 -391
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +210 -202
- package/dist/shims/metadata.js +545 -546
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation-state.d.ts +10 -18
- package/dist/shims/navigation-state.js +66 -74
- package/dist/shims/navigation-state.js.map +1 -1
- package/dist/shims/navigation.d.ts +59 -63
- package/dist/shims/navigation.js +505 -704
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/og.d.ts +2 -20
- package/dist/shims/og.js +2 -19
- package/dist/shims/readonly-url-search-params.d.ts +8 -5
- package/dist/shims/readonly-url-search-params.js +26 -22
- package/dist/shims/readonly-url-search-params.js.map +1 -1
- package/dist/shims/request-context.d.ts +8 -5
- package/dist/shims/request-context.js +50 -60
- package/dist/shims/request-context.js.map +1 -1
- package/dist/shims/request-state-types.d.ts +11 -11
- package/dist/shims/request-state-types.js +0 -1
- package/dist/shims/router-state.d.ts +13 -10
- package/dist/shims/router-state.js +34 -43
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/router.d.ts +81 -85
- package/dist/shims/router.js +506 -628
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script.d.ts +39 -48
- package/dist/shims/script.js +107 -160
- package/dist/shims/script.js.map +1 -1
- package/dist/shims/server-only.d.ts +1 -19
- package/dist/shims/server-only.js +0 -18
- package/dist/shims/server.d.ts +175 -164
- package/dist/shims/server.js +462 -478
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/unified-request-context.d.ts +20 -20
- package/dist/shims/unified-request-context.js +81 -99
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/shims/url-safety.d.ts +4 -1
- package/dist/shims/url-safety.js +15 -11
- package/dist/shims/url-safety.js.map +1 -1
- package/dist/shims/url-utils.d.ts +8 -5
- package/dist/shims/url-utils.js +62 -93
- package/dist/shims/url-utils.js.map +1 -1
- package/dist/shims/web-vitals.d.ts +10 -8
- package/dist/shims/web-vitals.js +9 -15
- package/dist/shims/web-vitals.js.map +1 -1
- package/dist/utils/base-path.d.ts +5 -2
- package/dist/utils/base-path.js +21 -19
- package/dist/utils/base-path.js.map +1 -1
- package/dist/utils/domain-locale.d.ts +17 -9
- package/dist/utils/domain-locale.js +36 -56
- package/dist/utils/domain-locale.js.map +1 -1
- package/dist/utils/hash.d.ts +4 -1
- package/dist/utils/hash.js +19 -17
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/manifest-paths.d.ts +6 -3
- package/dist/utils/manifest-paths.js +15 -16
- package/dist/utils/manifest-paths.js.map +1 -1
- package/dist/utils/project.d.ts +13 -11
- package/dist/utils/project.js +169 -216
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/query.d.ts +8 -6
- package/dist/utils/query.js +57 -67
- package/dist/utils/query.js.map +1 -1
- package/package.json +10 -9
- package/dist/build/report.d.ts.map +0 -1
- package/dist/build/static-export.d.ts.map +0 -1
- package/dist/check.d.ts.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/client/entry.d.ts.map +0 -1
- package/dist/client/validate-module-path.d.ts.map +0 -1
- package/dist/client/vinext-next-data.d.ts.map +0 -1
- package/dist/client/vinext-next-data.js.map +0 -1
- package/dist/cloudflare/index.d.ts.map +0 -1
- package/dist/cloudflare/index.js.map +0 -1
- package/dist/cloudflare/kv-cache-handler.d.ts.map +0 -1
- package/dist/cloudflare/tpr.d.ts.map +0 -1
- package/dist/config/config-matchers.d.ts.map +0 -1
- package/dist/config/dotenv.d.ts.map +0 -1
- package/dist/config/next-config.d.ts.map +0 -1
- package/dist/deploy.d.ts.map +0 -1
- package/dist/entries/app-browser-entry.d.ts.map +0 -1
- package/dist/entries/app-rsc-entry.d.ts.map +0 -1
- package/dist/entries/app-ssr-entry.d.ts.map +0 -1
- package/dist/entries/pages-client-entry.d.ts.map +0 -1
- package/dist/entries/pages-entry-helpers.d.ts.map +0 -1
- package/dist/entries/pages-server-entry.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/init.d.ts.map +0 -1
- package/dist/plugins/async-hooks-stub.d.ts.map +0 -1
- package/dist/plugins/client-reference-dedup.d.ts.map +0 -1
- package/dist/routing/app-router.d.ts.map +0 -1
- package/dist/routing/file-matcher.d.ts.map +0 -1
- package/dist/routing/pages-router.d.ts.map +0 -1
- package/dist/routing/route-trie.d.ts.map +0 -1
- package/dist/routing/route-validation.d.ts.map +0 -1
- package/dist/routing/utils.d.ts.map +0 -1
- package/dist/server/api-handler.d.ts.map +0 -1
- package/dist/server/app-router-entry.d.ts.map +0 -1
- package/dist/server/dev-module-runner.d.ts.map +0 -1
- package/dist/server/dev-origin-check.d.ts.map +0 -1
- package/dist/server/dev-server.d.ts.map +0 -1
- package/dist/server/html.d.ts.map +0 -1
- package/dist/server/image-optimization.d.ts.map +0 -1
- package/dist/server/instrumentation.d.ts.map +0 -1
- package/dist/server/isr-cache.d.ts.map +0 -1
- package/dist/server/metadata-routes.d.ts.map +0 -1
- package/dist/server/middleware-codegen.d.ts.map +0 -1
- package/dist/server/middleware-request-headers.d.ts.map +0 -1
- package/dist/server/middleware.d.ts.map +0 -1
- package/dist/server/normalize-path.d.ts.map +0 -1
- package/dist/server/pages-i18n.d.ts.map +0 -1
- package/dist/server/prod-server.d.ts.map +0 -1
- package/dist/server/request-log.d.ts.map +0 -1
- package/dist/server/request-pipeline.d.ts.map +0 -1
- package/dist/server/worker-utils.d.ts.map +0 -1
- package/dist/shims/amp.d.ts.map +0 -1
- package/dist/shims/app.d.ts.map +0 -1
- package/dist/shims/app.js.map +0 -1
- package/dist/shims/cache-runtime.d.ts.map +0 -1
- package/dist/shims/cache.d.ts.map +0 -1
- package/dist/shims/client-only.d.ts.map +0 -1
- package/dist/shims/client-only.js.map +0 -1
- package/dist/shims/compat-router.d.ts.map +0 -1
- package/dist/shims/config.d.ts.map +0 -1
- package/dist/shims/constants.d.ts.map +0 -1
- package/dist/shims/document.d.ts.map +0 -1
- package/dist/shims/dynamic.d.ts.map +0 -1
- package/dist/shims/error-boundary.d.ts.map +0 -1
- package/dist/shims/error.d.ts.map +0 -1
- package/dist/shims/fetch-cache.d.ts.map +0 -1
- package/dist/shims/font-google-base.d.ts.map +0 -1
- package/dist/shims/font-google.d.ts.map +0 -1
- package/dist/shims/font-google.generated.d.ts.map +0 -1
- package/dist/shims/font-google.js.map +0 -1
- package/dist/shims/font-local.d.ts.map +0 -1
- package/dist/shims/form.d.ts.map +0 -1
- package/dist/shims/head-state.d.ts.map +0 -1
- package/dist/shims/head.d.ts.map +0 -1
- package/dist/shims/headers.d.ts.map +0 -1
- package/dist/shims/i18n-context.d.ts.map +0 -1
- package/dist/shims/i18n-state.d.ts.map +0 -1
- package/dist/shims/image-config.d.ts.map +0 -1
- package/dist/shims/image.d.ts.map +0 -1
- package/dist/shims/internal/api-utils.d.ts.map +0 -1
- package/dist/shims/internal/api-utils.js.map +0 -1
- package/dist/shims/internal/app-router-context.d.ts.map +0 -1
- package/dist/shims/internal/cookies.d.ts.map +0 -1
- package/dist/shims/internal/cookies.js.map +0 -1
- package/dist/shims/internal/parse-cookie-header.d.ts.map +0 -1
- package/dist/shims/internal/router-context.d.ts.map +0 -1
- package/dist/shims/internal/utils.d.ts.map +0 -1
- package/dist/shims/internal/work-unit-async-storage.d.ts.map +0 -1
- package/dist/shims/layout-segment-context.d.ts.map +0 -1
- package/dist/shims/legacy-image.d.ts.map +0 -1
- package/dist/shims/link.d.ts.map +0 -1
- package/dist/shims/metadata.d.ts.map +0 -1
- package/dist/shims/navigation-state.d.ts.map +0 -1
- package/dist/shims/navigation.d.ts.map +0 -1
- package/dist/shims/og.d.ts.map +0 -1
- package/dist/shims/og.js.map +0 -1
- package/dist/shims/readonly-url-search-params.d.ts.map +0 -1
- package/dist/shims/request-context.d.ts.map +0 -1
- package/dist/shims/request-state-types.d.ts.map +0 -1
- package/dist/shims/request-state-types.js.map +0 -1
- package/dist/shims/router-state.d.ts.map +0 -1
- package/dist/shims/router.d.ts.map +0 -1
- package/dist/shims/script.d.ts.map +0 -1
- package/dist/shims/server-only.d.ts.map +0 -1
- package/dist/shims/server-only.js.map +0 -1
- package/dist/shims/server.d.ts.map +0 -1
- package/dist/shims/unified-request-context.d.ts.map +0 -1
- package/dist/shims/url-safety.d.ts.map +0 -1
- package/dist/shims/url-utils.d.ts.map +0 -1
- package/dist/shims/web-vitals.d.ts.map +0 -1
- package/dist/utils/base-path.d.ts.map +0 -1
- package/dist/utils/domain-locale.d.ts.map +0 -1
- package/dist/utils/hash.d.ts.map +0 -1
- package/dist/utils/manifest-paths.d.ts.map +0 -1
- package/dist/utils/project.d.ts.map +0 -1
- package/dist/utils/query.d.ts.map +0 -1
|
@@ -1,991 +1,782 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Config pattern matching and rule application utilities.
|
|
3
|
-
*
|
|
4
|
-
* Shared between the dev server (index.ts) and the production server
|
|
5
|
-
* (prod-server.ts) so both apply next.config.js rules identically.
|
|
6
|
-
*/
|
|
7
1
|
import { buildRequestHeadersFromMiddlewareResponse } from "../server/middleware-request-headers.js";
|
|
2
|
+
//#region src/config/config-matchers.ts
|
|
8
3
|
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const _compiledPatternCache = new Map();
|
|
4
|
+
* Cache for compiled regex patterns in matchConfigPattern.
|
|
5
|
+
*
|
|
6
|
+
* Redirect/rewrite patterns are static — they come from next.config.js and
|
|
7
|
+
* never change at runtime. Without caching, every request that hits the regex
|
|
8
|
+
* branch re-runs the full tokeniser walk + isSafeRegex + new RegExp() for
|
|
9
|
+
* every rule in the array. On apps with many locale-prefixed rules (which all
|
|
10
|
+
* contain `(` and therefore enter the regex branch) this dominated profiling
|
|
11
|
+
* at ~2.4 seconds of CPU self-time.
|
|
12
|
+
*
|
|
13
|
+
* Value is `null` when safeRegExp rejected the pattern (ReDoS risk), so we
|
|
14
|
+
* skip it on subsequent requests too without re-running the scanner.
|
|
15
|
+
*/
|
|
16
|
+
const _compiledPatternCache = /* @__PURE__ */ new Map();
|
|
22
17
|
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const _compiledHeaderSourceCache = new Map();
|
|
18
|
+
* Cache for compiled header source regexes in matchHeaders.
|
|
19
|
+
*
|
|
20
|
+
* Each NextHeader rule has a `source` that is run through escapeHeaderSource()
|
|
21
|
+
* then safeRegExp() to produce a RegExp. Both are pure functions of the source
|
|
22
|
+
* string and the result never changes. Without caching, every request
|
|
23
|
+
* re-runs the full escapeHeaderSource tokeniser + isSafeRegex scan + new RegExp()
|
|
24
|
+
* for every header rule.
|
|
25
|
+
*
|
|
26
|
+
* Value is `null` when safeRegExp rejected the pattern (ReDoS risk).
|
|
27
|
+
*/
|
|
28
|
+
const _compiledHeaderSourceCache = /* @__PURE__ */ new Map();
|
|
34
29
|
/**
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const _compiledConditionCache = new Map();
|
|
30
|
+
* Cache for compiled has/missing condition value regexes in checkSingleCondition.
|
|
31
|
+
*
|
|
32
|
+
* Each has/missing condition may carry a `value` string that is passed directly
|
|
33
|
+
* to safeRegExp() for matching against header/cookie/query/host values. The
|
|
34
|
+
* condition objects are static (from next.config.js) so the compiled RegExp
|
|
35
|
+
* never changes. Without caching, safeRegExp() is called on every request for
|
|
36
|
+
* every condition on every rule.
|
|
37
|
+
*
|
|
38
|
+
* Value is `null` when safeRegExp rejected the pattern, or `false` when the
|
|
39
|
+
* value string was undefined (no regex needed — use exact string comparison).
|
|
40
|
+
*/
|
|
41
|
+
const _compiledConditionCache = /* @__PURE__ */ new Map();
|
|
47
42
|
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const _compiledDestinationParamCache = new Map();
|
|
43
|
+
* Cache for destination substitution regexes in substituteDestinationParams.
|
|
44
|
+
*
|
|
45
|
+
* The regex depends only on the set of param keys captured from the matched
|
|
46
|
+
* source pattern. Caching by sorted key list avoids recompiling a new RegExp
|
|
47
|
+
* for repeated redirect/rewrite calls that use the same param shape.
|
|
48
|
+
*/
|
|
49
|
+
const _compiledDestinationParamCache = /* @__PURE__ */ new Map();
|
|
55
50
|
/**
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
51
|
+
* Redirect index for O(1) locale-static rule lookup.
|
|
52
|
+
*
|
|
53
|
+
* Many Next.js apps generate 50-100 redirect rules of the form:
|
|
54
|
+
* /:locale(en|es|fr|...)?/some-static-path → /some-destination
|
|
55
|
+
*
|
|
56
|
+
* The compiled regex for each is like:
|
|
57
|
+
* ^/(en|es|fr|...)?/some-static-path$
|
|
58
|
+
*
|
|
59
|
+
* When no redirect matches (the common case for ordinary page loads),
|
|
60
|
+
* matchRedirect previously ran exec() on every one of those regexes —
|
|
61
|
+
* ~2ms per call, ~2992ms total self-time in profiles.
|
|
62
|
+
*
|
|
63
|
+
* The index splits rules into two buckets:
|
|
64
|
+
*
|
|
65
|
+
* localeStatic — rules whose source is exactly /:paramName(alt1|alt2|...)?/suffix
|
|
66
|
+
* where `suffix` is a static path with no further params or regex groups.
|
|
67
|
+
* These are indexed in a Map<suffix, entry[]> for O(1) lookup after a
|
|
68
|
+
* single fast strip of the optional locale prefix.
|
|
69
|
+
*
|
|
70
|
+
* linear — all other rules. Matched with the original O(n) loop.
|
|
71
|
+
*
|
|
72
|
+
* The index is stored in a WeakMap keyed by the redirects array so it is
|
|
73
|
+
* computed once per config load and GC'd when the array is no longer live.
|
|
74
|
+
*
|
|
75
|
+
* ## Ordering invariant
|
|
76
|
+
*
|
|
77
|
+
* Redirect rules must be evaluated in their original order (first match wins).
|
|
78
|
+
* Each locale-static entry stores its `originalIndex` so that, when a
|
|
79
|
+
* locale-static fast-path match is found, any linear rules that appear earlier
|
|
80
|
+
* in the array are still checked first.
|
|
81
|
+
*/
|
|
87
82
|
/** Matches `/:param(alternation)?/static/suffix` — the locale-static pattern. */
|
|
88
83
|
const _LOCALE_STATIC_RE = /^\/:[\w-]+\(([^)]+)\)\?\/([a-zA-Z0-9_~.%@!$&'*+,;=:/-]+)$/;
|
|
89
|
-
const _redirectIndexCache = new WeakMap();
|
|
84
|
+
const _redirectIndexCache = /* @__PURE__ */ new WeakMap();
|
|
90
85
|
/**
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
86
|
+
* Build (or retrieve from cache) the redirect index for a given redirects array.
|
|
87
|
+
*
|
|
88
|
+
* Called once per config load from matchRedirect. The WeakMap ensures the index
|
|
89
|
+
* is recomputed if the config is reloaded (new array reference) and GC'd when
|
|
90
|
+
* the array is collected.
|
|
91
|
+
*/
|
|
97
92
|
function _getRedirectIndex(redirects) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
index = { localeStatic, linear };
|
|
134
|
-
_redirectIndexCache.set(redirects, index);
|
|
135
|
-
return index;
|
|
93
|
+
let index = _redirectIndexCache.get(redirects);
|
|
94
|
+
if (index !== void 0) return index;
|
|
95
|
+
const localeStatic = /* @__PURE__ */ new Map();
|
|
96
|
+
const linear = [];
|
|
97
|
+
for (let i = 0; i < redirects.length; i++) {
|
|
98
|
+
const redirect = redirects[i];
|
|
99
|
+
const m = _LOCALE_STATIC_RE.exec(redirect.source);
|
|
100
|
+
if (m) {
|
|
101
|
+
const paramName = redirect.source.slice(2, redirect.source.indexOf("("));
|
|
102
|
+
const alternation = m[1];
|
|
103
|
+
const suffix = "/" + m[2];
|
|
104
|
+
const altRe = safeRegExp("^(?:" + alternation + ")$");
|
|
105
|
+
if (!altRe) {
|
|
106
|
+
linear.push([i, redirect]);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const entry = {
|
|
110
|
+
paramName,
|
|
111
|
+
altRe,
|
|
112
|
+
redirect,
|
|
113
|
+
originalIndex: i
|
|
114
|
+
};
|
|
115
|
+
const bucket = localeStatic.get(suffix);
|
|
116
|
+
if (bucket) bucket.push(entry);
|
|
117
|
+
else localeStatic.set(suffix, [entry]);
|
|
118
|
+
} else linear.push([i, redirect]);
|
|
119
|
+
}
|
|
120
|
+
index = {
|
|
121
|
+
localeStatic,
|
|
122
|
+
linear
|
|
123
|
+
};
|
|
124
|
+
_redirectIndexCache.set(redirects, index);
|
|
125
|
+
return index;
|
|
136
126
|
}
|
|
137
127
|
/** Hop-by-hop headers that should not be forwarded through a proxy. */
|
|
138
128
|
const HOP_BY_HOP_HEADERS = new Set([
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
129
|
+
"connection",
|
|
130
|
+
"keep-alive",
|
|
131
|
+
"proxy-authenticate",
|
|
132
|
+
"proxy-authorization",
|
|
133
|
+
"te",
|
|
134
|
+
"trailers",
|
|
135
|
+
"transfer-encoding",
|
|
136
|
+
"upgrade"
|
|
137
|
+
]);
|
|
138
|
+
/**
|
|
139
|
+
* Request hop-by-hop headers to strip before proxying with fetch().
|
|
140
|
+
* Intentionally narrower than HOP_BY_HOP_HEADERS: external rewrite proxying
|
|
141
|
+
* still forwards proxy auth credentials, while response sanitization strips
|
|
142
|
+
* them before returning data to the client.
|
|
143
|
+
*/
|
|
144
|
+
const REQUEST_HOP_BY_HOP_HEADERS = new Set([
|
|
145
|
+
"connection",
|
|
146
|
+
"keep-alive",
|
|
147
|
+
"te",
|
|
148
|
+
"trailers",
|
|
149
|
+
"transfer-encoding",
|
|
150
|
+
"upgrade"
|
|
147
151
|
]);
|
|
152
|
+
function stripHopByHopRequestHeaders(headers) {
|
|
153
|
+
const connectionTokens = (headers.get("connection") || "").split(",").map((value) => value.trim().toLowerCase()).filter(Boolean);
|
|
154
|
+
for (const header of REQUEST_HOP_BY_HOP_HEADERS) headers.delete(header);
|
|
155
|
+
for (const token of connectionTokens) headers.delete(token);
|
|
156
|
+
}
|
|
148
157
|
/**
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (depth > 0) {
|
|
221
|
-
quantifierAtDepth[depth] = true;
|
|
222
|
-
}
|
|
223
|
-
i++;
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
if (ch === "?") {
|
|
227
|
-
// '?' after +, *, ?, or } is a non-greedy modifier, not a quantifier
|
|
228
|
-
const prev = i > 0 ? pattern[i - 1] : "";
|
|
229
|
-
if (prev !== "+" && prev !== "*" && prev !== "?" && prev !== "}") {
|
|
230
|
-
if (depth > 0) {
|
|
231
|
-
quantifierAtDepth[depth] = true;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
i++;
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
if (ch === "{") {
|
|
238
|
-
// Check if this is a quantifier {n}, {n,}, {n,m}
|
|
239
|
-
let j = i + 1;
|
|
240
|
-
while (j < pattern.length && /[\d,]/.test(pattern[j]))
|
|
241
|
-
j++;
|
|
242
|
-
if (j < pattern.length && pattern[j] === "}" && j > i + 1) {
|
|
243
|
-
if (depth > 0) {
|
|
244
|
-
quantifierAtDepth[depth] = true;
|
|
245
|
-
}
|
|
246
|
-
i = j + 1;
|
|
247
|
-
continue;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
i++;
|
|
251
|
-
}
|
|
252
|
-
return true;
|
|
158
|
+
* Detect regex patterns vulnerable to catastrophic backtracking (ReDoS).
|
|
159
|
+
*
|
|
160
|
+
* Uses a lightweight heuristic: scans the pattern string for nested quantifiers
|
|
161
|
+
* (a quantifier applied to a group that itself contains a quantifier). This
|
|
162
|
+
* catches the most common pathological patterns like `(a+)+`, `(.*)*`,
|
|
163
|
+
* `([^/]+)+`, `(a|a+)+` without needing a full regex parser.
|
|
164
|
+
*
|
|
165
|
+
* Returns true if the pattern appears safe, false if it's potentially dangerous.
|
|
166
|
+
*/
|
|
167
|
+
function isSafeRegex(pattern) {
|
|
168
|
+
const quantifierAtDepth = [];
|
|
169
|
+
let depth = 0;
|
|
170
|
+
let i = 0;
|
|
171
|
+
while (i < pattern.length) {
|
|
172
|
+
const ch = pattern[i];
|
|
173
|
+
if (ch === "\\") {
|
|
174
|
+
i += 2;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (ch === "[") {
|
|
178
|
+
i++;
|
|
179
|
+
while (i < pattern.length && pattern[i] !== "]") {
|
|
180
|
+
if (pattern[i] === "\\") i++;
|
|
181
|
+
i++;
|
|
182
|
+
}
|
|
183
|
+
i++;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (ch === "(") {
|
|
187
|
+
depth++;
|
|
188
|
+
if (quantifierAtDepth.length <= depth) quantifierAtDepth.push(false);
|
|
189
|
+
else quantifierAtDepth[depth] = false;
|
|
190
|
+
i++;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (ch === ")") {
|
|
194
|
+
const hadQuantifier = depth > 0 && quantifierAtDepth[depth];
|
|
195
|
+
if (depth > 0) depth--;
|
|
196
|
+
const next = pattern[i + 1];
|
|
197
|
+
if (next === "+" || next === "*" || next === "{") {
|
|
198
|
+
if (hadQuantifier) return false;
|
|
199
|
+
if (depth >= 0 && depth < quantifierAtDepth.length) quantifierAtDepth[depth] = true;
|
|
200
|
+
}
|
|
201
|
+
i++;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (ch === "+" || ch === "*") {
|
|
205
|
+
if (depth > 0) quantifierAtDepth[depth] = true;
|
|
206
|
+
i++;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (ch === "?") {
|
|
210
|
+
const prev = i > 0 ? pattern[i - 1] : "";
|
|
211
|
+
if (prev !== "+" && prev !== "*" && prev !== "?" && prev !== "}") {
|
|
212
|
+
if (depth > 0) quantifierAtDepth[depth] = true;
|
|
213
|
+
}
|
|
214
|
+
i++;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (ch === "{") {
|
|
218
|
+
let j = i + 1;
|
|
219
|
+
while (j < pattern.length && /[\d,]/.test(pattern[j])) j++;
|
|
220
|
+
if (j < pattern.length && pattern[j] === "}" && j > i + 1) {
|
|
221
|
+
if (depth > 0) quantifierAtDepth[depth] = true;
|
|
222
|
+
i = j + 1;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
i++;
|
|
227
|
+
}
|
|
228
|
+
return true;
|
|
253
229
|
}
|
|
254
230
|
/**
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
catch {
|
|
271
|
-
return null;
|
|
272
|
-
}
|
|
231
|
+
* Compile a regex pattern safely. Returns the compiled RegExp or null if the
|
|
232
|
+
* pattern is invalid or vulnerable to ReDoS.
|
|
233
|
+
*
|
|
234
|
+
* Logs a warning when a pattern is rejected so developers can fix their config.
|
|
235
|
+
*/
|
|
236
|
+
function safeRegExp(pattern, flags) {
|
|
237
|
+
if (!isSafeRegex(pattern)) {
|
|
238
|
+
console.warn(`[vinext] Ignoring potentially unsafe regex pattern (ReDoS risk): ${pattern}\n Patterns with nested quantifiers (e.g. (a+)+) can cause catastrophic backtracking.\n Simplify the pattern to avoid nested repetition.`);
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
return new RegExp(pattern, flags);
|
|
243
|
+
} catch {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
273
246
|
}
|
|
274
247
|
/**
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
// Plain named parameter → match one segment
|
|
319
|
-
result += "[^/]+";
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
else {
|
|
323
|
-
switch (m[0]) {
|
|
324
|
-
case ".":
|
|
325
|
-
result += "\\.";
|
|
326
|
-
break;
|
|
327
|
-
case "+":
|
|
328
|
-
result += "\\+";
|
|
329
|
-
break;
|
|
330
|
-
case "?":
|
|
331
|
-
result += "\\?";
|
|
332
|
-
break;
|
|
333
|
-
case "*":
|
|
334
|
-
result += ".*";
|
|
335
|
-
break;
|
|
336
|
-
default:
|
|
337
|
-
result += m[0];
|
|
338
|
-
break;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
return result;
|
|
248
|
+
* Convert a Next.js header/rewrite/redirect source pattern into a regex string.
|
|
249
|
+
*
|
|
250
|
+
* Regex groups in the source (e.g. `(\d+)`) are extracted first, the remaining
|
|
251
|
+
* text is escaped/converted in a **single pass** (avoiding chained `.replace()`
|
|
252
|
+
* which CodeQL flags as incomplete sanitization), then groups are restored.
|
|
253
|
+
*/
|
|
254
|
+
function escapeHeaderSource(source) {
|
|
255
|
+
const S = "";
|
|
256
|
+
const groups = [];
|
|
257
|
+
const withPlaceholders = source.replace(/\(([^)]+)\)/g, (_m, inner) => {
|
|
258
|
+
groups.push(inner);
|
|
259
|
+
return `${S}G${groups.length - 1}${S}`;
|
|
260
|
+
});
|
|
261
|
+
let result = "";
|
|
262
|
+
const re = new RegExp(`${S}G(\\d+)${S}|:[\\w-]+|[.+?*]|[^.+?*:\\uE000]+`, "g");
|
|
263
|
+
let m;
|
|
264
|
+
while ((m = re.exec(withPlaceholders)) !== null) if (m[1] !== void 0) result += `(${groups[Number(m[1])]})`;
|
|
265
|
+
else if (m[0].startsWith(":")) {
|
|
266
|
+
const constraintMatch = withPlaceholders.slice(re.lastIndex).match(new RegExp(`^${S}G(\\d+)${S}`));
|
|
267
|
+
if (constraintMatch) {
|
|
268
|
+
re.lastIndex += constraintMatch[0].length;
|
|
269
|
+
result += `(${groups[Number(constraintMatch[1])]})`;
|
|
270
|
+
} else result += "[^/]+";
|
|
271
|
+
} else switch (m[0]) {
|
|
272
|
+
case ".":
|
|
273
|
+
result += "\\.";
|
|
274
|
+
break;
|
|
275
|
+
case "+":
|
|
276
|
+
result += "\\+";
|
|
277
|
+
break;
|
|
278
|
+
case "?":
|
|
279
|
+
result += "\\?";
|
|
280
|
+
break;
|
|
281
|
+
case "*":
|
|
282
|
+
result += ".*";
|
|
283
|
+
break;
|
|
284
|
+
default:
|
|
285
|
+
result += m[0];
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
return result;
|
|
343
289
|
}
|
|
344
290
|
/**
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
cookies[key] = value;
|
|
359
|
-
}
|
|
360
|
-
return cookies;
|
|
291
|
+
* Parse a Cookie header string into a key-value record.
|
|
292
|
+
*/
|
|
293
|
+
function parseCookies(cookieHeader) {
|
|
294
|
+
if (!cookieHeader) return {};
|
|
295
|
+
const cookies = {};
|
|
296
|
+
for (const part of cookieHeader.split(";")) {
|
|
297
|
+
const eq = part.indexOf("=");
|
|
298
|
+
if (eq === -1) continue;
|
|
299
|
+
const key = part.slice(0, eq).trim();
|
|
300
|
+
const value = part.slice(eq + 1).trim();
|
|
301
|
+
if (key) cookies[key] = value;
|
|
302
|
+
}
|
|
303
|
+
return cookies;
|
|
361
304
|
}
|
|
362
305
|
/**
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
306
|
+
* Build a RequestContext from a Web Request object.
|
|
307
|
+
*/
|
|
308
|
+
function requestContextFromRequest(request) {
|
|
309
|
+
const url = new URL(request.url);
|
|
310
|
+
return {
|
|
311
|
+
headers: request.headers,
|
|
312
|
+
cookies: parseCookies(request.headers.get("cookie")),
|
|
313
|
+
query: url.searchParams,
|
|
314
|
+
host: normalizeHost(request.headers.get("host"), url.hostname)
|
|
315
|
+
};
|
|
373
316
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
return host.split(":", 1)[0].toLowerCase();
|
|
317
|
+
function normalizeHost(hostHeader, fallbackHostname) {
|
|
318
|
+
return (hostHeader ?? fallbackHostname).split(":", 1)[0].toLowerCase();
|
|
377
319
|
}
|
|
378
320
|
/**
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
321
|
+
* Unpack `x-middleware-request-*` headers from the collected middleware
|
|
322
|
+
* response headers into the actual request, and strip all `x-middleware-*`
|
|
323
|
+
* internal signals so they never reach clients.
|
|
324
|
+
*
|
|
325
|
+
* `middlewareHeaders` is mutated in-place (matching keys are deleted).
|
|
326
|
+
* Returns a (possibly cloned) `Request` with the unpacked headers applied,
|
|
327
|
+
* and a fresh `RequestContext` built from it — ready for post-middleware
|
|
328
|
+
* config rule matching (beforeFiles, afterFiles, fallback).
|
|
329
|
+
*
|
|
330
|
+
* Works for both Node.js requests (mutable headers) and Workers requests
|
|
331
|
+
* (immutable — cloned only when there are headers to apply).
|
|
332
|
+
*
|
|
333
|
+
* `x-middleware-request-*` values are always plain strings (they carry
|
|
334
|
+
* individual header values), so the wider `string | string[]` type of
|
|
335
|
+
* `middlewareHeaders` is safe to cast here.
|
|
336
|
+
*/
|
|
337
|
+
function applyMiddlewareRequestHeaders(middlewareHeaders, request) {
|
|
338
|
+
const nextHeaders = buildRequestHeadersFromMiddlewareResponse(request.headers, middlewareHeaders);
|
|
339
|
+
for (const key of Object.keys(middlewareHeaders)) if (key.startsWith("x-middleware-")) delete middlewareHeaders[key];
|
|
340
|
+
if (nextHeaders) request = new Request(request.url, {
|
|
341
|
+
method: request.method,
|
|
342
|
+
headers: nextHeaders,
|
|
343
|
+
body: request.body,
|
|
344
|
+
duplex: request.body ? "half" : void 0
|
|
345
|
+
});
|
|
346
|
+
return {
|
|
347
|
+
request,
|
|
348
|
+
postMwReqCtx: requestContextFromRequest(request)
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
function _emptyParams() {
|
|
352
|
+
return Object.create(null);
|
|
353
|
+
}
|
|
354
|
+
function _matchConditionValue(actualValue, expectedValue) {
|
|
355
|
+
if (expectedValue === void 0) return _emptyParams();
|
|
356
|
+
const re = _cachedConditionRegex(expectedValue);
|
|
357
|
+
if (re) {
|
|
358
|
+
const match = re.exec(actualValue);
|
|
359
|
+
if (!match) return null;
|
|
360
|
+
const params = _emptyParams();
|
|
361
|
+
if (match.groups) {
|
|
362
|
+
for (const [key, value] of Object.entries(match.groups)) if (value !== void 0) params[key] = value;
|
|
363
|
+
}
|
|
364
|
+
return params;
|
|
365
|
+
}
|
|
366
|
+
return actualValue === expectedValue ? _emptyParams() : null;
|
|
413
367
|
}
|
|
414
368
|
/**
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
function
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
return cookieValue === condition.value;
|
|
441
|
-
}
|
|
442
|
-
return true;
|
|
443
|
-
}
|
|
444
|
-
case "query": {
|
|
445
|
-
const queryValue = ctx.query.get(condition.key);
|
|
446
|
-
if (queryValue === null)
|
|
447
|
-
return false;
|
|
448
|
-
if (condition.value !== undefined) {
|
|
449
|
-
const re = _cachedConditionRegex(condition.value);
|
|
450
|
-
if (re)
|
|
451
|
-
return re.test(queryValue);
|
|
452
|
-
return queryValue === condition.value;
|
|
453
|
-
}
|
|
454
|
-
return true;
|
|
455
|
-
}
|
|
456
|
-
case "host": {
|
|
457
|
-
if (condition.value !== undefined) {
|
|
458
|
-
const re = _cachedConditionRegex(condition.value);
|
|
459
|
-
if (re)
|
|
460
|
-
return re.test(ctx.host);
|
|
461
|
-
return ctx.host === condition.value;
|
|
462
|
-
}
|
|
463
|
-
return ctx.host === condition.key;
|
|
464
|
-
}
|
|
465
|
-
default:
|
|
466
|
-
return false;
|
|
467
|
-
}
|
|
369
|
+
* Check a single has/missing condition against request context.
|
|
370
|
+
* Returns captured params when the condition is satisfied, or null otherwise.
|
|
371
|
+
*/
|
|
372
|
+
function matchSingleCondition(condition, ctx) {
|
|
373
|
+
switch (condition.type) {
|
|
374
|
+
case "header": {
|
|
375
|
+
const headerValue = ctx.headers.get(condition.key);
|
|
376
|
+
if (headerValue === null) return null;
|
|
377
|
+
return _matchConditionValue(headerValue, condition.value);
|
|
378
|
+
}
|
|
379
|
+
case "cookie": {
|
|
380
|
+
const cookieValue = ctx.cookies[condition.key];
|
|
381
|
+
if (cookieValue === void 0) return null;
|
|
382
|
+
return _matchConditionValue(cookieValue, condition.value);
|
|
383
|
+
}
|
|
384
|
+
case "query": {
|
|
385
|
+
const queryValue = ctx.query.get(condition.key);
|
|
386
|
+
if (queryValue === null) return null;
|
|
387
|
+
return _matchConditionValue(queryValue, condition.value);
|
|
388
|
+
}
|
|
389
|
+
case "host":
|
|
390
|
+
if (condition.value !== void 0) return _matchConditionValue(ctx.host, condition.value);
|
|
391
|
+
return ctx.host === condition.key ? _emptyParams() : null;
|
|
392
|
+
default: return null;
|
|
393
|
+
}
|
|
468
394
|
}
|
|
469
395
|
/**
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
396
|
+
* Return a cached RegExp for a has/missing condition value string, compiling
|
|
397
|
+
* on first use. Returns null if safeRegExp rejected the pattern or if the
|
|
398
|
+
* value is not a valid regex (fall back to exact string comparison).
|
|
399
|
+
*/
|
|
474
400
|
function _cachedConditionRegex(value) {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
401
|
+
let re = _compiledConditionCache.get(value);
|
|
402
|
+
if (re === void 0) {
|
|
403
|
+
re = safeRegExp(value);
|
|
404
|
+
_compiledConditionCache.set(value, re);
|
|
405
|
+
}
|
|
406
|
+
return re;
|
|
481
407
|
}
|
|
482
408
|
/**
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
409
|
+
* Check all has/missing conditions for a config rule.
|
|
410
|
+
* Returns true if the rule should be applied (all has conditions pass, all missing conditions pass).
|
|
411
|
+
*
|
|
412
|
+
* - has: every condition must match (the request must have it)
|
|
413
|
+
* - missing: every condition must NOT match (the request must not have it)
|
|
414
|
+
*/
|
|
415
|
+
function collectConditionParams(has, missing, ctx) {
|
|
416
|
+
const params = _emptyParams();
|
|
417
|
+
if (has) for (const condition of has) {
|
|
418
|
+
const conditionParams = matchSingleCondition(condition, ctx);
|
|
419
|
+
if (!conditionParams) return null;
|
|
420
|
+
Object.assign(params, conditionParams);
|
|
421
|
+
}
|
|
422
|
+
if (missing) {
|
|
423
|
+
for (const condition of missing) if (matchSingleCondition(condition, ctx)) return null;
|
|
424
|
+
}
|
|
425
|
+
return params;
|
|
426
|
+
}
|
|
427
|
+
function checkHasConditions(has, missing, ctx) {
|
|
428
|
+
return collectConditionParams(has, missing, ctx) !== null;
|
|
503
429
|
}
|
|
504
430
|
/**
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
431
|
+
* If the current position in `str` starts with a parenthesized group, consume
|
|
432
|
+
* it and advance `re.lastIndex` past the closing `)`. Returns the group
|
|
433
|
+
* contents or null if no group is present.
|
|
434
|
+
*/
|
|
509
435
|
function extractConstraint(str, re) {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
if (depth !== 0)
|
|
523
|
-
return null;
|
|
524
|
-
re.lastIndex = i;
|
|
525
|
-
return str.slice(start, i - 1);
|
|
436
|
+
if (str[re.lastIndex] !== "(") return null;
|
|
437
|
+
const start = re.lastIndex + 1;
|
|
438
|
+
let depth = 1;
|
|
439
|
+
let i = start;
|
|
440
|
+
while (i < str.length && depth > 0) {
|
|
441
|
+
if (str[i] === "(") depth++;
|
|
442
|
+
else if (str[i] === ")") depth--;
|
|
443
|
+
i++;
|
|
444
|
+
}
|
|
445
|
+
if (depth !== 0) return null;
|
|
446
|
+
re.lastIndex = i;
|
|
447
|
+
return str.slice(start, i - 1);
|
|
526
448
|
}
|
|
527
449
|
/**
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
const re = safeRegExp("^" + regexStr + "$");
|
|
599
|
-
// Store null for rejected patterns so we don't re-run isSafeRegex.
|
|
600
|
-
compiled = re ? { re, paramNames } : null;
|
|
601
|
-
_compiledPatternCache.set(pattern, compiled);
|
|
602
|
-
}
|
|
603
|
-
if (!compiled)
|
|
604
|
-
return null;
|
|
605
|
-
const match = compiled.re.exec(pathname);
|
|
606
|
-
if (!match)
|
|
607
|
-
return null;
|
|
608
|
-
const params = Object.create(null);
|
|
609
|
-
for (let i = 0; i < compiled.paramNames.length; i++) {
|
|
610
|
-
params[compiled.paramNames[i]] = match[i + 1] ?? "";
|
|
611
|
-
}
|
|
612
|
-
return params;
|
|
613
|
-
}
|
|
614
|
-
catch {
|
|
615
|
-
// Fall through to segment-based matching
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
// Check for catch-all patterns (:param* or :param+) without regex groups
|
|
619
|
-
// Param names may contain hyphens (e.g. :sign-in*, :sign-up+).
|
|
620
|
-
const catchAllMatch = pattern.match(/:([\w-]+)(\*|\+)$/);
|
|
621
|
-
if (catchAllMatch) {
|
|
622
|
-
const prefix = pattern.slice(0, pattern.lastIndexOf(":"));
|
|
623
|
-
const paramName = catchAllMatch[1];
|
|
624
|
-
const isPlus = catchAllMatch[2] === "+";
|
|
625
|
-
const prefixNoSlash = prefix.replace(/\/$/, "");
|
|
626
|
-
if (!pathname.startsWith(prefixNoSlash))
|
|
627
|
-
return null;
|
|
628
|
-
const charAfter = pathname[prefixNoSlash.length];
|
|
629
|
-
if (charAfter !== undefined && charAfter !== "/")
|
|
630
|
-
return null;
|
|
631
|
-
const rest = pathname.slice(prefixNoSlash.length);
|
|
632
|
-
if (isPlus && (!rest || rest === "/"))
|
|
633
|
-
return null;
|
|
634
|
-
let restValue = rest.startsWith("/") ? rest.slice(1) : rest;
|
|
635
|
-
// NOTE: Do NOT decodeURIComponent here. The pathname is already decoded at
|
|
636
|
-
// the request entry point. Decoding again would produce incorrect param values.
|
|
637
|
-
return { [paramName]: restValue };
|
|
638
|
-
}
|
|
639
|
-
// Simple segment-based matching for exact patterns and :param
|
|
640
|
-
const parts = pattern.split("/");
|
|
641
|
-
const pathParts = pathname.split("/");
|
|
642
|
-
if (parts.length !== pathParts.length)
|
|
643
|
-
return null;
|
|
644
|
-
const params = Object.create(null);
|
|
645
|
-
for (let i = 0; i < parts.length; i++) {
|
|
646
|
-
if (parts[i].startsWith(":")) {
|
|
647
|
-
params[parts[i].slice(1)] = pathParts[i];
|
|
648
|
-
}
|
|
649
|
-
else if (parts[i] !== pathParts[i]) {
|
|
650
|
-
return null;
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
return params;
|
|
450
|
+
* Match a Next.js config pattern (from redirects/rewrites sources) against a pathname.
|
|
451
|
+
* Returns matched params or null.
|
|
452
|
+
*
|
|
453
|
+
* Supports:
|
|
454
|
+
* :param - matches a single path segment
|
|
455
|
+
* :param* - matches zero or more segments (catch-all)
|
|
456
|
+
* :param+ - matches one or more segments
|
|
457
|
+
* (regex) - inline regex patterns in the source
|
|
458
|
+
* :param(constraint) - named param with inline regex constraint
|
|
459
|
+
*/
|
|
460
|
+
function matchConfigPattern(pathname, pattern) {
|
|
461
|
+
if (pattern.includes("(") || pattern.includes("\\") || /:[\w-]+[*+][^/]/.test(pattern) || /:[\w-]+\./.test(pattern)) try {
|
|
462
|
+
let compiled = _compiledPatternCache.get(pattern);
|
|
463
|
+
if (compiled === void 0) {
|
|
464
|
+
const paramNames = [];
|
|
465
|
+
let regexStr = "";
|
|
466
|
+
const tokenRe = /:([\w-]+)|[.]|[^:.]+/g;
|
|
467
|
+
let tok;
|
|
468
|
+
while ((tok = tokenRe.exec(pattern)) !== null) if (tok[1] !== void 0) {
|
|
469
|
+
const name = tok[1];
|
|
470
|
+
const rest = pattern.slice(tokenRe.lastIndex);
|
|
471
|
+
if (rest.startsWith("*") || rest.startsWith("+")) {
|
|
472
|
+
const quantifier = rest[0];
|
|
473
|
+
tokenRe.lastIndex += 1;
|
|
474
|
+
const constraint = extractConstraint(pattern, tokenRe);
|
|
475
|
+
paramNames.push(name);
|
|
476
|
+
if (constraint !== null) regexStr += `(${constraint})`;
|
|
477
|
+
else regexStr += quantifier === "*" ? "(.*)" : "(.+)";
|
|
478
|
+
} else {
|
|
479
|
+
const constraint = extractConstraint(pattern, tokenRe);
|
|
480
|
+
paramNames.push(name);
|
|
481
|
+
regexStr += constraint !== null ? `(${constraint})` : "([^/]+)";
|
|
482
|
+
}
|
|
483
|
+
} else if (tok[0] === ".") regexStr += "\\.";
|
|
484
|
+
else regexStr += tok[0];
|
|
485
|
+
const re = safeRegExp("^" + regexStr + "$");
|
|
486
|
+
compiled = re ? {
|
|
487
|
+
re,
|
|
488
|
+
paramNames
|
|
489
|
+
} : null;
|
|
490
|
+
_compiledPatternCache.set(pattern, compiled);
|
|
491
|
+
}
|
|
492
|
+
if (!compiled) return null;
|
|
493
|
+
const match = compiled.re.exec(pathname);
|
|
494
|
+
if (!match) return null;
|
|
495
|
+
const params = Object.create(null);
|
|
496
|
+
for (let i = 0; i < compiled.paramNames.length; i++) params[compiled.paramNames[i]] = match[i + 1] ?? "";
|
|
497
|
+
return params;
|
|
498
|
+
} catch {}
|
|
499
|
+
const catchAllMatch = pattern.match(/:([\w-]+)(\*|\+)$/);
|
|
500
|
+
if (catchAllMatch) {
|
|
501
|
+
const prefix = pattern.slice(0, pattern.lastIndexOf(":"));
|
|
502
|
+
const paramName = catchAllMatch[1];
|
|
503
|
+
const isPlus = catchAllMatch[2] === "+";
|
|
504
|
+
const prefixNoSlash = prefix.replace(/\/$/, "");
|
|
505
|
+
if (!pathname.startsWith(prefixNoSlash)) return null;
|
|
506
|
+
const charAfter = pathname[prefixNoSlash.length];
|
|
507
|
+
if (charAfter !== void 0 && charAfter !== "/") return null;
|
|
508
|
+
const rest = pathname.slice(prefixNoSlash.length);
|
|
509
|
+
if (isPlus && (!rest || rest === "/")) return null;
|
|
510
|
+
let restValue = rest.startsWith("/") ? rest.slice(1) : rest;
|
|
511
|
+
return { [paramName]: restValue };
|
|
512
|
+
}
|
|
513
|
+
const parts = pattern.split("/");
|
|
514
|
+
const pathParts = pathname.split("/");
|
|
515
|
+
if (parts.length !== pathParts.length) return null;
|
|
516
|
+
const params = Object.create(null);
|
|
517
|
+
for (let i = 0; i < parts.length; i++) if (parts[i].startsWith(":")) params[parts[i].slice(1)] = pathParts[i];
|
|
518
|
+
else if (parts[i] !== pathParts[i]) return null;
|
|
519
|
+
return params;
|
|
654
520
|
}
|
|
655
521
|
/**
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
// --- Linear fallback: all non-locale-static rules ---
|
|
762
|
-
//
|
|
763
|
-
// We only need to check linear rules whose originalIndex < localeMatchIndex.
|
|
764
|
-
// If localeMatchIndex is Infinity (no locale match), we check all of them.
|
|
765
|
-
for (const [origIdx, redirect] of index.linear) {
|
|
766
|
-
if (origIdx >= localeMatchIndex) {
|
|
767
|
-
// This linear rule comes after the best locale-static match —
|
|
768
|
-
// the locale-static match wins. Stop scanning.
|
|
769
|
-
break;
|
|
770
|
-
}
|
|
771
|
-
const params = matchConfigPattern(pathname, redirect.source);
|
|
772
|
-
if (params) {
|
|
773
|
-
if (redirect.has || redirect.missing) {
|
|
774
|
-
if (!checkHasConditions(redirect.has, redirect.missing, ctx)) {
|
|
775
|
-
continue;
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
let dest = substituteDestinationParams(redirect.destination, params);
|
|
779
|
-
// Collapse protocol-relative URLs (e.g. //evil.com from decoded %2F in catch-all params).
|
|
780
|
-
dest = sanitizeDestination(dest);
|
|
781
|
-
return { destination: dest, permanent: redirect.permanent };
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
// Return the locale-static match if found (no earlier linear rule matched).
|
|
785
|
-
return localeMatch;
|
|
522
|
+
* Apply redirect rules from next.config.js.
|
|
523
|
+
* Returns the redirect info if a redirect was matched, or null.
|
|
524
|
+
*
|
|
525
|
+
* `ctx` provides the request context (cookies, headers, query, host) used
|
|
526
|
+
* to evaluate has/missing conditions. Next.js always has request context
|
|
527
|
+
* when evaluating redirects, so this parameter is required.
|
|
528
|
+
*
|
|
529
|
+
* ## Performance
|
|
530
|
+
*
|
|
531
|
+
* Rules with a locale-capture-group prefix (the dominant pattern in large
|
|
532
|
+
* Next.js apps — e.g. `/:locale(en|es|fr|...)?/some-path`) are handled via
|
|
533
|
+
* a pre-built index. Instead of running exec() on each locale regex
|
|
534
|
+
* individually, we:
|
|
535
|
+
*
|
|
536
|
+
* 1. Strip the optional locale prefix from the pathname with one cheap
|
|
537
|
+
* string-slice check (no regex exec on the hot path).
|
|
538
|
+
* 2. Look up the stripped suffix in a Map<suffix, entry[]>.
|
|
539
|
+
* 3. For each matching entry, validate the captured locale string against
|
|
540
|
+
* a small, anchored alternation regex.
|
|
541
|
+
*
|
|
542
|
+
* This reduces the per-request cost from O(n × regex) to O(1) map lookup +
|
|
543
|
+
* O(matches × tiny-regex), eliminating the ~2992ms self-time reported in
|
|
544
|
+
* profiles for apps with 63+ locale-prefixed rules.
|
|
545
|
+
*
|
|
546
|
+
* Rules that don't fit the locale-static pattern fall back to the original
|
|
547
|
+
* linear matchConfigPattern scan.
|
|
548
|
+
*
|
|
549
|
+
* ## Ordering invariant
|
|
550
|
+
*
|
|
551
|
+
* First match wins, preserving the original redirect array order. When a
|
|
552
|
+
* locale-static fast-path match is found at position N, all linear rules with
|
|
553
|
+
* an original index < N are checked via matchConfigPattern first — they are
|
|
554
|
+
* few in practice (typically zero) so this is not a hot-path concern.
|
|
555
|
+
*/
|
|
556
|
+
function matchRedirect(pathname, redirects, ctx) {
|
|
557
|
+
if (redirects.length === 0) return null;
|
|
558
|
+
const index = _getRedirectIndex(redirects);
|
|
559
|
+
let localeMatch = null;
|
|
560
|
+
let localeMatchIndex = Infinity;
|
|
561
|
+
if (index.localeStatic.size > 0) {
|
|
562
|
+
const noLocaleBucket = index.localeStatic.get(pathname);
|
|
563
|
+
if (noLocaleBucket) for (const entry of noLocaleBucket) {
|
|
564
|
+
if (entry.originalIndex >= localeMatchIndex) continue;
|
|
565
|
+
const redirect = entry.redirect;
|
|
566
|
+
const conditionParams = redirect.has || redirect.missing ? collectConditionParams(redirect.has, redirect.missing, ctx) : _emptyParams();
|
|
567
|
+
if (!conditionParams) continue;
|
|
568
|
+
let dest = substituteDestinationParams(redirect.destination, {
|
|
569
|
+
[entry.paramName]: "",
|
|
570
|
+
...conditionParams
|
|
571
|
+
});
|
|
572
|
+
dest = sanitizeDestination(dest);
|
|
573
|
+
localeMatch = {
|
|
574
|
+
destination: dest,
|
|
575
|
+
permanent: redirect.permanent
|
|
576
|
+
};
|
|
577
|
+
localeMatchIndex = entry.originalIndex;
|
|
578
|
+
break;
|
|
579
|
+
}
|
|
580
|
+
const slashTwo = pathname.indexOf("/", 1);
|
|
581
|
+
if (slashTwo !== -1) {
|
|
582
|
+
const suffix = pathname.slice(slashTwo);
|
|
583
|
+
const localePart = pathname.slice(1, slashTwo);
|
|
584
|
+
const localeBucket = index.localeStatic.get(suffix);
|
|
585
|
+
if (localeBucket) for (const entry of localeBucket) {
|
|
586
|
+
if (entry.originalIndex >= localeMatchIndex) continue;
|
|
587
|
+
if (!entry.altRe.test(localePart)) continue;
|
|
588
|
+
const redirect = entry.redirect;
|
|
589
|
+
const conditionParams = redirect.has || redirect.missing ? collectConditionParams(redirect.has, redirect.missing, ctx) : _emptyParams();
|
|
590
|
+
if (!conditionParams) continue;
|
|
591
|
+
let dest = substituteDestinationParams(redirect.destination, {
|
|
592
|
+
[entry.paramName]: localePart,
|
|
593
|
+
...conditionParams
|
|
594
|
+
});
|
|
595
|
+
dest = sanitizeDestination(dest);
|
|
596
|
+
localeMatch = {
|
|
597
|
+
destination: dest,
|
|
598
|
+
permanent: redirect.permanent
|
|
599
|
+
};
|
|
600
|
+
localeMatchIndex = entry.originalIndex;
|
|
601
|
+
break;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
for (const [origIdx, redirect] of index.linear) {
|
|
606
|
+
if (origIdx >= localeMatchIndex) break;
|
|
607
|
+
const params = matchConfigPattern(pathname, redirect.source);
|
|
608
|
+
if (params) {
|
|
609
|
+
const conditionParams = redirect.has || redirect.missing ? collectConditionParams(redirect.has, redirect.missing, ctx) : _emptyParams();
|
|
610
|
+
if (!conditionParams) continue;
|
|
611
|
+
let dest = substituteDestinationParams(redirect.destination, {
|
|
612
|
+
...params,
|
|
613
|
+
...conditionParams
|
|
614
|
+
});
|
|
615
|
+
dest = sanitizeDestination(dest);
|
|
616
|
+
return {
|
|
617
|
+
destination: dest,
|
|
618
|
+
permanent: redirect.permanent
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
return localeMatch;
|
|
786
623
|
}
|
|
787
624
|
/**
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
return null;
|
|
625
|
+
* Apply rewrite rules from next.config.js.
|
|
626
|
+
* Returns the rewritten URL or null if no rewrite matched.
|
|
627
|
+
*
|
|
628
|
+
* `ctx` provides the request context (cookies, headers, query, host) used
|
|
629
|
+
* to evaluate has/missing conditions. Next.js always has request context
|
|
630
|
+
* when evaluating rewrites, so this parameter is required.
|
|
631
|
+
*/
|
|
632
|
+
function matchRewrite(pathname, rewrites, ctx) {
|
|
633
|
+
for (const rewrite of rewrites) {
|
|
634
|
+
const params = matchConfigPattern(pathname, rewrite.source);
|
|
635
|
+
if (params) {
|
|
636
|
+
const conditionParams = rewrite.has || rewrite.missing ? collectConditionParams(rewrite.has, rewrite.missing, ctx) : _emptyParams();
|
|
637
|
+
if (!conditionParams) continue;
|
|
638
|
+
let dest = substituteDestinationParams(rewrite.destination, {
|
|
639
|
+
...params,
|
|
640
|
+
...conditionParams
|
|
641
|
+
});
|
|
642
|
+
dest = sanitizeDestination(dest);
|
|
643
|
+
return dest;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
return null;
|
|
811
647
|
}
|
|
812
648
|
/**
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
649
|
+
* Substitute all matched route params into a redirect/rewrite destination.
|
|
650
|
+
*
|
|
651
|
+
* Handles repeated params (e.g. `/api/:id/:id`) and catch-all suffix forms
|
|
652
|
+
* (`:path*`, `:path+`) in a single pass. Unknown params are left intact.
|
|
653
|
+
*/
|
|
818
654
|
function substituteDestinationParams(destination, params) {
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
if (!paramRe) {
|
|
831
|
-
const paramAlternation = sortedKeys
|
|
832
|
-
.map((key) => key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
|
|
833
|
-
.join("|");
|
|
834
|
-
paramRe = new RegExp(`:(${paramAlternation})([+*])?(?![A-Za-z0-9_])`, "g");
|
|
835
|
-
_compiledDestinationParamCache.set(cacheKey, paramRe);
|
|
836
|
-
}
|
|
837
|
-
return destination.replace(paramRe, (_token, key) => params[key]);
|
|
655
|
+
const keys = Object.keys(params);
|
|
656
|
+
if (keys.length === 0) return destination;
|
|
657
|
+
const sortedKeys = [...keys].sort((a, b) => b.length - a.length);
|
|
658
|
+
const cacheKey = sortedKeys.join("\0");
|
|
659
|
+
let paramRe = _compiledDestinationParamCache.get(cacheKey);
|
|
660
|
+
if (!paramRe) {
|
|
661
|
+
const paramAlternation = sortedKeys.map((key) => key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
662
|
+
paramRe = new RegExp(`:(${paramAlternation})([+*])?(?![A-Za-z0-9_])`, "g");
|
|
663
|
+
_compiledDestinationParamCache.set(cacheKey, paramRe);
|
|
664
|
+
}
|
|
665
|
+
return destination.replace(paramRe, (_token, key) => params[key]);
|
|
838
666
|
}
|
|
839
667
|
/**
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
}
|
|
855
|
-
// Normalize leading backslashes to forward slashes. Browsers interpret
|
|
856
|
-
// backslash as forward slash in URL contexts, so "\/evil.com" becomes
|
|
857
|
-
// "//evil.com" (protocol-relative redirect). Replace any mix of leading
|
|
858
|
-
// slashes and backslashes with a single forward slash.
|
|
859
|
-
dest = dest.replace(/^[\\/]+/, "/");
|
|
860
|
-
return dest;
|
|
668
|
+
* Sanitize a redirect/rewrite destination to collapse protocol-relative URLs.
|
|
669
|
+
*
|
|
670
|
+
* After parameter substitution, a destination like `/:path*` can become
|
|
671
|
+
* `//evil.com` if the catch-all captured a decoded `%2F` (`/evil.com`).
|
|
672
|
+
* Browsers interpret `//evil.com` as a protocol-relative URL, redirecting
|
|
673
|
+
* users off-site.
|
|
674
|
+
*
|
|
675
|
+
* This function collapses any leading double (or more) slashes to a single
|
|
676
|
+
* slash for non-external (relative) destinations.
|
|
677
|
+
*/
|
|
678
|
+
function sanitizeDestination(dest) {
|
|
679
|
+
if (dest.startsWith("http://") || dest.startsWith("https://")) return dest;
|
|
680
|
+
dest = dest.replace(/^[\\/]+/, "/");
|
|
681
|
+
return dest;
|
|
861
682
|
}
|
|
862
683
|
/**
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
684
|
+
* Check if a URL is external (absolute URL or protocol-relative).
|
|
685
|
+
* Detects any URL scheme (http:, https:, data:, javascript:, blob:, etc.)
|
|
686
|
+
* per RFC 3986, plus protocol-relative URLs (//).
|
|
687
|
+
*/
|
|
688
|
+
function isExternalUrl(url) {
|
|
689
|
+
return /^[a-z][a-z0-9+.-]*:/i.test(url) || url.startsWith("//");
|
|
869
690
|
}
|
|
870
691
|
/**
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
return new Response("Bad Gateway", { status: 502 });
|
|
933
|
-
}
|
|
934
|
-
finally {
|
|
935
|
-
clearTimeout(timeout);
|
|
936
|
-
}
|
|
937
|
-
// Build the response to return to the client.
|
|
938
|
-
// Copy all upstream headers except hop-by-hop headers.
|
|
939
|
-
// Node.js fetch() auto-decompresses responses (gzip, br, etc.), so the body
|
|
940
|
-
// we receive is already plain text. Forwarding the original content-encoding
|
|
941
|
-
// and content-length headers causes the browser to attempt a second
|
|
942
|
-
// decompression on the already-decoded body, resulting in
|
|
943
|
-
// ERR_CONTENT_DECODING_FAILED. Strip both headers on Node.js only.
|
|
944
|
-
// On Workers, fetch() preserves wire encoding, so the headers stay accurate.
|
|
945
|
-
const isNodeRuntime = typeof process !== "undefined" && !!process.versions?.node;
|
|
946
|
-
const responseHeaders = new Headers();
|
|
947
|
-
upstreamResponse.headers.forEach((value, key) => {
|
|
948
|
-
const lower = key.toLowerCase();
|
|
949
|
-
if (HOP_BY_HOP_HEADERS.has(lower))
|
|
950
|
-
return;
|
|
951
|
-
if (isNodeRuntime && (lower === "content-encoding" || lower === "content-length"))
|
|
952
|
-
return;
|
|
953
|
-
responseHeaders.append(key, value);
|
|
954
|
-
});
|
|
955
|
-
return new Response(upstreamResponse.body, {
|
|
956
|
-
status: upstreamResponse.status,
|
|
957
|
-
statusText: upstreamResponse.statusText,
|
|
958
|
-
headers: responseHeaders,
|
|
959
|
-
});
|
|
692
|
+
* Proxy an incoming request to an external URL and return the upstream response.
|
|
693
|
+
*
|
|
694
|
+
* Used for external rewrites (e.g. `/ph/:path*` → `https://us.i.posthog.com/:path*`).
|
|
695
|
+
* Next.js handles these as server-side reverse proxies, forwarding the request
|
|
696
|
+
* method, headers, and body to the external destination.
|
|
697
|
+
*
|
|
698
|
+
* Works in all runtimes (Node.js, Cloudflare Workers) via the standard fetch() API.
|
|
699
|
+
*/
|
|
700
|
+
async function proxyExternalRequest(request, externalUrl) {
|
|
701
|
+
const originalUrl = new URL(request.url);
|
|
702
|
+
const targetUrl = new URL(externalUrl);
|
|
703
|
+
const destinationKeys = new Set(targetUrl.searchParams.keys());
|
|
704
|
+
for (const [key, value] of originalUrl.searchParams) if (!destinationKeys.has(key)) targetUrl.searchParams.append(key, value);
|
|
705
|
+
const headers = new Headers(request.headers);
|
|
706
|
+
headers.set("host", targetUrl.host);
|
|
707
|
+
stripHopByHopRequestHeaders(headers);
|
|
708
|
+
const keysToDelete = [];
|
|
709
|
+
for (const key of headers.keys()) if (key.startsWith("x-middleware-")) keysToDelete.push(key);
|
|
710
|
+
for (const key of keysToDelete) headers.delete(key);
|
|
711
|
+
const method = request.method;
|
|
712
|
+
const hasBody = method !== "GET" && method !== "HEAD";
|
|
713
|
+
const init = {
|
|
714
|
+
method,
|
|
715
|
+
headers,
|
|
716
|
+
redirect: "manual"
|
|
717
|
+
};
|
|
718
|
+
if (hasBody && request.body) {
|
|
719
|
+
init.body = request.body;
|
|
720
|
+
init.duplex = "half";
|
|
721
|
+
}
|
|
722
|
+
const controller = new AbortController();
|
|
723
|
+
const timeout = setTimeout(() => controller.abort(), 3e4);
|
|
724
|
+
let upstreamResponse;
|
|
725
|
+
try {
|
|
726
|
+
upstreamResponse = await fetch(targetUrl.href, {
|
|
727
|
+
...init,
|
|
728
|
+
signal: controller.signal
|
|
729
|
+
});
|
|
730
|
+
} catch (e) {
|
|
731
|
+
if (e?.name === "AbortError") {
|
|
732
|
+
console.error("[vinext] External rewrite proxy timeout:", targetUrl.href);
|
|
733
|
+
return new Response("Gateway Timeout", { status: 504 });
|
|
734
|
+
}
|
|
735
|
+
console.error("[vinext] External rewrite proxy error:", e);
|
|
736
|
+
return new Response("Bad Gateway", { status: 502 });
|
|
737
|
+
} finally {
|
|
738
|
+
clearTimeout(timeout);
|
|
739
|
+
}
|
|
740
|
+
const isNodeRuntime = typeof process !== "undefined" && !!process.versions?.node;
|
|
741
|
+
const responseHeaders = new Headers();
|
|
742
|
+
upstreamResponse.headers.forEach((value, key) => {
|
|
743
|
+
const lower = key.toLowerCase();
|
|
744
|
+
if (HOP_BY_HOP_HEADERS.has(lower)) return;
|
|
745
|
+
if (isNodeRuntime && (lower === "content-encoding" || lower === "content-length")) return;
|
|
746
|
+
responseHeaders.append(key, value);
|
|
747
|
+
});
|
|
748
|
+
return new Response(upstreamResponse.body, {
|
|
749
|
+
status: upstreamResponse.status,
|
|
750
|
+
statusText: upstreamResponse.statusText,
|
|
751
|
+
headers: responseHeaders
|
|
752
|
+
});
|
|
960
753
|
}
|
|
961
754
|
/**
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
}
|
|
986
|
-
result.push(...rule.headers);
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
return result;
|
|
755
|
+
* Apply custom header rules from next.config.js.
|
|
756
|
+
* Returns an array of { key, value } pairs to set on the response.
|
|
757
|
+
*
|
|
758
|
+
* `ctx` provides the request context (cookies, headers, query, host) used
|
|
759
|
+
* to evaluate has/missing conditions. Next.js always has request context
|
|
760
|
+
* when evaluating headers, so this parameter is required.
|
|
761
|
+
*/
|
|
762
|
+
function matchHeaders(pathname, headers, ctx) {
|
|
763
|
+
const result = [];
|
|
764
|
+
for (const rule of headers) {
|
|
765
|
+
let sourceRegex = _compiledHeaderSourceCache.get(rule.source);
|
|
766
|
+
if (sourceRegex === void 0) {
|
|
767
|
+
sourceRegex = safeRegExp("^" + escapeHeaderSource(rule.source) + "$");
|
|
768
|
+
_compiledHeaderSourceCache.set(rule.source, sourceRegex);
|
|
769
|
+
}
|
|
770
|
+
if (sourceRegex && sourceRegex.test(pathname)) {
|
|
771
|
+
if (rule.has || rule.missing) {
|
|
772
|
+
if (!checkHasConditions(rule.has, rule.missing, ctx)) continue;
|
|
773
|
+
}
|
|
774
|
+
result.push(...rule.headers);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
return result;
|
|
990
778
|
}
|
|
779
|
+
//#endregion
|
|
780
|
+
export { applyMiddlewareRequestHeaders, checkHasConditions, escapeHeaderSource, isExternalUrl, isSafeRegex, matchConfigPattern, matchHeaders, matchRedirect, matchRewrite, normalizeHost, parseCookies, proxyExternalRequest, requestContextFromRequest, safeRegExp, sanitizeDestination };
|
|
781
|
+
|
|
991
782
|
//# sourceMappingURL=config-matchers.js.map
|