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,998 +1,767 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Serves the built output from `vinext build`. Handles:
|
|
5
|
-
* - Static asset serving from client build output
|
|
6
|
-
* - Pages Router: SSR rendering + API route handling
|
|
7
|
-
* - App Router: RSC/SSR rendering, route handlers, server actions
|
|
8
|
-
* - Gzip/Brotli compression for text-based responses
|
|
9
|
-
* - Streaming SSR for App Router
|
|
10
|
-
*
|
|
11
|
-
* Build output for Pages Router:
|
|
12
|
-
* - dist/client/ — static assets (JS, CSS, images) + .vite/ssr-manifest.json
|
|
13
|
-
* - dist/server/entry.js — SSR entry point (virtual:vinext-server-entry)
|
|
14
|
-
*
|
|
15
|
-
* Build output for App Router:
|
|
16
|
-
* - dist/client/ — static assets (JS, CSS, images)
|
|
17
|
-
* - dist/server/index.js — RSC entry (default export: handler(Request) → Response)
|
|
18
|
-
* - dist/server/ssr/index.js — SSR entry (imported by RSC entry at runtime)
|
|
19
|
-
*/
|
|
20
|
-
import { createServer } from "node:http";
|
|
21
|
-
import { Readable, pipeline } from "node:stream";
|
|
22
|
-
import { pathToFileURL } from "node:url";
|
|
23
|
-
import fs from "node:fs";
|
|
24
|
-
import path from "node:path";
|
|
25
|
-
import zlib from "node:zlib";
|
|
26
|
-
import { matchRedirect, matchRewrite, matchHeaders, requestContextFromRequest, applyMiddlewareRequestHeaders, isExternalUrl, proxyExternalRequest, sanitizeDestination, } from "../config/config-matchers.js";
|
|
27
|
-
import { IMAGE_OPTIMIZATION_PATH, IMAGE_CONTENT_SECURITY_POLICY, parseImageParams, isSafeImageContentType, DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, } from "./image-optimization.js";
|
|
1
|
+
import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
|
|
2
|
+
import { applyMiddlewareRequestHeaders, isExternalUrl, matchHeaders, matchRedirect, matchRewrite, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "../config/config-matchers.js";
|
|
28
3
|
import { normalizePath } from "./normalize-path.js";
|
|
29
4
|
import { hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
30
|
-
import { computeLazyChunks } from "../index.js";
|
|
31
5
|
import { manifestFileWithBase } from "../utils/manifest-paths.js";
|
|
32
|
-
import {
|
|
6
|
+
import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, isSafeImageContentType, parseImageParams } from "./image-optimization.js";
|
|
7
|
+
import { readPrerenderSecret } from "../build/server-manifest.js";
|
|
8
|
+
import { computeLazyChunks } from "../index.js";
|
|
9
|
+
import fs from "node:fs";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { pathToFileURL } from "node:url";
|
|
12
|
+
import { createServer } from "node:http";
|
|
13
|
+
import { Readable, pipeline } from "node:stream";
|
|
14
|
+
import zlib from "node:zlib";
|
|
15
|
+
//#region src/server/prod-server.ts
|
|
16
|
+
/**
|
|
17
|
+
* Production server for vinext.
|
|
18
|
+
*
|
|
19
|
+
* Serves the built output from `vinext build`. Handles:
|
|
20
|
+
* - Static asset serving from client build output
|
|
21
|
+
* - Pages Router: SSR rendering + API route handling
|
|
22
|
+
* - App Router: RSC/SSR rendering, route handlers, server actions
|
|
23
|
+
* - Gzip/Brotli compression for text-based responses
|
|
24
|
+
* - Streaming SSR for App Router
|
|
25
|
+
*
|
|
26
|
+
* Build output for Pages Router:
|
|
27
|
+
* - dist/client/ — static assets (JS, CSS, images) + .vite/ssr-manifest.json
|
|
28
|
+
* - dist/server/entry.js — SSR entry point (virtual:vinext-server-entry)
|
|
29
|
+
*
|
|
30
|
+
* Build output for App Router:
|
|
31
|
+
* - dist/client/ — static assets (JS, CSS, images)
|
|
32
|
+
* - dist/server/index.js — RSC entry (default export: handler(Request) → Response)
|
|
33
|
+
* - dist/server/ssr/index.js — SSR entry (imported by RSC entry at runtime)
|
|
34
|
+
*/
|
|
33
35
|
/** Convert a Node.js IncomingMessage into a ReadableStream for Web Request body. */
|
|
34
36
|
function readNodeStream(req) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
},
|
|
41
|
-
});
|
|
37
|
+
return new ReadableStream({ start(controller) {
|
|
38
|
+
req.on("data", (chunk) => controller.enqueue(new Uint8Array(chunk)));
|
|
39
|
+
req.on("end", () => controller.close());
|
|
40
|
+
req.on("error", (err) => controller.error(err));
|
|
41
|
+
} });
|
|
42
42
|
}
|
|
43
43
|
/** Content types that benefit from compression. */
|
|
44
44
|
const COMPRESSIBLE_TYPES = new Set([
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
45
|
+
"text/html",
|
|
46
|
+
"text/css",
|
|
47
|
+
"text/plain",
|
|
48
|
+
"text/xml",
|
|
49
|
+
"text/javascript",
|
|
50
|
+
"application/javascript",
|
|
51
|
+
"application/json",
|
|
52
|
+
"application/xml",
|
|
53
|
+
"application/xhtml+xml",
|
|
54
|
+
"application/rss+xml",
|
|
55
|
+
"application/atom+xml",
|
|
56
|
+
"image/svg+xml",
|
|
57
|
+
"application/manifest+json",
|
|
58
|
+
"application/wasm"
|
|
59
59
|
]);
|
|
60
60
|
/** Minimum size threshold for compression (in bytes). Below this, compression overhead isn't worth it. */
|
|
61
61
|
const COMPRESS_THRESHOLD = 1024;
|
|
62
62
|
/**
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
* Parse the Accept-Encoding header and return the best supported encoding.
|
|
64
|
+
* Preference order: br > gzip > deflate > identity.
|
|
65
|
+
*/
|
|
66
66
|
function negotiateEncoding(req) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return "gzip";
|
|
75
|
-
if (lower.includes("deflate"))
|
|
76
|
-
return "deflate";
|
|
77
|
-
return null;
|
|
67
|
+
const accept = req.headers["accept-encoding"];
|
|
68
|
+
if (!accept || typeof accept !== "string") return null;
|
|
69
|
+
const lower = accept.toLowerCase();
|
|
70
|
+
if (lower.includes("br")) return "br";
|
|
71
|
+
if (lower.includes("gzip")) return "gzip";
|
|
72
|
+
if (lower.includes("deflate")) return "deflate";
|
|
73
|
+
return null;
|
|
78
74
|
}
|
|
79
75
|
/**
|
|
80
|
-
|
|
81
|
-
|
|
76
|
+
* Create a compression stream for the given encoding.
|
|
77
|
+
*/
|
|
82
78
|
function createCompressor(encoding) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
case "gzip":
|
|
91
|
-
return zlib.createGzip({ level: 6 }); // Default level, good balance
|
|
92
|
-
case "deflate":
|
|
93
|
-
return zlib.createDeflate({ level: 6 });
|
|
94
|
-
}
|
|
79
|
+
switch (encoding) {
|
|
80
|
+
case "br": return zlib.createBrotliCompress({ params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 4 } });
|
|
81
|
+
case "gzip": return zlib.createGzip({ level: 6 });
|
|
82
|
+
case "deflate": return zlib.createDeflate({ level: 6 });
|
|
83
|
+
}
|
|
95
84
|
}
|
|
96
85
|
/**
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
86
|
+
* Merge middleware headers and a Web Response's headers into a single
|
|
87
|
+
* record suitable for Node.js `res.writeHead()`. Uses `getSetCookie()`
|
|
88
|
+
* to preserve multiple Set-Cookie values instead of flattening them.
|
|
89
|
+
*/
|
|
101
90
|
function mergeResponseHeaders(middlewareHeaders, response) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const existing = merged["set-cookie"];
|
|
114
|
-
const mwCookies = existing ? (Array.isArray(existing) ? existing : [existing]) : [];
|
|
115
|
-
merged["set-cookie"] = [...mwCookies, ...responseCookies];
|
|
116
|
-
}
|
|
117
|
-
return merged;
|
|
91
|
+
const merged = { ...middlewareHeaders };
|
|
92
|
+
response.headers.forEach((v, k) => {
|
|
93
|
+
if (k === "set-cookie") return;
|
|
94
|
+
merged[k] = v;
|
|
95
|
+
});
|
|
96
|
+
const responseCookies = response.headers.getSetCookie?.() ?? [];
|
|
97
|
+
if (responseCookies.length > 0) {
|
|
98
|
+
const existing = merged["set-cookie"];
|
|
99
|
+
merged["set-cookie"] = [...existing ? Array.isArray(existing) ? existing : [existing] : [], ...responseCookies];
|
|
100
|
+
}
|
|
101
|
+
return merged;
|
|
118
102
|
}
|
|
119
103
|
/**
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
function sendCompressed(req, res, body, contentType, statusCode, extraHeaders = {}, compress = true, statusText =
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
"Content-Encoding": encoding,
|
|
156
|
-
Vary: varyValue,
|
|
157
|
-
});
|
|
158
|
-
compressor.end(buf);
|
|
159
|
-
pipeline(compressor, res, () => {
|
|
160
|
-
/* ignore pipeline errors on closed connections */
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
// Strip any pre-existing content-length (from the Web Response constructor)
|
|
165
|
-
// before setting our own — avoids duplicate Content-Length headers.
|
|
166
|
-
const { "content-length": _cl, "Content-Length": _CL, ...headersWithoutLength } = extraHeaders;
|
|
167
|
-
writeHead({
|
|
168
|
-
...headersWithoutLength,
|
|
169
|
-
"Content-Type": contentType,
|
|
170
|
-
"Content-Length": String(buf.length),
|
|
171
|
-
});
|
|
172
|
-
res.end(buf);
|
|
173
|
-
}
|
|
104
|
+
* Send a compressed response if the content type is compressible and the
|
|
105
|
+
* client supports compression. Otherwise send uncompressed.
|
|
106
|
+
*/
|
|
107
|
+
function sendCompressed(req, res, body, contentType, statusCode, extraHeaders = {}, compress = true, statusText = void 0) {
|
|
108
|
+
const buf = typeof body === "string" ? Buffer.from(body) : body;
|
|
109
|
+
const baseType = contentType.split(";")[0].trim();
|
|
110
|
+
const encoding = compress ? negotiateEncoding(req) : null;
|
|
111
|
+
const writeHead = (headers) => {
|
|
112
|
+
if (statusText) res.writeHead(statusCode, statusText, headers);
|
|
113
|
+
else res.writeHead(statusCode, headers);
|
|
114
|
+
};
|
|
115
|
+
if (encoding && COMPRESSIBLE_TYPES.has(baseType) && buf.length >= 1024) {
|
|
116
|
+
const compressor = createCompressor(encoding);
|
|
117
|
+
const rawVary = extraHeaders["Vary"] ?? extraHeaders["vary"];
|
|
118
|
+
const existingVary = Array.isArray(rawVary) ? rawVary.join(", ") : rawVary;
|
|
119
|
+
let varyValue;
|
|
120
|
+
if (existingVary) varyValue = existingVary.toLowerCase().includes("accept-encoding") ? existingVary : existingVary + ", Accept-Encoding";
|
|
121
|
+
else varyValue = "Accept-Encoding";
|
|
122
|
+
writeHead({
|
|
123
|
+
...extraHeaders,
|
|
124
|
+
"Content-Type": contentType,
|
|
125
|
+
"Content-Encoding": encoding,
|
|
126
|
+
Vary: varyValue
|
|
127
|
+
});
|
|
128
|
+
compressor.end(buf);
|
|
129
|
+
pipeline(compressor, res, () => {});
|
|
130
|
+
} else {
|
|
131
|
+
const { "content-length": _cl, "Content-Length": _CL, ...headersWithoutLength } = extraHeaders;
|
|
132
|
+
writeHead({
|
|
133
|
+
...headersWithoutLength,
|
|
134
|
+
"Content-Type": contentType,
|
|
135
|
+
"Content-Length": String(buf.length)
|
|
136
|
+
});
|
|
137
|
+
res.end(buf);
|
|
138
|
+
}
|
|
174
139
|
}
|
|
175
140
|
/** Content-type lookup for static assets. */
|
|
176
141
|
const CONTENT_TYPES = {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
142
|
+
".js": "application/javascript",
|
|
143
|
+
".mjs": "application/javascript",
|
|
144
|
+
".css": "text/css",
|
|
145
|
+
".html": "text/html",
|
|
146
|
+
".json": "application/json",
|
|
147
|
+
".png": "image/png",
|
|
148
|
+
".jpg": "image/jpeg",
|
|
149
|
+
".jpeg": "image/jpeg",
|
|
150
|
+
".gif": "image/gif",
|
|
151
|
+
".svg": "image/svg+xml",
|
|
152
|
+
".ico": "image/x-icon",
|
|
153
|
+
".woff": "font/woff",
|
|
154
|
+
".woff2": "font/woff2",
|
|
155
|
+
".ttf": "font/ttf",
|
|
156
|
+
".eot": "application/vnd.ms-fontobject",
|
|
157
|
+
".webp": "image/webp",
|
|
158
|
+
".avif": "image/avif",
|
|
159
|
+
".map": "application/json",
|
|
160
|
+
".rsc": "text/x-component"
|
|
195
161
|
};
|
|
196
162
|
/**
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
163
|
+
* Try to serve a static file from the client build directory.
|
|
164
|
+
* Returns true if the file was served, false otherwise.
|
|
165
|
+
*/
|
|
200
166
|
function tryServeStatic(req, res, clientDir, pathname, compress, extraHeaders) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
return true;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
res.writeHead(200, baseHeaders);
|
|
251
|
-
fs.createReadStream(staticFile).pipe(res);
|
|
252
|
-
return true;
|
|
167
|
+
const resolvedClient = path.resolve(clientDir);
|
|
168
|
+
let decodedPathname;
|
|
169
|
+
try {
|
|
170
|
+
decodedPathname = decodeURIComponent(pathname);
|
|
171
|
+
} catch {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
if (decodedPathname.startsWith("/.vite/") || decodedPathname === "/.vite") return false;
|
|
175
|
+
const staticFile = path.resolve(clientDir, "." + decodedPathname);
|
|
176
|
+
if (!staticFile.startsWith(resolvedClient + path.sep) && staticFile !== resolvedClient) return false;
|
|
177
|
+
let resolvedStaticFile = staticFile;
|
|
178
|
+
if (pathname === "/") return false;
|
|
179
|
+
if (!fs.existsSync(resolvedStaticFile) || !fs.statSync(resolvedStaticFile).isFile()) {
|
|
180
|
+
const htmlFallback = staticFile + ".html";
|
|
181
|
+
if (fs.existsSync(htmlFallback) && fs.statSync(htmlFallback).isFile()) resolvedStaticFile = htmlFallback;
|
|
182
|
+
else {
|
|
183
|
+
const indexFallback = path.join(staticFile, "index.html");
|
|
184
|
+
if (fs.existsSync(indexFallback) && fs.statSync(indexFallback).isFile()) resolvedStaticFile = indexFallback;
|
|
185
|
+
else return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const ct = CONTENT_TYPES[path.extname(resolvedStaticFile)] ?? "application/octet-stream";
|
|
189
|
+
const cacheControl = pathname.startsWith("/assets/") ? "public, max-age=31536000, immutable" : "public, max-age=3600";
|
|
190
|
+
const baseHeaders = {
|
|
191
|
+
"Content-Type": ct,
|
|
192
|
+
"Cache-Control": cacheControl,
|
|
193
|
+
...extraHeaders
|
|
194
|
+
};
|
|
195
|
+
const baseType = ct.split(";")[0].trim();
|
|
196
|
+
if (compress && COMPRESSIBLE_TYPES.has(baseType)) {
|
|
197
|
+
const encoding = negotiateEncoding(req);
|
|
198
|
+
if (encoding) {
|
|
199
|
+
const fileStream = fs.createReadStream(resolvedStaticFile);
|
|
200
|
+
const compressor = createCompressor(encoding);
|
|
201
|
+
res.writeHead(200, {
|
|
202
|
+
...baseHeaders,
|
|
203
|
+
"Content-Encoding": encoding,
|
|
204
|
+
Vary: "Accept-Encoding"
|
|
205
|
+
});
|
|
206
|
+
pipeline(fileStream, compressor, res, () => {});
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
res.writeHead(200, baseHeaders);
|
|
211
|
+
fs.createReadStream(resolvedStaticFile).pipe(res);
|
|
212
|
+
return true;
|
|
253
213
|
}
|
|
254
214
|
/**
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
215
|
+
* Resolve the host for a request, ignoring X-Forwarded-Host to prevent
|
|
216
|
+
* host header poisoning attacks (open redirects, cache poisoning).
|
|
217
|
+
*
|
|
218
|
+
* X-Forwarded-Host is only trusted when the VINEXT_TRUSTED_HOSTS env var
|
|
219
|
+
* lists the forwarded host value. Without this, an attacker can send
|
|
220
|
+
* X-Forwarded-Host: evil.com and poison any redirect that resolves
|
|
221
|
+
* against request.url.
|
|
222
|
+
*
|
|
223
|
+
* On Cloudflare Workers, X-Forwarded-Host is always set by Cloudflare
|
|
224
|
+
* itself, so this is only a concern for the Node.js prod-server.
|
|
225
|
+
*/
|
|
266
226
|
function resolveHost(req, fallback) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
return forwardedHost;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return hostHeader || fallback;
|
|
227
|
+
const rawForwarded = req.headers["x-forwarded-host"];
|
|
228
|
+
const hostHeader = req.headers.host;
|
|
229
|
+
if (rawForwarded) {
|
|
230
|
+
const forwardedHost = rawForwarded.split(",")[0].trim().toLowerCase();
|
|
231
|
+
if (forwardedHost && trustedHosts.has(forwardedHost)) return forwardedHost;
|
|
232
|
+
}
|
|
233
|
+
return hostHeader || fallback;
|
|
278
234
|
}
|
|
279
235
|
/** Hosts that are allowed as X-Forwarded-Host values (stored lowercase). */
|
|
280
|
-
const trustedHosts = new Set((process.env.VINEXT_TRUSTED_HOSTS ?? "")
|
|
281
|
-
.split(",")
|
|
282
|
-
.map((h) => h.trim().toLowerCase())
|
|
283
|
-
.filter(Boolean));
|
|
236
|
+
const trustedHosts = new Set((process.env.VINEXT_TRUSTED_HOSTS ?? "").split(",").map((h) => h.trim().toLowerCase()).filter(Boolean));
|
|
284
237
|
/**
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
238
|
+
* Whether to trust X-Forwarded-Proto from upstream proxies.
|
|
239
|
+
* Enabled when VINEXT_TRUST_PROXY=1 or when VINEXT_TRUSTED_HOSTS is set
|
|
240
|
+
* (having trusted hosts implies a trusted proxy).
|
|
241
|
+
*/
|
|
289
242
|
const trustProxy = process.env.VINEXT_TRUST_PROXY === "1" || trustedHosts.size > 0;
|
|
290
243
|
/**
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
244
|
+
* Convert a Node.js IncomingMessage to a Web Request object.
|
|
245
|
+
*
|
|
246
|
+
* When `urlOverride` is provided, it is used as the path + query string
|
|
247
|
+
* instead of `req.url`. This avoids redundant path normalization when the
|
|
248
|
+
* caller has already decoded and normalized the pathname (e.g. the App
|
|
249
|
+
* Router prod server normalizes before static-asset lookup, and can pass
|
|
250
|
+
* the result here so the downstream RSC handler doesn't re-normalize).
|
|
251
|
+
*/
|
|
299
252
|
function nodeToWebRequest(req, urlOverride) {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const hasBody = method !== "GET" && method !== "HEAD";
|
|
321
|
-
const init = {
|
|
322
|
-
method,
|
|
323
|
-
headers,
|
|
324
|
-
};
|
|
325
|
-
if (hasBody) {
|
|
326
|
-
// Convert Node.js readable stream to Web ReadableStream for request body.
|
|
327
|
-
// Readable.toWeb() is available since Node.js 17.
|
|
328
|
-
init.body = Readable.toWeb(req);
|
|
329
|
-
init.duplex = "half"; // Required for streaming request bodies
|
|
330
|
-
}
|
|
331
|
-
return new Request(url, init);
|
|
253
|
+
const rawProto = trustProxy ? req.headers["x-forwarded-proto"]?.split(",")[0]?.trim() : void 0;
|
|
254
|
+
const origin = `${rawProto === "https" || rawProto === "http" ? rawProto : "http"}://${resolveHost(req, "localhost")}`;
|
|
255
|
+
const url = new URL(urlOverride ?? req.url ?? "/", origin);
|
|
256
|
+
const headers = new Headers();
|
|
257
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
258
|
+
if (value === void 0) continue;
|
|
259
|
+
if (Array.isArray(value)) for (const v of value) headers.append(key, v);
|
|
260
|
+
else headers.set(key, value);
|
|
261
|
+
}
|
|
262
|
+
const method = req.method ?? "GET";
|
|
263
|
+
const hasBody = method !== "GET" && method !== "HEAD";
|
|
264
|
+
const init = {
|
|
265
|
+
method,
|
|
266
|
+
headers
|
|
267
|
+
};
|
|
268
|
+
if (hasBody) {
|
|
269
|
+
init.body = Readable.toWeb(req);
|
|
270
|
+
init.duplex = "half";
|
|
271
|
+
}
|
|
272
|
+
return new Request(url, init);
|
|
332
273
|
}
|
|
333
274
|
/**
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
275
|
+
* Stream a Web Response back to a Node.js ServerResponse.
|
|
276
|
+
* Supports streaming compression for SSR responses.
|
|
277
|
+
*/
|
|
337
278
|
async function sendWebResponse(webResponse, req, res, compress) {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
// of overwriting. This prevents stripping the Vary values that the App Router
|
|
377
|
-
// sets for content negotiation (RSC stream vs HTML).
|
|
378
|
-
const existingVary = nodeHeaders["Vary"] ?? nodeHeaders["vary"];
|
|
379
|
-
if (existingVary) {
|
|
380
|
-
const existing = String(existingVary).toLowerCase();
|
|
381
|
-
if (!existing.includes("accept-encoding")) {
|
|
382
|
-
nodeHeaders["Vary"] = existingVary + ", Accept-Encoding";
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
else {
|
|
386
|
-
nodeHeaders["Vary"] = "Accept-Encoding";
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
writeHead(nodeHeaders);
|
|
390
|
-
// HEAD requests: send headers only, skip the body
|
|
391
|
-
if (req.method === "HEAD") {
|
|
392
|
-
res.end();
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
// Convert Web ReadableStream to Node.js Readable and pipe to response.
|
|
396
|
-
// Readable.fromWeb() is available since Node.js 17.
|
|
397
|
-
const nodeStream = Readable.fromWeb(webResponse.body);
|
|
398
|
-
if (shouldCompress) {
|
|
399
|
-
const compressor = createCompressor(encoding);
|
|
400
|
-
pipeline(nodeStream, compressor, res, () => {
|
|
401
|
-
/* ignore pipeline errors on closed connections */
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
else {
|
|
405
|
-
pipeline(nodeStream, res, () => {
|
|
406
|
-
/* ignore pipeline errors on closed connections */
|
|
407
|
-
});
|
|
408
|
-
}
|
|
279
|
+
const status = webResponse.status;
|
|
280
|
+
const statusText = webResponse.statusText || void 0;
|
|
281
|
+
const writeHead = (headers) => {
|
|
282
|
+
if (statusText) res.writeHead(status, statusText, headers);
|
|
283
|
+
else res.writeHead(status, headers);
|
|
284
|
+
};
|
|
285
|
+
const nodeHeaders = {};
|
|
286
|
+
webResponse.headers.forEach((value, key) => {
|
|
287
|
+
const existing = nodeHeaders[key];
|
|
288
|
+
if (existing !== void 0) nodeHeaders[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
|
|
289
|
+
else nodeHeaders[key] = value;
|
|
290
|
+
});
|
|
291
|
+
if (!webResponse.body) {
|
|
292
|
+
writeHead(nodeHeaders);
|
|
293
|
+
res.end();
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const alreadyEncoded = webResponse.headers.has("content-encoding");
|
|
297
|
+
const baseType = (webResponse.headers.get("content-type") ?? "").split(";")[0].trim();
|
|
298
|
+
const encoding = compress && !alreadyEncoded ? negotiateEncoding(req) : null;
|
|
299
|
+
const shouldCompress = !!(encoding && COMPRESSIBLE_TYPES.has(baseType));
|
|
300
|
+
if (shouldCompress) {
|
|
301
|
+
delete nodeHeaders["content-length"];
|
|
302
|
+
delete nodeHeaders["Content-Length"];
|
|
303
|
+
nodeHeaders["Content-Encoding"] = encoding;
|
|
304
|
+
const existingVary = nodeHeaders["Vary"] ?? nodeHeaders["vary"];
|
|
305
|
+
if (existingVary) {
|
|
306
|
+
if (!String(existingVary).toLowerCase().includes("accept-encoding")) nodeHeaders["Vary"] = existingVary + ", Accept-Encoding";
|
|
307
|
+
} else nodeHeaders["Vary"] = "Accept-Encoding";
|
|
308
|
+
}
|
|
309
|
+
writeHead(nodeHeaders);
|
|
310
|
+
if (req.method === "HEAD") {
|
|
311
|
+
res.end();
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const nodeStream = Readable.fromWeb(webResponse.body);
|
|
315
|
+
if (shouldCompress) pipeline(nodeStream, createCompressor(encoding), res, () => {});
|
|
316
|
+
else pipeline(nodeStream, res, () => {});
|
|
409
317
|
}
|
|
410
318
|
/**
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
319
|
+
* Start the production server.
|
|
320
|
+
*
|
|
321
|
+
* Automatically detects whether the build is App Router (dist/server/index.js) or
|
|
322
|
+
* Pages Router (dist/server/entry.js) and configures the appropriate handler.
|
|
323
|
+
*/
|
|
324
|
+
async function startProdServer(options = {}) {
|
|
325
|
+
const { port = process.env.PORT ? parseInt(process.env.PORT) : 3e3, host = "0.0.0.0", outDir = path.resolve("dist"), noCompression = false } = options;
|
|
326
|
+
const compress = !noCompression;
|
|
327
|
+
const resolvedOutDir = path.resolve(outDir);
|
|
328
|
+
const clientDir = path.join(resolvedOutDir, "client");
|
|
329
|
+
const rscEntryPath = path.join(resolvedOutDir, "server", "index.js");
|
|
330
|
+
const serverEntryPath = path.join(resolvedOutDir, "server", "entry.js");
|
|
331
|
+
const isAppRouter = fs.existsSync(rscEntryPath);
|
|
332
|
+
if (!isAppRouter && !fs.existsSync(serverEntryPath)) {
|
|
333
|
+
console.error(`[vinext] No build output found in ${outDir}`);
|
|
334
|
+
console.error("Run `vinext build` first.");
|
|
335
|
+
process.exit(1);
|
|
336
|
+
}
|
|
337
|
+
if (isAppRouter) return startAppRouterServer({
|
|
338
|
+
port,
|
|
339
|
+
host,
|
|
340
|
+
clientDir,
|
|
341
|
+
rscEntryPath,
|
|
342
|
+
compress
|
|
343
|
+
});
|
|
344
|
+
return startPagesRouterServer({
|
|
345
|
+
port,
|
|
346
|
+
host,
|
|
347
|
+
clientDir,
|
|
348
|
+
serverEntryPath,
|
|
349
|
+
compress
|
|
350
|
+
});
|
|
435
351
|
}
|
|
436
352
|
function createNodeExecutionContext() {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
},
|
|
444
|
-
passThroughOnException() { },
|
|
445
|
-
};
|
|
353
|
+
return {
|
|
354
|
+
waitUntil(promise) {
|
|
355
|
+
Promise.resolve(promise).catch(() => {});
|
|
356
|
+
},
|
|
357
|
+
passThroughOnException() {}
|
|
358
|
+
};
|
|
446
359
|
}
|
|
447
360
|
function resolveAppRouterHandler(entry) {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
console.error("[vinext] App Router entry must export either a default handler function or a Worker-style default export with fetch()");
|
|
458
|
-
process.exit(1);
|
|
361
|
+
if (typeof entry === "function") return (request) => Promise.resolve(entry(request));
|
|
362
|
+
if (entry && typeof entry === "object" && "fetch" in entry) {
|
|
363
|
+
const workerEntry = entry;
|
|
364
|
+
if (typeof workerEntry.fetch === "function") return (request) => Promise.resolve(workerEntry.fetch(request, void 0, createNodeExecutionContext()));
|
|
365
|
+
}
|
|
366
|
+
console.error("[vinext] App Router entry must export either a default handler function or a Worker-style default export with fetch()");
|
|
367
|
+
process.exit(1);
|
|
459
368
|
}
|
|
460
369
|
/**
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
370
|
+
* Start the App Router production server.
|
|
371
|
+
*
|
|
372
|
+
* The App Router entry (dist/server/index.js) can export either:
|
|
373
|
+
* - a default handler function: handler(request: Request) → Promise<Response>
|
|
374
|
+
* - a Worker-style object: { fetch(request, env, ctx) → Promise<Response> }
|
|
375
|
+
*
|
|
376
|
+
* This handler already does everything: route matching, RSC rendering,
|
|
377
|
+
* SSR HTML generation (via import("./ssr/index.js")), route handlers,
|
|
378
|
+
* server actions, ISR caching, 404s, redirects, etc.
|
|
379
|
+
*
|
|
380
|
+
* The production server's job is simply to:
|
|
381
|
+
* 1. Serve static assets from dist/client/
|
|
382
|
+
* 2. Convert Node.js IncomingMessage → Web Request
|
|
383
|
+
* 3. Call the RSC handler
|
|
384
|
+
* 4. Stream the Web Response back (with optional compression)
|
|
385
|
+
*/
|
|
477
386
|
async function startAppRouterServer(options) {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
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
|
-
// Convert Node.js request to Web Request and call the RSC handler
|
|
559
|
-
const request = nodeToWebRequest(req, normalizedUrl);
|
|
560
|
-
const response = await rscHandler(request);
|
|
561
|
-
// Stream the Web Response back to the Node.js response
|
|
562
|
-
await sendWebResponse(response, req, res, compress);
|
|
563
|
-
}
|
|
564
|
-
catch (e) {
|
|
565
|
-
console.error("[vinext] Server error:", e);
|
|
566
|
-
if (!res.headersSent) {
|
|
567
|
-
res.writeHead(500);
|
|
568
|
-
res.end("Internal Server Error");
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
});
|
|
572
|
-
await new Promise((resolve) => {
|
|
573
|
-
server.listen(port, host, () => {
|
|
574
|
-
const addr = server.address();
|
|
575
|
-
const actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
576
|
-
console.log(`[vinext] Production server running at http://${host}:${actualPort}`);
|
|
577
|
-
resolve();
|
|
578
|
-
});
|
|
579
|
-
});
|
|
580
|
-
return server;
|
|
387
|
+
const { port, host, clientDir, rscEntryPath, compress } = options;
|
|
388
|
+
let imageConfig;
|
|
389
|
+
const imageConfigPath = path.join(path.dirname(rscEntryPath), "image-config.json");
|
|
390
|
+
if (fs.existsSync(imageConfigPath)) try {
|
|
391
|
+
imageConfig = JSON.parse(fs.readFileSync(imageConfigPath, "utf-8"));
|
|
392
|
+
} catch {}
|
|
393
|
+
const prerenderSecret = readPrerenderSecret(path.dirname(rscEntryPath));
|
|
394
|
+
const rscMtime = fs.statSync(rscEntryPath).mtimeMs;
|
|
395
|
+
const rscHandler = resolveAppRouterHandler((await import(`${pathToFileURL(rscEntryPath).href}?t=${rscMtime}`)).default);
|
|
396
|
+
const server = createServer(async (req, res) => {
|
|
397
|
+
const rawUrl = req.url ?? "/";
|
|
398
|
+
const rawPathname = rawUrl.split("?")[0].replaceAll("\\", "/");
|
|
399
|
+
let pathname;
|
|
400
|
+
try {
|
|
401
|
+
pathname = normalizePath(normalizePathnameForRouteMatchStrict(rawPathname));
|
|
402
|
+
} catch {
|
|
403
|
+
res.writeHead(400);
|
|
404
|
+
res.end("Bad Request");
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (rawPathname.startsWith("//")) {
|
|
408
|
+
res.writeHead(404);
|
|
409
|
+
res.end("404 Not Found");
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
if (pathname === "/__vinext/prerender/static-params" || pathname === "/__vinext/prerender/pages-static-paths") {
|
|
413
|
+
const secret = req.headers["x-vinext-prerender-secret"];
|
|
414
|
+
if (!prerenderSecret || secret !== prerenderSecret) {
|
|
415
|
+
res.writeHead(403);
|
|
416
|
+
res.end("Forbidden");
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (pathname !== "/" && tryServeStatic(req, res, clientDir, pathname, compress)) return;
|
|
421
|
+
if (pathname === "/_vinext/image") {
|
|
422
|
+
const params = parseImageParams(new URL(rawUrl, "http://localhost"), [...DEFAULT_DEVICE_SIZES, ...DEFAULT_IMAGE_SIZES]);
|
|
423
|
+
if (!params) {
|
|
424
|
+
res.writeHead(400);
|
|
425
|
+
res.end("Bad Request");
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (!isSafeImageContentType(CONTENT_TYPES[path.extname(params.imageUrl).toLowerCase()] ?? "application/octet-stream", imageConfig?.dangerouslyAllowSVG)) {
|
|
429
|
+
res.writeHead(400);
|
|
430
|
+
res.end("The requested resource is not an allowed image type");
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
const imageSecurityHeaders = {
|
|
434
|
+
"Content-Security-Policy": imageConfig?.contentSecurityPolicy ?? "script-src 'none'; frame-src 'none'; sandbox;",
|
|
435
|
+
"X-Content-Type-Options": "nosniff",
|
|
436
|
+
"Content-Disposition": imageConfig?.contentDispositionType === "attachment" ? "attachment" : "inline"
|
|
437
|
+
};
|
|
438
|
+
if (tryServeStatic(req, res, clientDir, params.imageUrl, false, imageSecurityHeaders)) return;
|
|
439
|
+
res.writeHead(404);
|
|
440
|
+
res.end("Image not found");
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
try {
|
|
444
|
+
const qs = rawUrl.includes("?") ? rawUrl.slice(rawUrl.indexOf("?")) : "";
|
|
445
|
+
await sendWebResponse(await rscHandler(nodeToWebRequest(req, pathname + qs)), req, res, compress);
|
|
446
|
+
} catch (e) {
|
|
447
|
+
console.error("[vinext] Server error:", e);
|
|
448
|
+
if (!res.headersSent) {
|
|
449
|
+
res.writeHead(500);
|
|
450
|
+
res.end("Internal Server Error");
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
await new Promise((resolve) => {
|
|
455
|
+
server.listen(port, host, () => {
|
|
456
|
+
const addr = server.address();
|
|
457
|
+
const actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
458
|
+
console.log(`[vinext] Production server running at http://${host}:${actualPort}`);
|
|
459
|
+
resolve();
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
const addr = server.address();
|
|
463
|
+
return {
|
|
464
|
+
server,
|
|
465
|
+
port: typeof addr === "object" && addr ? addr.port : port
|
|
466
|
+
};
|
|
581
467
|
}
|
|
582
468
|
/**
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
469
|
+
* Start the Pages Router production server.
|
|
470
|
+
*
|
|
471
|
+
* Uses the server entry (dist/server/entry.js) which exports:
|
|
472
|
+
* - renderPage(request, url, manifest) — SSR rendering (Web Request → Response)
|
|
473
|
+
* - handleApiRoute(request, url) — API route handling (Web Request → Response)
|
|
474
|
+
* - runMiddleware(request, ctx?) — middleware execution (ctx optional; pass for ctx.waitUntil() on Workers)
|
|
475
|
+
* - vinextConfig — embedded next.config.js settings
|
|
476
|
+
*/
|
|
591
477
|
async function startPagesRouterServer(options) {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
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
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
for (const h of matched) {
|
|
878
|
-
const lk = h.key.toLowerCase();
|
|
879
|
-
if (lk === "set-cookie") {
|
|
880
|
-
const existing = middlewareHeaders[lk];
|
|
881
|
-
if (Array.isArray(existing)) {
|
|
882
|
-
existing.push(h.value);
|
|
883
|
-
}
|
|
884
|
-
else if (existing) {
|
|
885
|
-
middlewareHeaders[lk] = [existing, h.value];
|
|
886
|
-
}
|
|
887
|
-
else {
|
|
888
|
-
middlewareHeaders[lk] = [h.value];
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
else if (lk === "vary" && middlewareHeaders[lk]) {
|
|
892
|
-
middlewareHeaders[lk] += ", " + h.value;
|
|
893
|
-
}
|
|
894
|
-
else if (!(lk in middlewareHeaders)) {
|
|
895
|
-
// Middleware headers take precedence: only set if middleware
|
|
896
|
-
// did not already place this key on the response.
|
|
897
|
-
middlewareHeaders[lk] = h.value;
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
// ── 7. Apply beforeFiles rewrites from next.config.js ─────────
|
|
902
|
-
if (configRewrites.beforeFiles?.length) {
|
|
903
|
-
const rewritten = matchRewrite(resolvedPathname, configRewrites.beforeFiles, postMwReqCtx);
|
|
904
|
-
if (rewritten) {
|
|
905
|
-
if (isExternalUrl(rewritten)) {
|
|
906
|
-
const proxyResponse = await proxyExternalRequest(webRequest, rewritten);
|
|
907
|
-
await sendWebResponse(proxyResponse, req, res, compress);
|
|
908
|
-
return;
|
|
909
|
-
}
|
|
910
|
-
resolvedUrl = rewritten;
|
|
911
|
-
resolvedPathname = rewritten.split("?")[0];
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
// ── 8. API routes ─────────────────────────────────────────────
|
|
915
|
-
if (resolvedPathname.startsWith("/api/") || resolvedPathname === "/api") {
|
|
916
|
-
let response;
|
|
917
|
-
if (typeof handleApi === "function") {
|
|
918
|
-
response = await handleApi(webRequest, resolvedUrl);
|
|
919
|
-
}
|
|
920
|
-
else {
|
|
921
|
-
response = new Response("404 - API route not found", { status: 404 });
|
|
922
|
-
}
|
|
923
|
-
// Merge middleware + config headers into the response
|
|
924
|
-
const responseBody = Buffer.from(await response.arrayBuffer());
|
|
925
|
-
// API routes may return arbitrary data (JSON, binary, etc.), so
|
|
926
|
-
// default to application/octet-stream rather than text/html when
|
|
927
|
-
// the handler doesn't set an explicit Content-Type.
|
|
928
|
-
const ct = response.headers.get("content-type") ?? "application/octet-stream";
|
|
929
|
-
const responseHeaders = mergeResponseHeaders(middlewareHeaders, response);
|
|
930
|
-
const finalStatus = middlewareRewriteStatus ?? response.status;
|
|
931
|
-
const finalStatusText = finalStatus === response.status ? response.statusText || undefined : undefined;
|
|
932
|
-
sendCompressed(req, res, responseBody, ct, finalStatus, responseHeaders, compress, finalStatusText);
|
|
933
|
-
return;
|
|
934
|
-
}
|
|
935
|
-
// ── 9. Apply afterFiles rewrites from next.config.js ──────────
|
|
936
|
-
if (configRewrites.afterFiles?.length) {
|
|
937
|
-
const rewritten = matchRewrite(resolvedPathname, configRewrites.afterFiles, postMwReqCtx);
|
|
938
|
-
if (rewritten) {
|
|
939
|
-
if (isExternalUrl(rewritten)) {
|
|
940
|
-
const proxyResponse = await proxyExternalRequest(webRequest, rewritten);
|
|
941
|
-
await sendWebResponse(proxyResponse, req, res, compress);
|
|
942
|
-
return;
|
|
943
|
-
}
|
|
944
|
-
resolvedUrl = rewritten;
|
|
945
|
-
resolvedPathname = rewritten.split("?")[0];
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
// ── 10. SSR page rendering ────────────────────────────────────
|
|
949
|
-
let response;
|
|
950
|
-
if (typeof renderPage === "function") {
|
|
951
|
-
response = await renderPage(webRequest, resolvedUrl, ssrManifest);
|
|
952
|
-
// ── 11. Fallback rewrites (if SSR returned 404) ─────────────
|
|
953
|
-
if (response && response.status === 404 && configRewrites.fallback?.length) {
|
|
954
|
-
const fallbackRewrite = matchRewrite(resolvedPathname, configRewrites.fallback, postMwReqCtx);
|
|
955
|
-
if (fallbackRewrite) {
|
|
956
|
-
if (isExternalUrl(fallbackRewrite)) {
|
|
957
|
-
const proxyResponse = await proxyExternalRequest(webRequest, fallbackRewrite);
|
|
958
|
-
await sendWebResponse(proxyResponse, req, res, compress);
|
|
959
|
-
return;
|
|
960
|
-
}
|
|
961
|
-
response = await renderPage(webRequest, fallbackRewrite, ssrManifest);
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
if (!response) {
|
|
966
|
-
res.writeHead(404);
|
|
967
|
-
res.end("404 - Not found");
|
|
968
|
-
return;
|
|
969
|
-
}
|
|
970
|
-
// Merge middleware + config headers into the response
|
|
971
|
-
const responseBody = Buffer.from(await response.arrayBuffer());
|
|
972
|
-
const ct = response.headers.get("content-type") ?? "text/html";
|
|
973
|
-
const responseHeaders = mergeResponseHeaders(middlewareHeaders, response);
|
|
974
|
-
const finalStatus = middlewareRewriteStatus ?? response.status;
|
|
975
|
-
const finalStatusText = finalStatus === response.status ? response.statusText || undefined : undefined;
|
|
976
|
-
sendCompressed(req, res, responseBody, ct, finalStatus, responseHeaders, compress, finalStatusText);
|
|
977
|
-
}
|
|
978
|
-
catch (e) {
|
|
979
|
-
console.error("[vinext] Server error:", e);
|
|
980
|
-
if (!res.headersSent) {
|
|
981
|
-
res.writeHead(500);
|
|
982
|
-
res.end("Internal Server Error");
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
});
|
|
986
|
-
await new Promise((resolve) => {
|
|
987
|
-
server.listen(port, host, () => {
|
|
988
|
-
const addr = server.address();
|
|
989
|
-
const actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
990
|
-
console.log(`[vinext] Production server running at http://${host}:${actualPort}`);
|
|
991
|
-
resolve();
|
|
992
|
-
});
|
|
993
|
-
});
|
|
994
|
-
return server;
|
|
478
|
+
const { port, host, clientDir, serverEntryPath, compress } = options;
|
|
479
|
+
const serverMtime = fs.statSync(serverEntryPath).mtimeMs;
|
|
480
|
+
const serverEntry = await import(`${pathToFileURL(serverEntryPath).href}?t=${serverMtime}`);
|
|
481
|
+
const { renderPage, handleApiRoute: handleApi, runMiddleware, vinextConfig } = serverEntry;
|
|
482
|
+
const prerenderSecret = readPrerenderSecret(path.dirname(serverEntryPath));
|
|
483
|
+
const basePath = vinextConfig?.basePath ?? "";
|
|
484
|
+
const assetBase = basePath ? `${basePath}/` : "/";
|
|
485
|
+
const trailingSlash = vinextConfig?.trailingSlash ?? false;
|
|
486
|
+
const configRedirects = vinextConfig?.redirects ?? [];
|
|
487
|
+
const configRewrites = vinextConfig?.rewrites ?? {
|
|
488
|
+
beforeFiles: [],
|
|
489
|
+
afterFiles: [],
|
|
490
|
+
fallback: []
|
|
491
|
+
};
|
|
492
|
+
const configHeaders = vinextConfig?.headers ?? [];
|
|
493
|
+
const allowedImageWidths = [...vinextConfig?.images?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...vinextConfig?.images?.imageSizes ?? DEFAULT_IMAGE_SIZES];
|
|
494
|
+
const pagesImageConfig = vinextConfig?.images ? {
|
|
495
|
+
dangerouslyAllowSVG: vinextConfig.images.dangerouslyAllowSVG,
|
|
496
|
+
contentDispositionType: vinextConfig.images.contentDispositionType,
|
|
497
|
+
contentSecurityPolicy: vinextConfig.images.contentSecurityPolicy
|
|
498
|
+
} : void 0;
|
|
499
|
+
let ssrManifest = {};
|
|
500
|
+
const manifestPath = path.join(clientDir, ".vite", "ssr-manifest.json");
|
|
501
|
+
if (fs.existsSync(manifestPath)) ssrManifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
502
|
+
const buildManifestPath = path.join(clientDir, ".vite", "manifest.json");
|
|
503
|
+
if (fs.existsSync(buildManifestPath)) try {
|
|
504
|
+
const lazyChunks = computeLazyChunks(JSON.parse(fs.readFileSync(buildManifestPath, "utf-8"))).map((file) => manifestFileWithBase(file, assetBase));
|
|
505
|
+
if (lazyChunks.length > 0) globalThis.__VINEXT_LAZY_CHUNKS__ = lazyChunks;
|
|
506
|
+
} catch {}
|
|
507
|
+
const server = createServer(async (req, res) => {
|
|
508
|
+
const rawUrl = req.url ?? "/";
|
|
509
|
+
const rawPagesPathname = rawUrl.split("?")[0].replaceAll("\\", "/");
|
|
510
|
+
const rawQs = rawUrl.includes("?") ? rawUrl.slice(rawUrl.indexOf("?")) : "";
|
|
511
|
+
let pathname;
|
|
512
|
+
try {
|
|
513
|
+
pathname = normalizePath(normalizePathnameForRouteMatchStrict(rawPagesPathname));
|
|
514
|
+
} catch {
|
|
515
|
+
res.writeHead(400);
|
|
516
|
+
res.end("Bad Request");
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
let url = pathname + rawQs;
|
|
520
|
+
if (rawPagesPathname.startsWith("//")) {
|
|
521
|
+
res.writeHead(404);
|
|
522
|
+
res.end("404 Not Found");
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
if (pathname === "/__vinext/prerender/pages-static-paths") {
|
|
526
|
+
const secret = req.headers["x-vinext-prerender-secret"];
|
|
527
|
+
if (!prerenderSecret || secret !== prerenderSecret) {
|
|
528
|
+
res.writeHead(403);
|
|
529
|
+
res.end("Forbidden");
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
const parsedUrl = new URL(rawUrl, "http://localhost");
|
|
533
|
+
const pattern = parsedUrl.searchParams.get("pattern") ?? "";
|
|
534
|
+
const localesRaw = parsedUrl.searchParams.get("locales");
|
|
535
|
+
const locales = localesRaw ? JSON.parse(localesRaw) : [];
|
|
536
|
+
const defaultLocale = parsedUrl.searchParams.get("defaultLocale") ?? "";
|
|
537
|
+
const fn = (serverEntry.pageRoutes?.find((r) => r.pattern === pattern))?.module?.getStaticPaths;
|
|
538
|
+
if (typeof fn !== "function") {
|
|
539
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
540
|
+
res.end("null");
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
try {
|
|
544
|
+
const result = await fn({
|
|
545
|
+
locales,
|
|
546
|
+
defaultLocale
|
|
547
|
+
});
|
|
548
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
549
|
+
res.end(JSON.stringify(result));
|
|
550
|
+
} catch (e) {
|
|
551
|
+
res.writeHead(500);
|
|
552
|
+
res.end(e.message);
|
|
553
|
+
}
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
const staticLookupPath = stripBasePath(pathname, basePath);
|
|
557
|
+
if (staticLookupPath !== "/" && !staticLookupPath.startsWith("/api/") && tryServeStatic(req, res, clientDir, staticLookupPath, compress)) return;
|
|
558
|
+
if (pathname === "/_vinext/image" || staticLookupPath === "/_vinext/image") {
|
|
559
|
+
const params = parseImageParams(new URL(rawUrl, "http://localhost"), allowedImageWidths);
|
|
560
|
+
if (!params) {
|
|
561
|
+
res.writeHead(400);
|
|
562
|
+
res.end("Bad Request");
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
if (!isSafeImageContentType(CONTENT_TYPES[path.extname(params.imageUrl).toLowerCase()] ?? "application/octet-stream", pagesImageConfig?.dangerouslyAllowSVG)) {
|
|
566
|
+
res.writeHead(400);
|
|
567
|
+
res.end("The requested resource is not an allowed image type");
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
const imageSecurityHeaders = {
|
|
571
|
+
"Content-Security-Policy": pagesImageConfig?.contentSecurityPolicy ?? "script-src 'none'; frame-src 'none'; sandbox;",
|
|
572
|
+
"X-Content-Type-Options": "nosniff",
|
|
573
|
+
"Content-Disposition": pagesImageConfig?.contentDispositionType === "attachment" ? "attachment" : "inline"
|
|
574
|
+
};
|
|
575
|
+
if (tryServeStatic(req, res, clientDir, params.imageUrl, false, imageSecurityHeaders)) return;
|
|
576
|
+
res.writeHead(404);
|
|
577
|
+
res.end("Image not found");
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
try {
|
|
581
|
+
{
|
|
582
|
+
const stripped = stripBasePath(pathname, basePath);
|
|
583
|
+
if (stripped !== pathname) {
|
|
584
|
+
url = stripped + (url.includes("?") ? url.slice(url.indexOf("?")) : "");
|
|
585
|
+
pathname = stripped;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (pathname !== "/" && pathname !== "/api" && !pathname.startsWith("/api/")) {
|
|
589
|
+
const hasTrailing = pathname.endsWith("/");
|
|
590
|
+
if (trailingSlash && !hasTrailing) {
|
|
591
|
+
const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
|
|
592
|
+
res.writeHead(308, { Location: basePath + pathname + "/" + qs });
|
|
593
|
+
res.end();
|
|
594
|
+
return;
|
|
595
|
+
} else if (!trailingSlash && hasTrailing) {
|
|
596
|
+
const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
|
|
597
|
+
res.writeHead(308, { Location: basePath + pathname.replace(/\/+$/, "") + qs });
|
|
598
|
+
res.end();
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
const rawProtocol = trustProxy ? req.headers["x-forwarded-proto"]?.split(",")[0]?.trim() : void 0;
|
|
603
|
+
const protocol = rawProtocol === "https" || rawProtocol === "http" ? rawProtocol : "http";
|
|
604
|
+
const hostHeader = resolveHost(req, `${host}:${port}`);
|
|
605
|
+
const reqHeaders = Object.entries(req.headers).reduce((h, [k, v]) => {
|
|
606
|
+
if (v) h.set(k, Array.isArray(v) ? v.join(", ") : v);
|
|
607
|
+
return h;
|
|
608
|
+
}, new Headers());
|
|
609
|
+
const method = req.method ?? "GET";
|
|
610
|
+
const hasBody = method !== "GET" && method !== "HEAD";
|
|
611
|
+
let webRequest = new Request(`${protocol}://${hostHeader}${url}`, {
|
|
612
|
+
method,
|
|
613
|
+
headers: reqHeaders,
|
|
614
|
+
body: hasBody ? readNodeStream(req) : void 0,
|
|
615
|
+
duplex: hasBody ? "half" : void 0
|
|
616
|
+
});
|
|
617
|
+
const reqCtx = requestContextFromRequest(webRequest);
|
|
618
|
+
if (configRedirects.length) {
|
|
619
|
+
const redirect = matchRedirect(pathname, configRedirects, reqCtx);
|
|
620
|
+
if (redirect) {
|
|
621
|
+
const dest = sanitizeDestination(basePath && !isExternalUrl(redirect.destination) && !hasBasePath(redirect.destination, basePath) ? basePath + redirect.destination : redirect.destination);
|
|
622
|
+
res.writeHead(redirect.permanent ? 308 : 307, { Location: dest });
|
|
623
|
+
res.end();
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
let resolvedUrl = url;
|
|
628
|
+
const middlewareHeaders = {};
|
|
629
|
+
let middlewareRewriteStatus;
|
|
630
|
+
if (typeof runMiddleware === "function") {
|
|
631
|
+
const result = await runMiddleware(webRequest, void 0);
|
|
632
|
+
if (!result.continue) {
|
|
633
|
+
if (result.redirectUrl) {
|
|
634
|
+
const redirectHeaders = { Location: result.redirectUrl };
|
|
635
|
+
if (result.responseHeaders) for (const [key, value] of result.responseHeaders) {
|
|
636
|
+
const existing = redirectHeaders[key];
|
|
637
|
+
if (existing === void 0) redirectHeaders[key] = value;
|
|
638
|
+
else if (Array.isArray(existing)) existing.push(value);
|
|
639
|
+
else redirectHeaders[key] = [existing, value];
|
|
640
|
+
}
|
|
641
|
+
res.writeHead(result.redirectStatus ?? 307, redirectHeaders);
|
|
642
|
+
res.end();
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
if (result.response) {
|
|
646
|
+
const body = Buffer.from(await result.response.arrayBuffer());
|
|
647
|
+
const respHeaders = {};
|
|
648
|
+
result.response.headers.forEach((value, key) => {
|
|
649
|
+
if (key === "set-cookie") return;
|
|
650
|
+
respHeaders[key] = value;
|
|
651
|
+
});
|
|
652
|
+
const setCookies = result.response.headers.getSetCookie?.() ?? [];
|
|
653
|
+
if (setCookies.length > 0) respHeaders["set-cookie"] = setCookies;
|
|
654
|
+
if (result.response.statusText) res.writeHead(result.response.status, result.response.statusText, respHeaders);
|
|
655
|
+
else res.writeHead(result.response.status, respHeaders);
|
|
656
|
+
res.end(body);
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
if (result.responseHeaders) for (const [key, value] of result.responseHeaders) if (key === "set-cookie") {
|
|
661
|
+
const existing = middlewareHeaders[key];
|
|
662
|
+
if (Array.isArray(existing)) existing.push(value);
|
|
663
|
+
else if (existing) middlewareHeaders[key] = [existing, value];
|
|
664
|
+
else middlewareHeaders[key] = [value];
|
|
665
|
+
} else middlewareHeaders[key] = value;
|
|
666
|
+
if (result.rewriteUrl) resolvedUrl = result.rewriteUrl;
|
|
667
|
+
middlewareRewriteStatus = result.rewriteStatus;
|
|
668
|
+
}
|
|
669
|
+
const { postMwReqCtx, request: postMwReq } = applyMiddlewareRequestHeaders(middlewareHeaders, webRequest);
|
|
670
|
+
webRequest = postMwReq;
|
|
671
|
+
let resolvedPathname = resolvedUrl.split("?")[0];
|
|
672
|
+
if (configHeaders.length) {
|
|
673
|
+
const matched = matchHeaders(pathname, configHeaders, reqCtx);
|
|
674
|
+
for (const h of matched) {
|
|
675
|
+
const lk = h.key.toLowerCase();
|
|
676
|
+
if (lk === "set-cookie") {
|
|
677
|
+
const existing = middlewareHeaders[lk];
|
|
678
|
+
if (Array.isArray(existing)) existing.push(h.value);
|
|
679
|
+
else if (existing) middlewareHeaders[lk] = [existing, h.value];
|
|
680
|
+
else middlewareHeaders[lk] = [h.value];
|
|
681
|
+
} else if (lk === "vary" && middlewareHeaders[lk]) middlewareHeaders[lk] += ", " + h.value;
|
|
682
|
+
else if (!(lk in middlewareHeaders)) middlewareHeaders[lk] = h.value;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
if (configRewrites.beforeFiles?.length) {
|
|
686
|
+
const rewritten = matchRewrite(resolvedPathname, configRewrites.beforeFiles, postMwReqCtx);
|
|
687
|
+
if (rewritten) {
|
|
688
|
+
if (isExternalUrl(rewritten)) {
|
|
689
|
+
await sendWebResponse(await proxyExternalRequest(webRequest, rewritten), req, res, compress);
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
resolvedUrl = rewritten;
|
|
693
|
+
resolvedPathname = rewritten.split("?")[0];
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
if (resolvedPathname.startsWith("/api/") || resolvedPathname === "/api") {
|
|
697
|
+
let response;
|
|
698
|
+
if (typeof handleApi === "function") response = await handleApi(webRequest, resolvedUrl);
|
|
699
|
+
else response = new Response("404 - API route not found", { status: 404 });
|
|
700
|
+
const responseBody = Buffer.from(await response.arrayBuffer());
|
|
701
|
+
const ct = response.headers.get("content-type") ?? "application/octet-stream";
|
|
702
|
+
const responseHeaders = mergeResponseHeaders(middlewareHeaders, response);
|
|
703
|
+
const finalStatus = middlewareRewriteStatus ?? response.status;
|
|
704
|
+
sendCompressed(req, res, responseBody, ct, finalStatus, responseHeaders, compress, finalStatus === response.status ? response.statusText || void 0 : void 0);
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
if (configRewrites.afterFiles?.length) {
|
|
708
|
+
const rewritten = matchRewrite(resolvedPathname, configRewrites.afterFiles, postMwReqCtx);
|
|
709
|
+
if (rewritten) {
|
|
710
|
+
if (isExternalUrl(rewritten)) {
|
|
711
|
+
await sendWebResponse(await proxyExternalRequest(webRequest, rewritten), req, res, compress);
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
resolvedUrl = rewritten;
|
|
715
|
+
resolvedPathname = rewritten.split("?")[0];
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
let response;
|
|
719
|
+
if (typeof renderPage === "function") {
|
|
720
|
+
response = await renderPage(webRequest, resolvedUrl, ssrManifest);
|
|
721
|
+
if (response && response.status === 404 && configRewrites.fallback?.length) {
|
|
722
|
+
const fallbackRewrite = matchRewrite(resolvedPathname, configRewrites.fallback, postMwReqCtx);
|
|
723
|
+
if (fallbackRewrite) {
|
|
724
|
+
if (isExternalUrl(fallbackRewrite)) {
|
|
725
|
+
await sendWebResponse(await proxyExternalRequest(webRequest, fallbackRewrite), req, res, compress);
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
response = await renderPage(webRequest, fallbackRewrite, ssrManifest);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
if (!response) {
|
|
733
|
+
res.writeHead(404);
|
|
734
|
+
res.end("404 - Not found");
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
const responseBody = Buffer.from(await response.arrayBuffer());
|
|
738
|
+
const ct = response.headers.get("content-type") ?? "text/html";
|
|
739
|
+
const responseHeaders = mergeResponseHeaders(middlewareHeaders, response);
|
|
740
|
+
const finalStatus = middlewareRewriteStatus ?? response.status;
|
|
741
|
+
sendCompressed(req, res, responseBody, ct, finalStatus, responseHeaders, compress, finalStatus === response.status ? response.statusText || void 0 : void 0);
|
|
742
|
+
} catch (e) {
|
|
743
|
+
console.error("[vinext] Server error:", e);
|
|
744
|
+
if (!res.headersSent) {
|
|
745
|
+
res.writeHead(500);
|
|
746
|
+
res.end("Internal Server Error");
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
await new Promise((resolve) => {
|
|
751
|
+
server.listen(port, host, () => {
|
|
752
|
+
const addr = server.address();
|
|
753
|
+
const actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
754
|
+
console.log(`[vinext] Production server running at http://${host}:${actualPort}`);
|
|
755
|
+
resolve();
|
|
756
|
+
});
|
|
757
|
+
});
|
|
758
|
+
const addr = server.address();
|
|
759
|
+
return {
|
|
760
|
+
server,
|
|
761
|
+
port: typeof addr === "object" && addr ? addr.port : port
|
|
762
|
+
};
|
|
995
763
|
}
|
|
996
|
-
|
|
997
|
-
export {
|
|
764
|
+
//#endregion
|
|
765
|
+
export { COMPRESSIBLE_TYPES, COMPRESS_THRESHOLD, mergeResponseHeaders, negotiateEncoding, nodeToWebRequest, resolveHost, sendCompressed, startProdServer, trustProxy, trustedHosts };
|
|
766
|
+
|
|
998
767
|
//# sourceMappingURL=prod-server.js.map
|