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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tpr.js","sourceRoot":"","sources":["../../src/cloudflare/tpr.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * TPR: Traffic-aware Pre-Rendering\n *\n * Uses Cloudflare zone analytics to determine which pages actually get\n * traffic, and pre-renders only those during deploy. The pre-rendered\n * HTML is uploaded to KV in the same format ISR uses at runtime — no\n * runtime changes needed.\n *\n * Flow:\n * 1. Parse wrangler config to find custom domain and KV namespace\n * 2. Resolve the Cloudflare zone for the custom domain\n * 3. Query zone analytics (GraphQL) for top pages by request count\n * 4. Walk ranked list until coverage threshold is met\n * 5. Start the built production server locally\n * 6. Fetch each hot route to produce HTML\n * 7. Upload pre-rendered HTML to KV (same KVCacheEntry format ISR reads)\n *\n * TPR is an experimental feature enabled via --experimental-tpr. It\n * gracefully skips when no custom domain, no API token, no traffic data,\n * or no KV namespace is configured.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { spawn, type ChildProcess } from \"node:child_process\";\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport interface TPROptions {\n /** Project root directory. */\n root: string;\n /** Traffic coverage percentage (0–100). Default: 90. */\n coverage: number;\n /** Hard cap on number of pages to pre-render. Default: 1000. */\n limit: number;\n /** Analytics lookback window in hours. Default: 24. */\n window: number;\n}\n\nexport interface TPRResult {\n /** Total unique page paths found in analytics. */\n totalPaths: number;\n /** Number of pages successfully pre-rendered and uploaded. */\n prerenderedCount: number;\n /** Actual traffic coverage achieved (percentage). */\n coverageAchieved: number;\n /** Wall-clock duration of the TPR step in milliseconds. */\n durationMs: number;\n /** If TPR was skipped, the reason. */\n skipped?: string;\n}\n\ninterface TrafficEntry {\n path: string;\n requests: number;\n}\n\ninterface SelectedRoutes {\n routes: TrafficEntry[];\n totalRequests: number;\n coveredRequests: number;\n coveragePercent: number;\n}\n\ninterface PrerenderResult {\n html: string;\n status: number;\n headers: Record<string, string>;\n}\n\ninterface WranglerConfig {\n accountId?: string;\n kvNamespaceId?: string;\n customDomain?: string;\n}\n\n// ─── Wrangler Config Parsing ─────────────────────────────────────────────────\n\n/**\n * Parse wrangler config (JSONC or TOML) to extract the fields TPR needs:\n * account_id, VINEXT_CACHE KV namespace ID, and custom domain.\n */\nexport function parseWranglerConfig(root: string): WranglerConfig | null {\n // Try JSONC / JSON first\n for (const filename of [\"wrangler.jsonc\", \"wrangler.json\"]) {\n const filepath = path.join(root, filename);\n if (fs.existsSync(filepath)) {\n const content = fs.readFileSync(filepath, \"utf-8\");\n try {\n const json = JSON.parse(stripJsonComments(content));\n return extractFromJSON(json);\n } catch {\n continue;\n }\n }\n }\n\n // Try TOML\n const tomlPath = path.join(root, \"wrangler.toml\");\n if (fs.existsSync(tomlPath)) {\n const content = fs.readFileSync(tomlPath, \"utf-8\");\n return extractFromTOML(content);\n }\n\n return null;\n}\n\n/**\n * Strip single-line (//) and multi-line comments from JSONC while\n * preserving strings that contain slashes.\n */\nfunction stripJsonComments(str: string): string {\n let result = \"\";\n let inString = false;\n let inSingleLine = false;\n let inMultiLine = false;\n let escapeNext = false;\n\n for (let i = 0; i < str.length; i++) {\n const ch = str[i];\n const next = str[i + 1];\n\n if (escapeNext) {\n if (!inSingleLine && !inMultiLine) result += ch;\n escapeNext = false;\n continue;\n }\n\n if (ch === \"\\\\\" && inString) {\n result += ch;\n escapeNext = true;\n continue;\n }\n\n if (inSingleLine) {\n if (ch === \"\\n\") {\n inSingleLine = false;\n result += ch;\n }\n continue;\n }\n\n if (inMultiLine) {\n if (ch === \"*\" && next === \"/\") {\n inMultiLine = false;\n i++;\n }\n continue;\n }\n\n if (ch === '\"' && !inString) {\n inString = true;\n result += ch;\n continue;\n }\n\n if (ch === '\"' && inString) {\n inString = false;\n result += ch;\n continue;\n }\n\n if (!inString && ch === \"/\" && next === \"/\") {\n inSingleLine = true;\n i++;\n continue;\n }\n\n if (!inString && ch === \"/\" && next === \"*\") {\n inMultiLine = true;\n i++;\n continue;\n }\n\n result += ch;\n }\n\n return result;\n}\n\nfunction extractFromJSON(config: Record<string, unknown>): WranglerConfig {\n const result: WranglerConfig = {};\n\n // account_id\n if (typeof config.account_id === \"string\") {\n result.accountId = config.account_id;\n }\n\n // KV namespace ID for VINEXT_CACHE\n if (Array.isArray(config.kv_namespaces)) {\n const vinextKV = config.kv_namespaces.find(\n (ns: Record<string, unknown>) =>\n ns && typeof ns === \"object\" && ns.binding === \"VINEXT_CACHE\",\n );\n if (vinextKV && typeof vinextKV.id === \"string\" && vinextKV.id !== \"<your-kv-namespace-id>\") {\n result.kvNamespaceId = vinextKV.id;\n }\n }\n\n // Custom domain — check routes[] and custom_domains[]\n const domain = extractDomainFromRoutes(config.routes) ?? extractDomainFromCustomDomains(config);\n if (domain) result.customDomain = domain;\n\n return result;\n}\n\nfunction extractDomainFromRoutes(routes: unknown): string | null {\n if (!Array.isArray(routes)) return null;\n\n for (const route of routes) {\n if (typeof route === \"string\") {\n const domain = cleanDomain(route);\n if (domain && !domain.includes(\"workers.dev\")) return domain;\n } else if (route && typeof route === \"object\") {\n const r = route as Record<string, unknown>;\n const pattern =\n typeof r.zone_name === \"string\"\n ? r.zone_name\n : typeof r.pattern === \"string\"\n ? r.pattern\n : null;\n if (pattern) {\n const domain = cleanDomain(pattern);\n if (domain && !domain.includes(\"workers.dev\")) return domain;\n }\n }\n }\n return null;\n}\n\nfunction extractDomainFromCustomDomains(config: Record<string, unknown>): string | null {\n // Workers Custom Domains: \"custom_domains\": [\"example.com\"]\n if (Array.isArray(config.custom_domains)) {\n for (const d of config.custom_domains) {\n if (typeof d === \"string\" && !d.includes(\"workers.dev\")) {\n return cleanDomain(d);\n }\n }\n }\n return null;\n}\n\n/** Strip protocol and trailing wildcards from a route pattern to get a bare domain. */\nfunction cleanDomain(raw: string): string | null {\n const cleaned = raw\n .replace(/^https?:\\/\\//, \"\")\n .replace(/\\/\\*$/, \"\")\n .replace(/\\/+$/, \"\")\n .split(\"/\")[0]; // Take only the host part\n return cleaned || null;\n}\n\n/**\n * Simple extraction of specific fields from wrangler.toml content.\n * Not a full TOML parser — just enough for the fields we need.\n */\nfunction extractFromTOML(content: string): WranglerConfig {\n const result: WranglerConfig = {};\n\n // account_id = \"...\"\n const accountMatch = content.match(/^account_id\\s*=\\s*\"([^\"]+)\"/m);\n if (accountMatch) result.accountId = accountMatch[1];\n\n // KV namespace with binding = \"VINEXT_CACHE\"\n // Look for [[kv_namespaces]] blocks\n const kvBlocks = content.split(/\\[\\[kv_namespaces\\]\\]/);\n for (let i = 1; i < kvBlocks.length; i++) {\n const block = kvBlocks[i].split(/\\[\\[/)[0]; // Take until next section\n const bindingMatch = block.match(/binding\\s*=\\s*\"([^\"]+)\"/);\n const idMatch = block.match(/\\bid\\s*=\\s*\"([^\"]+)\"/);\n if (\n bindingMatch?.[1] === \"VINEXT_CACHE\" &&\n idMatch?.[1] &&\n idMatch[1] !== \"<your-kv-namespace-id>\"\n ) {\n result.kvNamespaceId = idMatch[1];\n }\n }\n\n // routes — both string and table forms\n // route = \"example.com/*\"\n const routeMatch = content.match(/^route\\s*=\\s*\"([^\"]+)\"/m);\n if (routeMatch) {\n const domain = cleanDomain(routeMatch[1]);\n if (domain && !domain.includes(\"workers.dev\")) {\n result.customDomain = domain;\n }\n }\n\n // [[routes]] blocks\n if (!result.customDomain) {\n const routeBlocks = content.split(/\\[\\[routes\\]\\]/);\n for (let i = 1; i < routeBlocks.length; i++) {\n const block = routeBlocks[i].split(/\\[\\[/)[0];\n const patternMatch = block.match(/pattern\\s*=\\s*\"([^\"]+)\"/);\n if (patternMatch) {\n const domain = cleanDomain(patternMatch[1]);\n if (domain && !domain.includes(\"workers.dev\")) {\n result.customDomain = domain;\n break;\n }\n }\n }\n }\n\n return result;\n}\n\n// ─── Cloudflare API ──────────────────────────────────────────────────────────\n\n/**\n * Generate zone lookup candidates from shortest (2-part) to longest.\n * Tries the most common case first (e.g., \"example.com\") and progressively\n * adds labels for multi-part TLDs (e.g., \"co.uk\" → \"example.co.uk\").\n *\n * \"shop.example.com\" → [\"example.com\", \"shop.example.com\"]\n * \"shop.example.co.uk\" → [\"co.uk\", \"example.co.uk\", \"shop.example.co.uk\"]\n * \"example.com\" → [\"example.com\"]\n */\nexport function domainCandidates(domain: string): string[] {\n const parts = domain.split(\".\");\n const candidates: string[] = [];\n for (let i = parts.length - 2; i >= 0; i--) {\n candidates.push(parts.slice(i).join(\".\"));\n }\n return candidates;\n}\n\n/** Resolve zone ID from a domain name via the Cloudflare API. */\nasync function resolveZoneId(domain: string, apiToken: string): Promise<string | null> {\n // Try progressively longer domain candidates until one matches a zone.\n // This handles all public suffixes without a hardcoded TLD list —\n // for simple TLDs (.com, .io) the 2-part candidate hits on the first try;\n // for multi-part TLDs (.co.uk, .com.au) it takes one extra call.\n for (const candidate of domainCandidates(domain)) {\n const response = await fetch(\n `https://api.cloudflare.com/client/v4/zones?name=${encodeURIComponent(candidate)}`,\n {\n headers: {\n Authorization: `Bearer ${apiToken}`,\n \"Content-Type\": \"application/json\",\n },\n },\n );\n\n if (!response.ok) continue;\n\n const data = (await response.json()) as {\n success: boolean;\n result?: Array<{ id: string }>;\n };\n if (data.success && data.result?.length) {\n return data.result[0].id;\n }\n }\n\n return null;\n}\n\n/** Resolve the account ID associated with the API token. */\nasync function resolveAccountId(apiToken: string): Promise<string | null> {\n const response = await fetch(\"https://api.cloudflare.com/client/v4/accounts?per_page=1\", {\n headers: {\n Authorization: `Bearer ${apiToken}`,\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (!response.ok) return null;\n\n const data = (await response.json()) as {\n success: boolean;\n result?: Array<{ id: string }>;\n };\n if (!data.success || !data.result?.length) return null;\n\n return data.result[0].id;\n}\n\n// ─── Traffic Querying ────────────────────────────────────────────────────────\n\n/**\n * Query Cloudflare zone analytics for top page paths by request count\n * over the given time window.\n */\nasync function queryTraffic(\n zoneTag: string,\n apiToken: string,\n windowHours: number,\n): Promise<TrafficEntry[]> {\n const now = new Date();\n const start = new Date(now.getTime() - windowHours * 60 * 60 * 1000);\n\n const query = `{\n viewer {\n zones(filter: { zoneTag: \"${zoneTag}\" }) {\n httpRequestsAdaptiveGroups(\n limit: 10000\n orderBy: [sum_requests_DESC]\n filter: {\n datetime_geq: \"${start.toISOString()}\"\n datetime_lt: \"${now.toISOString()}\"\n requestSource: \"eyeball\"\n }\n ) {\n sum { requests }\n dimensions { clientRequestPath }\n }\n }\n }\n }`;\n\n const response = await fetch(\"https://api.cloudflare.com/client/v4/graphql\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ query }),\n });\n\n if (!response.ok) {\n throw new Error(`Zone analytics query failed: ${response.status} ${response.statusText}`);\n }\n\n const data = (await response.json()) as {\n errors?: Array<{ message: string }>;\n data?: {\n viewer?: {\n zones?: Array<{\n httpRequestsAdaptiveGroups?: Array<{\n sum: { requests: number };\n dimensions: { clientRequestPath: string };\n }>;\n }>;\n };\n };\n };\n\n if (data.errors?.length) {\n throw new Error(`Zone analytics error: ${data.errors[0].message}`);\n }\n\n const groups = data.data?.viewer?.zones?.[0]?.httpRequestsAdaptiveGroups;\n if (!groups || groups.length === 0) return [];\n\n return filterTrafficPaths(\n groups.map((g) => ({\n path: g.dimensions.clientRequestPath,\n requests: g.sum.requests,\n })),\n );\n}\n\n/** Filter out non-page requests (static assets, API routes, internal routes). */\nfunction filterTrafficPaths(entries: TrafficEntry[]): TrafficEntry[] {\n return entries.filter((e) => {\n if (!e.path.startsWith(\"/\")) return false;\n // Static assets\n if (/\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff2?|ttf|eot|map|webp|avif)$/i.test(e.path))\n return false;\n // API routes\n if (e.path.startsWith(\"/api/\")) return false;\n // Internal routes\n if (e.path.startsWith(\"/_vinext/\") || e.path.startsWith(\"/_next/\")) return false;\n // RSC requests\n if (e.path.endsWith(\".rsc\")) return false;\n return true;\n });\n}\n\n// ─── Route Selection ─────────────────────────────────────────────────────────\n\n/**\n * Walk the ranked traffic list, accumulating request counts until the\n * coverage target is met or the hard cap is reached.\n */\nexport function selectRoutes(\n traffic: TrafficEntry[],\n coverageTarget: number,\n limit: number,\n): SelectedRoutes {\n const totalRequests = traffic.reduce((sum, e) => sum + e.requests, 0);\n if (totalRequests === 0) {\n return { routes: [], totalRequests: 0, coveredRequests: 0, coveragePercent: 0 };\n }\n\n const target = totalRequests * (coverageTarget / 100);\n const selected: TrafficEntry[] = [];\n let accumulated = 0;\n\n // Traffic is already sorted DESC by requests from the GraphQL query\n for (const entry of traffic) {\n if (accumulated >= target || selected.length >= limit) break;\n selected.push(entry);\n accumulated += entry.requests;\n }\n\n return {\n routes: selected,\n totalRequests,\n coveredRequests: accumulated,\n coveragePercent: (accumulated / totalRequests) * 100,\n };\n}\n\n// ─── Pre-rendering ───────────────────────────────────────────────────────────\n\n/** Pre-render port — high number to avoid collisions with dev servers. */\nconst PRERENDER_PORT = 19384;\n\n/** Max time to wait for the local server to start (ms). */\nconst SERVER_STARTUP_TIMEOUT = 30_000;\n\n/** Max concurrent fetch requests during pre-rendering. */\nconst FETCH_CONCURRENCY = 10;\n\n/**\n * Start a local production server, fetch each route to produce HTML,\n * and return the results. Pages that fail to render are skipped.\n */\nasync function prerenderRoutes(\n routes: string[],\n root: string,\n hostDomain?: string,\n): Promise<Map<string, PrerenderResult>> {\n const results = new Map<string, PrerenderResult>();\n let failedCount = 0;\n const port = PRERENDER_PORT;\n\n // Verify dist/ exists\n const distDir = path.join(root, \"dist\");\n if (!fs.existsSync(distDir)) {\n console.log(\" TPR: Skipping pre-render — dist/ directory not found\");\n return results;\n }\n\n // Start the local production server as a subprocess\n const serverProcess = startLocalServer(root, port);\n\n try {\n await waitForServer(port, SERVER_STARTUP_TIMEOUT);\n\n // Fetch routes in batches to limit concurrency\n for (let i = 0; i < routes.length; i += FETCH_CONCURRENCY) {\n const batch = routes.slice(i, i + FETCH_CONCURRENCY);\n const promises = batch.map(async (routePath) => {\n try {\n const response = await fetch(`http://127.0.0.1:${port}${routePath}`, {\n headers: {\n \"User-Agent\": \"vinext-tpr/1.0\",\n ...(hostDomain ? { Host: hostDomain } : {}),\n },\n redirect: \"manual\", // Don't follow redirects — cache the redirect itself\n });\n\n // Only cache successful responses (2xx and 3xx)\n if (response.status < 400) {\n const html = await response.text();\n const headers: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n // Only keep relevant headers\n if (\n key === \"content-type\" ||\n key === \"cache-control\" ||\n key === \"x-vinext-revalidate\" ||\n key === \"location\"\n ) {\n headers[key] = value;\n }\n });\n results.set(routePath, {\n html,\n status: response.status,\n headers,\n });\n }\n } catch {\n // Skip pages that fail to render — they may depend on\n // request-specific data (cookies, headers, auth) that\n // isn't available during pre-rendering.\n failedCount++;\n }\n });\n\n await Promise.all(promises);\n }\n\n if (failedCount > 0) {\n console.log(` TPR: ${failedCount} page(s) failed to pre-render (skipped)`);\n }\n } finally {\n serverProcess.kill(\"SIGTERM\");\n // Give it a moment to clean up\n await new Promise<void>((resolve) => {\n serverProcess.on(\"exit\", resolve);\n setTimeout(resolve, 2000);\n });\n }\n\n return results;\n}\n\n/**\n * Spawn a subprocess running the vinext production server.\n * Uses the same Node.js binary and resolves prod-server.js relative\n * to the current module (works whether vinext is installed or linked).\n */\nfunction startLocalServer(root: string, port: number): ChildProcess {\n const thisDir = fileURLToPath(new URL(\".\", import.meta.url));\n const prodServerPath = path.resolve(thisDir, \"..\", \"server\", \"prod-server.js\");\n const outDir = path.join(root, \"dist\");\n\n // Escape backslashes for Windows paths inside the JS string\n const escapedProdServer = prodServerPath.replace(/\\\\/g, \"\\\\\\\\\");\n const escapedOutDir = outDir.replace(/\\\\/g, \"\\\\\\\\\");\n\n const script = [\n `import(\"file://${escapedProdServer}\")`,\n `.then(m => m.startProdServer({ port: ${port}, host: \"127.0.0.1\", outDir: \"${escapedOutDir}\" }))`,\n `.catch(e => { console.error(\"[vinext-tpr] Server failed to start:\", e); process.exit(1); });`,\n ].join(\"\");\n\n const proc = spawn(process.execPath, [\"--input-type=module\", \"-e\", script], {\n cwd: root,\n stdio: \"pipe\",\n env: { ...process.env, NODE_ENV: \"production\" },\n });\n\n // Forward server errors to the parent's stderr for debugging\n proc.stderr?.on(\"data\", (chunk: Buffer) => {\n const msg = chunk.toString().trim();\n if (msg) console.error(` [tpr-server] ${msg}`);\n });\n\n return proc;\n}\n\n/** Poll the local server until it responds or the timeout is reached. */\nasync function waitForServer(port: number, timeoutMs: number): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 2000);\n const response = await fetch(`http://127.0.0.1:${port}/`, {\n redirect: \"manual\",\n signal: controller.signal,\n });\n clearTimeout(timer);\n // Any response means the server is up\n await response.text(); // consume body\n return;\n } catch {\n await new Promise<void>((r) => setTimeout(r, 300));\n }\n }\n throw new Error(`Local production server failed to start within ${timeoutMs / 1000}s`);\n}\n\n// ─── KV Upload ───────────────────────────────────────────────────────────────\n\n/**\n * Upload pre-rendered pages to KV using the Cloudflare REST API.\n * Writes in the same KVCacheEntry format that KVCacheHandler reads\n * at runtime, so ISR serves these entries without any code changes.\n */\nasync function uploadToKV(\n entries: Map<string, PrerenderResult>,\n namespaceId: string,\n accountId: string,\n apiToken: string,\n defaultRevalidateSeconds: number,\n): Promise<void> {\n const now = Date.now();\n\n // Build the bulk write payload\n const pairs: Array<{\n key: string;\n value: string;\n expiration_ttl?: number;\n }> = [];\n\n for (const [routePath, result] of entries) {\n // Determine revalidation window — use the page's revalidate header\n // if present, otherwise fall back to the default\n const revalidateHeader = result.headers[\"x-vinext-revalidate\"];\n const revalidateSeconds =\n revalidateHeader && !isNaN(Number(revalidateHeader))\n ? Number(revalidateHeader)\n : defaultRevalidateSeconds;\n\n const revalidateAt = revalidateSeconds > 0 ? now + revalidateSeconds * 1000 : null;\n\n // KV TTL: 10x the revalidation period, clamped to [60s, 30d]\n // (matches the logic in KVCacheHandler.set)\n const kvTtl =\n revalidateSeconds > 0\n ? Math.max(Math.min(revalidateSeconds * 10, 30 * 24 * 3600), 60)\n : 24 * 3600; // 24h fallback if no revalidation\n\n const entry = {\n value: {\n kind: \"APP_PAGE\" as const,\n html: result.html,\n headers: result.headers,\n status: result.status,\n },\n tags: [] as string[],\n lastModified: now,\n revalidateAt,\n };\n\n pairs.push({\n key: `cache:${routePath}`,\n value: JSON.stringify(entry),\n expiration_ttl: kvTtl,\n });\n }\n\n // Upload in batches (KV bulk API accepts up to 10,000 per request)\n const BATCH_SIZE = 10_000;\n for (let i = 0; i < pairs.length; i += BATCH_SIZE) {\n const batch = pairs.slice(i, i + BATCH_SIZE);\n const response = await fetch(\n `https://api.cloudflare.com/client/v4/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/bulk`,\n {\n method: \"PUT\",\n headers: {\n Authorization: `Bearer ${apiToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(batch),\n },\n );\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `KV bulk upload failed (batch ${Math.floor(i / BATCH_SIZE) + 1}): ${response.status} — ${text}`,\n );\n }\n }\n}\n\n// ─── Main Entry ──────────────────────────────────────────────────────────────\n\n/** Default revalidation TTL for pre-rendered pages (1 hour). */\nconst DEFAULT_REVALIDATE_SECONDS = 3600;\n\n/**\n * Run the TPR pipeline: query traffic, select routes, pre-render, upload.\n *\n * Designed to be called between the build step and wrangler deploy in\n * the `vinext deploy` pipeline. Gracefully skips (never errors) when\n * the prerequisites aren't met.\n */\nexport async function runTPR(options: TPROptions): Promise<TPRResult> {\n const startTime = Date.now();\n const { root, coverage, limit, window: windowHours } = options;\n\n const skip = (reason: string): TPRResult => ({\n totalPaths: 0,\n prerenderedCount: 0,\n coverageAchieved: 0,\n durationMs: Date.now() - startTime,\n skipped: reason,\n });\n\n // ── 1. Check for API token ────────────────────────────────────\n const apiToken = process.env.CLOUDFLARE_API_TOKEN;\n if (!apiToken) {\n return skip(\"no CLOUDFLARE_API_TOKEN set\");\n }\n\n // ── 2. Parse wrangler config ──────────────────────────────────\n const wranglerConfig = parseWranglerConfig(root);\n if (!wranglerConfig) {\n return skip(\"could not parse wrangler config\");\n }\n\n // ── 3. Check for custom domain ────────────────────────────────\n if (!wranglerConfig.customDomain) {\n return skip(\"no custom domain — zone analytics unavailable\");\n }\n\n // ── 4. Check for KV namespace ─────────────────────────────────\n if (!wranglerConfig.kvNamespaceId) {\n return skip(\"no VINEXT_CACHE KV namespace configured\");\n }\n\n // ── 5. Resolve account ID ─────────────────────────────────────\n const accountId = wranglerConfig.accountId ?? (await resolveAccountId(apiToken));\n if (!accountId) {\n return skip(\"could not resolve Cloudflare account ID\");\n }\n\n // ── 6. Resolve zone ID ────────────────────────────────────────\n console.log(` TPR: Analyzing traffic for ${wranglerConfig.customDomain} (last ${windowHours}h)`);\n\n const zoneId = await resolveZoneId(wranglerConfig.customDomain, apiToken);\n if (!zoneId) {\n return skip(`could not resolve zone for ${wranglerConfig.customDomain}`);\n }\n\n // ── 7. Query traffic data ─────────────────────────────────────\n let traffic: TrafficEntry[];\n try {\n traffic = await queryTraffic(zoneId, apiToken, windowHours);\n } catch (err) {\n return skip(`analytics query failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n if (traffic.length === 0) {\n return skip(\"no traffic data available (first deploy?)\");\n }\n\n // ── 8. Select routes by coverage ──────────────────────────────\n const selection = selectRoutes(traffic, coverage, limit);\n\n console.log(\n ` TPR: ${traffic.length.toLocaleString()} unique paths — ` +\n `${selection.routes.length} pages cover ${Math.round(selection.coveragePercent)}% of traffic`,\n );\n\n if (selection.routes.length === 0) {\n return {\n totalPaths: traffic.length,\n prerenderedCount: 0,\n coverageAchieved: 0,\n durationMs: Date.now() - startTime,\n skipped: \"no pre-renderable routes after filtering\",\n };\n }\n\n // ── 9. Pre-render selected routes ─────────────────────────────\n console.log(` TPR: Pre-rendering ${selection.routes.length} pages...`);\n\n const routePaths = selection.routes.map((r) => r.path);\n let rendered: Map<string, PrerenderResult>;\n try {\n rendered = await prerenderRoutes(routePaths, root, wranglerConfig.customDomain);\n } catch (err) {\n return skip(`pre-rendering failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n if (rendered.size === 0) {\n return {\n totalPaths: traffic.length,\n prerenderedCount: 0,\n coverageAchieved: selection.coveragePercent,\n durationMs: Date.now() - startTime,\n skipped: \"all pages failed to pre-render (request-dependent?)\",\n };\n }\n\n // ── 10. Upload to KV ──────────────────────────────────────────\n try {\n await uploadToKV(\n rendered,\n wranglerConfig.kvNamespaceId,\n accountId,\n apiToken,\n DEFAULT_REVALIDATE_SECONDS,\n );\n } catch (err) {\n return skip(`KV upload failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n const durationMs = Date.now() - startTime;\n console.log(\n ` TPR: Pre-rendered ${rendered.size} pages in ${(durationMs / 1000).toFixed(1)}s → KV cache`,\n );\n\n return {\n totalPaths: traffic.length,\n prerenderedCount: rendered.size,\n coverageAchieved: selection.coveragePercent,\n durationMs,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tpr.js","names":[],"sources":["../../src/cloudflare/tpr.ts"],"sourcesContent":["/**\n * TPR: Traffic-aware Pre-Rendering\n *\n * Uses Cloudflare zone analytics to determine which pages actually get\n * traffic, and pre-renders only those during deploy. The pre-rendered\n * HTML is uploaded to KV in the same format ISR uses at runtime — no\n * runtime changes needed.\n *\n * Flow:\n * 1. Parse wrangler config to find custom domain and KV namespace\n * 2. Resolve the Cloudflare zone for the custom domain\n * 3. Query zone analytics (GraphQL) for top pages by request count\n * 4. Walk ranked list until coverage threshold is met\n * 5. Start the built production server locally\n * 6. Fetch each hot route to produce HTML\n * 7. Upload pre-rendered HTML to KV (same KVCacheEntry format ISR reads)\n *\n * TPR is an experimental feature enabled via --experimental-tpr. It\n * gracefully skips when no custom domain, no API token, no traffic data,\n * or no KV namespace is configured.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { spawn, type ChildProcess } from \"node:child_process\";\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport interface TPROptions {\n /** Project root directory. */\n root: string;\n /** Traffic coverage percentage (0–100). Default: 90. */\n coverage: number;\n /** Hard cap on number of pages to pre-render. Default: 1000. */\n limit: number;\n /** Analytics lookback window in hours. Default: 24. */\n window: number;\n}\n\nexport interface TPRResult {\n /** Total unique page paths found in analytics. */\n totalPaths: number;\n /** Number of pages successfully pre-rendered and uploaded. */\n prerenderedCount: number;\n /** Actual traffic coverage achieved (percentage). */\n coverageAchieved: number;\n /** Wall-clock duration of the TPR step in milliseconds. */\n durationMs: number;\n /** If TPR was skipped, the reason. */\n skipped?: string;\n}\n\ninterface TrafficEntry {\n path: string;\n requests: number;\n}\n\ninterface SelectedRoutes {\n routes: TrafficEntry[];\n totalRequests: number;\n coveredRequests: number;\n coveragePercent: number;\n}\n\ninterface PrerenderResult {\n html: string;\n status: number;\n headers: Record<string, string>;\n}\n\ninterface WranglerConfig {\n accountId?: string;\n kvNamespaceId?: string;\n customDomain?: string;\n}\n\n// ─── Wrangler Config Parsing ─────────────────────────────────────────────────\n\n/**\n * Parse wrangler config (JSONC or TOML) to extract the fields TPR needs:\n * account_id, VINEXT_CACHE KV namespace ID, and custom domain.\n */\nexport function parseWranglerConfig(root: string): WranglerConfig | null {\n // Try JSONC / JSON first\n for (const filename of [\"wrangler.jsonc\", \"wrangler.json\"]) {\n const filepath = path.join(root, filename);\n if (fs.existsSync(filepath)) {\n const content = fs.readFileSync(filepath, \"utf-8\");\n try {\n const json = JSON.parse(stripJsonComments(content));\n return extractFromJSON(json);\n } catch {\n continue;\n }\n }\n }\n\n // Try TOML\n const tomlPath = path.join(root, \"wrangler.toml\");\n if (fs.existsSync(tomlPath)) {\n const content = fs.readFileSync(tomlPath, \"utf-8\");\n return extractFromTOML(content);\n }\n\n return null;\n}\n\n/**\n * Strip single-line (//) and multi-line comments from JSONC while\n * preserving strings that contain slashes.\n */\nfunction stripJsonComments(str: string): string {\n let result = \"\";\n let inString = false;\n let inSingleLine = false;\n let inMultiLine = false;\n let escapeNext = false;\n\n for (let i = 0; i < str.length; i++) {\n const ch = str[i];\n const next = str[i + 1];\n\n if (escapeNext) {\n if (!inSingleLine && !inMultiLine) result += ch;\n escapeNext = false;\n continue;\n }\n\n if (ch === \"\\\\\" && inString) {\n result += ch;\n escapeNext = true;\n continue;\n }\n\n if (inSingleLine) {\n if (ch === \"\\n\") {\n inSingleLine = false;\n result += ch;\n }\n continue;\n }\n\n if (inMultiLine) {\n if (ch === \"*\" && next === \"/\") {\n inMultiLine = false;\n i++;\n }\n continue;\n }\n\n if (ch === '\"' && !inString) {\n inString = true;\n result += ch;\n continue;\n }\n\n if (ch === '\"' && inString) {\n inString = false;\n result += ch;\n continue;\n }\n\n if (!inString && ch === \"/\" && next === \"/\") {\n inSingleLine = true;\n i++;\n continue;\n }\n\n if (!inString && ch === \"/\" && next === \"*\") {\n inMultiLine = true;\n i++;\n continue;\n }\n\n result += ch;\n }\n\n return result;\n}\n\nfunction extractFromJSON(config: Record<string, unknown>): WranglerConfig {\n const result: WranglerConfig = {};\n\n // account_id\n if (typeof config.account_id === \"string\") {\n result.accountId = config.account_id;\n }\n\n // KV namespace ID for VINEXT_CACHE\n if (Array.isArray(config.kv_namespaces)) {\n const vinextKV = config.kv_namespaces.find(\n (ns: Record<string, unknown>) =>\n ns && typeof ns === \"object\" && ns.binding === \"VINEXT_CACHE\",\n );\n if (vinextKV && typeof vinextKV.id === \"string\" && vinextKV.id !== \"<your-kv-namespace-id>\") {\n result.kvNamespaceId = vinextKV.id;\n }\n }\n\n // Custom domain — check routes[] and custom_domains[]\n const domain = extractDomainFromRoutes(config.routes) ?? extractDomainFromCustomDomains(config);\n if (domain) result.customDomain = domain;\n\n return result;\n}\n\nfunction extractDomainFromRoutes(routes: unknown): string | null {\n if (!Array.isArray(routes)) return null;\n\n for (const route of routes) {\n if (typeof route === \"string\") {\n const domain = cleanDomain(route);\n if (domain && !domain.includes(\"workers.dev\")) return domain;\n } else if (route && typeof route === \"object\") {\n const r = route as Record<string, unknown>;\n const pattern =\n typeof r.zone_name === \"string\"\n ? r.zone_name\n : typeof r.pattern === \"string\"\n ? r.pattern\n : null;\n if (pattern) {\n const domain = cleanDomain(pattern);\n if (domain && !domain.includes(\"workers.dev\")) return domain;\n }\n }\n }\n return null;\n}\n\nfunction extractDomainFromCustomDomains(config: Record<string, unknown>): string | null {\n // Workers Custom Domains: \"custom_domains\": [\"example.com\"]\n if (Array.isArray(config.custom_domains)) {\n for (const d of config.custom_domains) {\n if (typeof d === \"string\" && !d.includes(\"workers.dev\")) {\n return cleanDomain(d);\n }\n }\n }\n return null;\n}\n\n/** Strip protocol and trailing wildcards from a route pattern to get a bare domain. */\nfunction cleanDomain(raw: string): string | null {\n const cleaned = raw\n .replace(/^https?:\\/\\//, \"\")\n .replace(/\\/\\*$/, \"\")\n .replace(/\\/+$/, \"\")\n .split(\"/\")[0]; // Take only the host part\n return cleaned || null;\n}\n\n/**\n * Simple extraction of specific fields from wrangler.toml content.\n * Not a full TOML parser — just enough for the fields we need.\n */\nfunction extractFromTOML(content: string): WranglerConfig {\n const result: WranglerConfig = {};\n\n // account_id = \"...\"\n const accountMatch = content.match(/^account_id\\s*=\\s*\"([^\"]+)\"/m);\n if (accountMatch) result.accountId = accountMatch[1];\n\n // KV namespace with binding = \"VINEXT_CACHE\"\n // Look for [[kv_namespaces]] blocks\n const kvBlocks = content.split(/\\[\\[kv_namespaces\\]\\]/);\n for (let i = 1; i < kvBlocks.length; i++) {\n const block = kvBlocks[i].split(/\\[\\[/)[0]; // Take until next section\n const bindingMatch = block.match(/binding\\s*=\\s*\"([^\"]+)\"/);\n const idMatch = block.match(/\\bid\\s*=\\s*\"([^\"]+)\"/);\n if (\n bindingMatch?.[1] === \"VINEXT_CACHE\" &&\n idMatch?.[1] &&\n idMatch[1] !== \"<your-kv-namespace-id>\"\n ) {\n result.kvNamespaceId = idMatch[1];\n }\n }\n\n // routes — both string and table forms\n // route = \"example.com/*\"\n const routeMatch = content.match(/^route\\s*=\\s*\"([^\"]+)\"/m);\n if (routeMatch) {\n const domain = cleanDomain(routeMatch[1]);\n if (domain && !domain.includes(\"workers.dev\")) {\n result.customDomain = domain;\n }\n }\n\n // [[routes]] blocks\n if (!result.customDomain) {\n const routeBlocks = content.split(/\\[\\[routes\\]\\]/);\n for (let i = 1; i < routeBlocks.length; i++) {\n const block = routeBlocks[i].split(/\\[\\[/)[0];\n const patternMatch = block.match(/pattern\\s*=\\s*\"([^\"]+)\"/);\n if (patternMatch) {\n const domain = cleanDomain(patternMatch[1]);\n if (domain && !domain.includes(\"workers.dev\")) {\n result.customDomain = domain;\n break;\n }\n }\n }\n }\n\n return result;\n}\n\n// ─── Cloudflare API ──────────────────────────────────────────────────────────\n\n/**\n * Generate zone lookup candidates from shortest (2-part) to longest.\n * Tries the most common case first (e.g., \"example.com\") and progressively\n * adds labels for multi-part TLDs (e.g., \"co.uk\" → \"example.co.uk\").\n *\n * \"shop.example.com\" → [\"example.com\", \"shop.example.com\"]\n * \"shop.example.co.uk\" → [\"co.uk\", \"example.co.uk\", \"shop.example.co.uk\"]\n * \"example.com\" → [\"example.com\"]\n */\nexport function domainCandidates(domain: string): string[] {\n const parts = domain.split(\".\");\n const candidates: string[] = [];\n for (let i = parts.length - 2; i >= 0; i--) {\n candidates.push(parts.slice(i).join(\".\"));\n }\n return candidates;\n}\n\n/** Resolve zone ID from a domain name via the Cloudflare API. */\nasync function resolveZoneId(domain: string, apiToken: string): Promise<string | null> {\n // Try progressively longer domain candidates until one matches a zone.\n // This handles all public suffixes without a hardcoded TLD list —\n // for simple TLDs (.com, .io) the 2-part candidate hits on the first try;\n // for multi-part TLDs (.co.uk, .com.au) it takes one extra call.\n for (const candidate of domainCandidates(domain)) {\n const response = await fetch(\n `https://api.cloudflare.com/client/v4/zones?name=${encodeURIComponent(candidate)}`,\n {\n headers: {\n Authorization: `Bearer ${apiToken}`,\n \"Content-Type\": \"application/json\",\n },\n },\n );\n\n if (!response.ok) continue;\n\n const data = (await response.json()) as {\n success: boolean;\n result?: Array<{ id: string }>;\n };\n if (data.success && data.result?.length) {\n return data.result[0].id;\n }\n }\n\n return null;\n}\n\n/** Resolve the account ID associated with the API token. */\nasync function resolveAccountId(apiToken: string): Promise<string | null> {\n const response = await fetch(\"https://api.cloudflare.com/client/v4/accounts?per_page=1\", {\n headers: {\n Authorization: `Bearer ${apiToken}`,\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (!response.ok) return null;\n\n const data = (await response.json()) as {\n success: boolean;\n result?: Array<{ id: string }>;\n };\n if (!data.success || !data.result?.length) return null;\n\n return data.result[0].id;\n}\n\n// ─── Traffic Querying ────────────────────────────────────────────────────────\n\n/**\n * Query Cloudflare zone analytics for top page paths by request count\n * over the given time window.\n */\nasync function queryTraffic(\n zoneTag: string,\n apiToken: string,\n windowHours: number,\n): Promise<TrafficEntry[]> {\n const now = new Date();\n const start = new Date(now.getTime() - windowHours * 60 * 60 * 1000);\n\n const query = `{\n viewer {\n zones(filter: { zoneTag: \"${zoneTag}\" }) {\n httpRequestsAdaptiveGroups(\n limit: 10000\n orderBy: [sum_requests_DESC]\n filter: {\n datetime_geq: \"${start.toISOString()}\"\n datetime_lt: \"${now.toISOString()}\"\n requestSource: \"eyeball\"\n }\n ) {\n sum { requests }\n dimensions { clientRequestPath }\n }\n }\n }\n }`;\n\n const response = await fetch(\"https://api.cloudflare.com/client/v4/graphql\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ query }),\n });\n\n if (!response.ok) {\n throw new Error(`Zone analytics query failed: ${response.status} ${response.statusText}`);\n }\n\n const data = (await response.json()) as {\n errors?: Array<{ message: string }>;\n data?: {\n viewer?: {\n zones?: Array<{\n httpRequestsAdaptiveGroups?: Array<{\n sum: { requests: number };\n dimensions: { clientRequestPath: string };\n }>;\n }>;\n };\n };\n };\n\n if (data.errors?.length) {\n throw new Error(`Zone analytics error: ${data.errors[0].message}`);\n }\n\n const groups = data.data?.viewer?.zones?.[0]?.httpRequestsAdaptiveGroups;\n if (!groups || groups.length === 0) return [];\n\n return filterTrafficPaths(\n groups.map((g) => ({\n path: g.dimensions.clientRequestPath,\n requests: g.sum.requests,\n })),\n );\n}\n\n/** Filter out non-page requests (static assets, API routes, internal routes). */\nfunction filterTrafficPaths(entries: TrafficEntry[]): TrafficEntry[] {\n return entries.filter((e) => {\n if (!e.path.startsWith(\"/\")) return false;\n // Static assets\n if (/\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff2?|ttf|eot|map|webp|avif)$/i.test(e.path))\n return false;\n // API routes\n if (e.path.startsWith(\"/api/\")) return false;\n // Internal routes\n if (e.path.startsWith(\"/_vinext/\") || e.path.startsWith(\"/_next/\")) return false;\n // RSC requests\n if (e.path.endsWith(\".rsc\")) return false;\n return true;\n });\n}\n\n// ─── Route Selection ─────────────────────────────────────────────────────────\n\n/**\n * Walk the ranked traffic list, accumulating request counts until the\n * coverage target is met or the hard cap is reached.\n */\nexport function selectRoutes(\n traffic: TrafficEntry[],\n coverageTarget: number,\n limit: number,\n): SelectedRoutes {\n const totalRequests = traffic.reduce((sum, e) => sum + e.requests, 0);\n if (totalRequests === 0) {\n return { routes: [], totalRequests: 0, coveredRequests: 0, coveragePercent: 0 };\n }\n\n const target = totalRequests * (coverageTarget / 100);\n const selected: TrafficEntry[] = [];\n let accumulated = 0;\n\n // Traffic is already sorted DESC by requests from the GraphQL query\n for (const entry of traffic) {\n if (accumulated >= target || selected.length >= limit) break;\n selected.push(entry);\n accumulated += entry.requests;\n }\n\n return {\n routes: selected,\n totalRequests,\n coveredRequests: accumulated,\n coveragePercent: (accumulated / totalRequests) * 100,\n };\n}\n\n// ─── Pre-rendering ───────────────────────────────────────────────────────────\n\n/** Pre-render port — high number to avoid collisions with dev servers. */\nconst PRERENDER_PORT = 19384;\n\n/** Max time to wait for the local server to start (ms). */\nconst SERVER_STARTUP_TIMEOUT = 30_000;\n\n/** Max concurrent fetch requests during pre-rendering. */\nconst FETCH_CONCURRENCY = 10;\n\n/**\n * Start a local production server, fetch each route to produce HTML,\n * and return the results. Pages that fail to render are skipped.\n */\nasync function prerenderRoutes(\n routes: string[],\n root: string,\n hostDomain?: string,\n): Promise<Map<string, PrerenderResult>> {\n const results = new Map<string, PrerenderResult>();\n let failedCount = 0;\n const port = PRERENDER_PORT;\n\n // Verify dist/ exists\n const distDir = path.join(root, \"dist\");\n if (!fs.existsSync(distDir)) {\n console.log(\" TPR: Skipping pre-render — dist/ directory not found\");\n return results;\n }\n\n // Start the local production server as a subprocess\n const serverProcess = startLocalServer(root, port);\n\n try {\n await waitForServer(port, SERVER_STARTUP_TIMEOUT);\n\n // Fetch routes in batches to limit concurrency\n for (let i = 0; i < routes.length; i += FETCH_CONCURRENCY) {\n const batch = routes.slice(i, i + FETCH_CONCURRENCY);\n const promises = batch.map(async (routePath) => {\n try {\n const response = await fetch(`http://127.0.0.1:${port}${routePath}`, {\n headers: {\n \"User-Agent\": \"vinext-tpr/1.0\",\n ...(hostDomain ? { Host: hostDomain } : {}),\n },\n redirect: \"manual\", // Don't follow redirects — cache the redirect itself\n });\n\n // Only cache successful responses (2xx and 3xx)\n if (response.status < 400) {\n const html = await response.text();\n const headers: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n // Only keep relevant headers\n if (\n key === \"content-type\" ||\n key === \"cache-control\" ||\n key === \"x-vinext-revalidate\" ||\n key === \"location\"\n ) {\n headers[key] = value;\n }\n });\n results.set(routePath, {\n html,\n status: response.status,\n headers,\n });\n }\n } catch {\n // Skip pages that fail to render — they may depend on\n // request-specific data (cookies, headers, auth) that\n // isn't available during pre-rendering.\n failedCount++;\n }\n });\n\n await Promise.all(promises);\n }\n\n if (failedCount > 0) {\n console.log(` TPR: ${failedCount} page(s) failed to pre-render (skipped)`);\n }\n } finally {\n serverProcess.kill(\"SIGTERM\");\n // Give it a moment to clean up\n await new Promise<void>((resolve) => {\n serverProcess.on(\"exit\", resolve);\n setTimeout(resolve, 2000);\n });\n }\n\n return results;\n}\n\n/**\n * Spawn a subprocess running the vinext production server.\n * Uses the same Node.js binary and resolves prod-server.js relative\n * to the current module (works whether vinext is installed or linked).\n */\nfunction startLocalServer(root: string, port: number): ChildProcess {\n const thisDir = fileURLToPath(new URL(\".\", import.meta.url));\n const prodServerPath = path.resolve(thisDir, \"..\", \"server\", \"prod-server.js\");\n const outDir = path.join(root, \"dist\");\n\n // Escape backslashes for Windows paths inside the JS string\n const escapedProdServer = prodServerPath.replace(/\\\\/g, \"\\\\\\\\\");\n const escapedOutDir = outDir.replace(/\\\\/g, \"\\\\\\\\\");\n\n const script = [\n `import(\"file://${escapedProdServer}\")`,\n `.then(m => m.startProdServer({ port: ${port}, host: \"127.0.0.1\", outDir: \"${escapedOutDir}\" }))`,\n `.catch(e => { console.error(\"[vinext-tpr] Server failed to start:\", e); process.exit(1); });`,\n ].join(\"\");\n\n const proc = spawn(process.execPath, [\"--input-type=module\", \"-e\", script], {\n cwd: root,\n stdio: \"pipe\",\n env: { ...process.env, NODE_ENV: \"production\" },\n });\n\n // Forward server errors to the parent's stderr for debugging\n proc.stderr?.on(\"data\", (chunk: Buffer) => {\n const msg = chunk.toString().trim();\n if (msg) console.error(` [tpr-server] ${msg}`);\n });\n\n return proc;\n}\n\n/** Poll the local server until it responds or the timeout is reached. */\nasync function waitForServer(port: number, timeoutMs: number): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 2000);\n const response = await fetch(`http://127.0.0.1:${port}/`, {\n redirect: \"manual\",\n signal: controller.signal,\n });\n clearTimeout(timer);\n // Any response means the server is up\n await response.text(); // consume body\n return;\n } catch {\n await new Promise<void>((r) => setTimeout(r, 300));\n }\n }\n throw new Error(`Local production server failed to start within ${timeoutMs / 1000}s`);\n}\n\n// ─── KV Upload ───────────────────────────────────────────────────────────────\n\n/**\n * Upload pre-rendered pages to KV using the Cloudflare REST API.\n * Writes in the same KVCacheEntry format that KVCacheHandler reads\n * at runtime, so ISR serves these entries without any code changes.\n */\nasync function uploadToKV(\n entries: Map<string, PrerenderResult>,\n namespaceId: string,\n accountId: string,\n apiToken: string,\n defaultRevalidateSeconds: number,\n): Promise<void> {\n const now = Date.now();\n\n // Build the bulk write payload\n const pairs: Array<{\n key: string;\n value: string;\n expiration_ttl?: number;\n }> = [];\n\n for (const [routePath, result] of entries) {\n // Determine revalidation window — use the page's revalidate header\n // if present, otherwise fall back to the default\n const revalidateHeader = result.headers[\"x-vinext-revalidate\"];\n const revalidateSeconds =\n revalidateHeader && !isNaN(Number(revalidateHeader))\n ? Number(revalidateHeader)\n : defaultRevalidateSeconds;\n\n const revalidateAt = revalidateSeconds > 0 ? now + revalidateSeconds * 1000 : null;\n\n // KV TTL: 10x the revalidation period, clamped to [60s, 30d]\n // (matches the logic in KVCacheHandler.set)\n const kvTtl =\n revalidateSeconds > 0\n ? Math.max(Math.min(revalidateSeconds * 10, 30 * 24 * 3600), 60)\n : 24 * 3600; // 24h fallback if no revalidation\n\n const entry = {\n value: {\n kind: \"APP_PAGE\" as const,\n html: result.html,\n headers: result.headers,\n status: result.status,\n },\n tags: [] as string[],\n lastModified: now,\n revalidateAt,\n };\n\n pairs.push({\n key: `cache:${routePath}`,\n value: JSON.stringify(entry),\n expiration_ttl: kvTtl,\n });\n }\n\n // Upload in batches (KV bulk API accepts up to 10,000 per request)\n const BATCH_SIZE = 10_000;\n for (let i = 0; i < pairs.length; i += BATCH_SIZE) {\n const batch = pairs.slice(i, i + BATCH_SIZE);\n const response = await fetch(\n `https://api.cloudflare.com/client/v4/accounts/${accountId}/storage/kv/namespaces/${namespaceId}/bulk`,\n {\n method: \"PUT\",\n headers: {\n Authorization: `Bearer ${apiToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(batch),\n },\n );\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `KV bulk upload failed (batch ${Math.floor(i / BATCH_SIZE) + 1}): ${response.status} — ${text}`,\n );\n }\n }\n}\n\n// ─── Main Entry ──────────────────────────────────────────────────────────────\n\n/** Default revalidation TTL for pre-rendered pages (1 hour). */\nconst DEFAULT_REVALIDATE_SECONDS = 3600;\n\n/**\n * Run the TPR pipeline: query traffic, select routes, pre-render, upload.\n *\n * Designed to be called between the build step and wrangler deploy in\n * the `vinext deploy` pipeline. Gracefully skips (never errors) when\n * the prerequisites aren't met.\n */\nexport async function runTPR(options: TPROptions): Promise<TPRResult> {\n const startTime = Date.now();\n const { root, coverage, limit, window: windowHours } = options;\n\n const skip = (reason: string): TPRResult => ({\n totalPaths: 0,\n prerenderedCount: 0,\n coverageAchieved: 0,\n durationMs: Date.now() - startTime,\n skipped: reason,\n });\n\n // ── 1. Check for API token ────────────────────────────────────\n const apiToken = process.env.CLOUDFLARE_API_TOKEN;\n if (!apiToken) {\n return skip(\"no CLOUDFLARE_API_TOKEN set\");\n }\n\n // ── 2. Parse wrangler config ──────────────────────────────────\n const wranglerConfig = parseWranglerConfig(root);\n if (!wranglerConfig) {\n return skip(\"could not parse wrangler config\");\n }\n\n // ── 3. Check for custom domain ────────────────────────────────\n if (!wranglerConfig.customDomain) {\n return skip(\"no custom domain — zone analytics unavailable\");\n }\n\n // ── 4. Check for KV namespace ─────────────────────────────────\n if (!wranglerConfig.kvNamespaceId) {\n return skip(\"no VINEXT_CACHE KV namespace configured\");\n }\n\n // ── 5. Resolve account ID ─────────────────────────────────────\n const accountId = wranglerConfig.accountId ?? (await resolveAccountId(apiToken));\n if (!accountId) {\n return skip(\"could not resolve Cloudflare account ID\");\n }\n\n // ── 6. Resolve zone ID ────────────────────────────────────────\n console.log(` TPR: Analyzing traffic for ${wranglerConfig.customDomain} (last ${windowHours}h)`);\n\n const zoneId = await resolveZoneId(wranglerConfig.customDomain, apiToken);\n if (!zoneId) {\n return skip(`could not resolve zone for ${wranglerConfig.customDomain}`);\n }\n\n // ── 7. Query traffic data ─────────────────────────────────────\n let traffic: TrafficEntry[];\n try {\n traffic = await queryTraffic(zoneId, apiToken, windowHours);\n } catch (err) {\n return skip(`analytics query failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n if (traffic.length === 0) {\n return skip(\"no traffic data available (first deploy?)\");\n }\n\n // ── 8. Select routes by coverage ──────────────────────────────\n const selection = selectRoutes(traffic, coverage, limit);\n\n console.log(\n ` TPR: ${traffic.length.toLocaleString()} unique paths — ` +\n `${selection.routes.length} pages cover ${Math.round(selection.coveragePercent)}% of traffic`,\n );\n\n if (selection.routes.length === 0) {\n return {\n totalPaths: traffic.length,\n prerenderedCount: 0,\n coverageAchieved: 0,\n durationMs: Date.now() - startTime,\n skipped: \"no pre-renderable routes after filtering\",\n };\n }\n\n // ── 9. Pre-render selected routes ─────────────────────────────\n console.log(` TPR: Pre-rendering ${selection.routes.length} pages...`);\n\n const routePaths = selection.routes.map((r) => r.path);\n let rendered: Map<string, PrerenderResult>;\n try {\n rendered = await prerenderRoutes(routePaths, root, wranglerConfig.customDomain);\n } catch (err) {\n return skip(`pre-rendering failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n if (rendered.size === 0) {\n return {\n totalPaths: traffic.length,\n prerenderedCount: 0,\n coverageAchieved: selection.coveragePercent,\n durationMs: Date.now() - startTime,\n skipped: \"all pages failed to pre-render (request-dependent?)\",\n };\n }\n\n // ── 10. Upload to KV ──────────────────────────────────────────\n try {\n await uploadToKV(\n rendered,\n wranglerConfig.kvNamespaceId,\n accountId,\n apiToken,\n DEFAULT_REVALIDATE_SECONDS,\n );\n } catch (err) {\n return skip(`KV upload failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n const durationMs = Date.now() - startTime;\n console.log(\n ` TPR: Pre-rendered ${rendered.size} pages in ${(durationMs / 1000).toFixed(1)}s → KV cache`,\n );\n\n return {\n totalPaths: traffic.length,\n prerenderedCount: rendered.size,\n coverageAchieved: selection.coveragePercent,\n durationMs,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
-
import type { NextRedirect, NextRewrite, NextHeader, HasCondition } from "./next-config.js";
|
|
1
|
+
import { HasCondition, NextHeader, NextRedirect, NextRewrite } from "./next-config.js";
|
|
2
|
+
|
|
3
|
+
//#region src/config/config-matchers.d.ts
|
|
8
4
|
/**
|
|
9
5
|
* Detect regex patterns vulnerable to catastrophic backtracking (ReDoS).
|
|
10
6
|
*
|
|
@@ -15,14 +11,14 @@ import type { NextRedirect, NextRewrite, NextHeader, HasCondition } from "./next
|
|
|
15
11
|
*
|
|
16
12
|
* Returns true if the pattern appears safe, false if it's potentially dangerous.
|
|
17
13
|
*/
|
|
18
|
-
|
|
14
|
+
declare function isSafeRegex(pattern: string): boolean;
|
|
19
15
|
/**
|
|
20
16
|
* Compile a regex pattern safely. Returns the compiled RegExp or null if the
|
|
21
17
|
* pattern is invalid or vulnerable to ReDoS.
|
|
22
18
|
*
|
|
23
19
|
* Logs a warning when a pattern is rejected so developers can fix their config.
|
|
24
20
|
*/
|
|
25
|
-
|
|
21
|
+
declare function safeRegExp(pattern: string, flags?: string): RegExp | null;
|
|
26
22
|
/**
|
|
27
23
|
* Convert a Next.js header/rewrite/redirect source pattern into a regex string.
|
|
28
24
|
*
|
|
@@ -30,26 +26,26 @@ export declare function safeRegExp(pattern: string, flags?: string): RegExp | nu
|
|
|
30
26
|
* text is escaped/converted in a **single pass** (avoiding chained `.replace()`
|
|
31
27
|
* which CodeQL flags as incomplete sanitization), then groups are restored.
|
|
32
28
|
*/
|
|
33
|
-
|
|
29
|
+
declare function escapeHeaderSource(source: string): string;
|
|
34
30
|
/**
|
|
35
31
|
* Request context needed for evaluating has/missing conditions.
|
|
36
32
|
* Callers extract the relevant parts from the incoming Request.
|
|
37
33
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
interface RequestContext {
|
|
35
|
+
headers: Headers;
|
|
36
|
+
cookies: Record<string, string>;
|
|
37
|
+
query: URLSearchParams;
|
|
38
|
+
host: string;
|
|
43
39
|
}
|
|
44
40
|
/**
|
|
45
41
|
* Parse a Cookie header string into a key-value record.
|
|
46
42
|
*/
|
|
47
|
-
|
|
43
|
+
declare function parseCookies(cookieHeader: string | null): Record<string, string>;
|
|
48
44
|
/**
|
|
49
45
|
* Build a RequestContext from a Web Request object.
|
|
50
46
|
*/
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
declare function requestContextFromRequest(request: Request): RequestContext;
|
|
48
|
+
declare function normalizeHost(hostHeader: string | null, fallbackHostname: string): string;
|
|
53
49
|
/**
|
|
54
50
|
* Unpack `x-middleware-request-*` headers from the collected middleware
|
|
55
51
|
* response headers into the actual request, and strip all `x-middleware-*`
|
|
@@ -67,18 +63,11 @@ export declare function normalizeHost(hostHeader: string | null, fallbackHostnam
|
|
|
67
63
|
* individual header values), so the wider `string | string[]` type of
|
|
68
64
|
* `middlewareHeaders` is safe to cast here.
|
|
69
65
|
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
declare function applyMiddlewareRequestHeaders(middlewareHeaders: Record<string, string | string[]>, request: Request): {
|
|
67
|
+
request: Request;
|
|
68
|
+
postMwReqCtx: RequestContext;
|
|
73
69
|
};
|
|
74
|
-
|
|
75
|
-
* Check all has/missing conditions for a config rule.
|
|
76
|
-
* Returns true if the rule should be applied (all has conditions pass, all missing conditions pass).
|
|
77
|
-
*
|
|
78
|
-
* - has: every condition must match (the request must have it)
|
|
79
|
-
* - missing: every condition must NOT match (the request must not have it)
|
|
80
|
-
*/
|
|
81
|
-
export declare function checkHasConditions(has: HasCondition[] | undefined, missing: HasCondition[] | undefined, ctx: RequestContext): boolean;
|
|
70
|
+
declare function checkHasConditions(has: HasCondition[] | undefined, missing: HasCondition[] | undefined, ctx: RequestContext): boolean;
|
|
82
71
|
/**
|
|
83
72
|
* Match a Next.js config pattern (from redirects/rewrites sources) against a pathname.
|
|
84
73
|
* Returns matched params or null.
|
|
@@ -90,7 +79,7 @@ export declare function checkHasConditions(has: HasCondition[] | undefined, miss
|
|
|
90
79
|
* (regex) - inline regex patterns in the source
|
|
91
80
|
* :param(constraint) - named param with inline regex constraint
|
|
92
81
|
*/
|
|
93
|
-
|
|
82
|
+
declare function matchConfigPattern(pathname: string, pattern: string): Record<string, string> | null;
|
|
94
83
|
/**
|
|
95
84
|
* Apply redirect rules from next.config.js.
|
|
96
85
|
* Returns the redirect info if a redirect was matched, or null.
|
|
@@ -126,9 +115,9 @@ export declare function matchConfigPattern(pathname: string, pattern: string): R
|
|
|
126
115
|
* an original index < N are checked via matchConfigPattern first — they are
|
|
127
116
|
* few in practice (typically zero) so this is not a hot-path concern.
|
|
128
117
|
*/
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
declare function matchRedirect(pathname: string, redirects: NextRedirect[], ctx: RequestContext): {
|
|
119
|
+
destination: string;
|
|
120
|
+
permanent: boolean;
|
|
132
121
|
} | null;
|
|
133
122
|
/**
|
|
134
123
|
* Apply rewrite rules from next.config.js.
|
|
@@ -138,7 +127,7 @@ export declare function matchRedirect(pathname: string, redirects: NextRedirect[
|
|
|
138
127
|
* to evaluate has/missing conditions. Next.js always has request context
|
|
139
128
|
* when evaluating rewrites, so this parameter is required.
|
|
140
129
|
*/
|
|
141
|
-
|
|
130
|
+
declare function matchRewrite(pathname: string, rewrites: NextRewrite[], ctx: RequestContext): string | null;
|
|
142
131
|
/**
|
|
143
132
|
* Sanitize a redirect/rewrite destination to collapse protocol-relative URLs.
|
|
144
133
|
*
|
|
@@ -150,13 +139,13 @@ export declare function matchRewrite(pathname: string, rewrites: NextRewrite[],
|
|
|
150
139
|
* This function collapses any leading double (or more) slashes to a single
|
|
151
140
|
* slash for non-external (relative) destinations.
|
|
152
141
|
*/
|
|
153
|
-
|
|
142
|
+
declare function sanitizeDestination(dest: string): string;
|
|
154
143
|
/**
|
|
155
144
|
* Check if a URL is external (absolute URL or protocol-relative).
|
|
156
145
|
* Detects any URL scheme (http:, https:, data:, javascript:, blob:, etc.)
|
|
157
146
|
* per RFC 3986, plus protocol-relative URLs (//).
|
|
158
147
|
*/
|
|
159
|
-
|
|
148
|
+
declare function isExternalUrl(url: string): boolean;
|
|
160
149
|
/**
|
|
161
150
|
* Proxy an incoming request to an external URL and return the upstream response.
|
|
162
151
|
*
|
|
@@ -166,7 +155,7 @@ export declare function isExternalUrl(url: string): boolean;
|
|
|
166
155
|
*
|
|
167
156
|
* Works in all runtimes (Node.js, Cloudflare Workers) via the standard fetch() API.
|
|
168
157
|
*/
|
|
169
|
-
|
|
158
|
+
declare function proxyExternalRequest(request: Request, externalUrl: string): Promise<Response>;
|
|
170
159
|
/**
|
|
171
160
|
* Apply custom header rules from next.config.js.
|
|
172
161
|
* Returns an array of { key, value } pairs to set on the response.
|
|
@@ -175,8 +164,10 @@ export declare function proxyExternalRequest(request: Request, externalUrl: stri
|
|
|
175
164
|
* to evaluate has/missing conditions. Next.js always has request context
|
|
176
165
|
* when evaluating headers, so this parameter is required.
|
|
177
166
|
*/
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
167
|
+
declare function matchHeaders(pathname: string, headers: NextHeader[], ctx: RequestContext): Array<{
|
|
168
|
+
key: string;
|
|
169
|
+
value: string;
|
|
181
170
|
}>;
|
|
171
|
+
//#endregion
|
|
172
|
+
export { RequestContext, applyMiddlewareRequestHeaders, checkHasConditions, escapeHeaderSource, isExternalUrl, isSafeRegex, matchConfigPattern, matchHeaders, matchRedirect, matchRewrite, normalizeHost, parseCookies, proxyExternalRequest, requestContextFromRequest, safeRegExp, sanitizeDestination };
|
|
182
173
|
//# sourceMappingURL=config-matchers.d.ts.map
|