vinext 0.1.1 → 0.1.3
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 +2 -5
- package/dist/build/client-build-config.d.ts +7 -1
- package/dist/build/client-build-config.js +9 -1
- package/dist/build/prerender.d.ts +9 -1
- package/dist/build/prerender.js +41 -12
- package/dist/build/run-prerender.d.ts +10 -2
- package/dist/build/run-prerender.js +15 -1
- package/dist/check.js +4 -3
- package/dist/client/app-nav-failure-handler.d.ts +8 -0
- package/dist/client/app-nav-failure-handler.js +44 -0
- package/dist/client/navigation-runtime.d.ts +3 -2
- package/dist/client/vinext-next-data.d.ts +18 -1
- package/dist/client/window-next.d.ts +8 -5
- package/dist/client/window-next.js +12 -1
- package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
- package/dist/config/config-matchers.d.ts +11 -4
- package/dist/config/config-matchers.js +88 -16
- package/dist/config/next-config.d.ts +59 -4
- package/dist/config/next-config.js +149 -48
- package/dist/deploy.d.ts +30 -11
- package/dist/deploy.js +189 -101
- package/dist/entries/app-browser-entry.d.ts +9 -3
- package/dist/entries/app-browser-entry.js +21 -3
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +71 -6
- package/dist/entries/app-rsc-manifest.js +2 -0
- package/dist/entries/app-ssr-entry.js +1 -1
- package/dist/entries/pages-client-entry.js +54 -9
- package/dist/entries/pages-server-entry.js +48 -11
- package/dist/index.d.ts +0 -2
- package/dist/index.js +285 -139
- package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
- package/dist/plugins/dynamic-preload-metadata.js +415 -0
- package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
- package/dist/plugins/extensionless-dynamic-import.js +152 -0
- package/dist/plugins/og-assets.js +2 -2
- package/dist/plugins/optimize-imports.d.ts +10 -5
- package/dist/plugins/optimize-imports.js +27 -21
- package/dist/plugins/postcss.js +7 -7
- package/dist/plugins/sass.d.ts +53 -24
- package/dist/plugins/sass.js +249 -1
- package/dist/plugins/typeof-window.d.ts +14 -0
- package/dist/plugins/typeof-window.js +150 -0
- package/dist/plugins/wasm-module-import.d.ts +15 -0
- package/dist/plugins/wasm-module-import.js +50 -0
- package/dist/routing/app-route-graph.d.ts +25 -2
- package/dist/routing/app-route-graph.js +91 -22
- package/dist/routing/file-matcher.d.ts +10 -1
- package/dist/routing/file-matcher.js +23 -2
- package/dist/routing/pages-router.js +3 -3
- package/dist/routing/utils.d.ts +35 -6
- package/dist/routing/utils.js +59 -7
- package/dist/server/api-handler.d.ts +6 -1
- package/dist/server/api-handler.js +21 -15
- package/dist/server/app-browser-action-result.d.ts +19 -6
- package/dist/server/app-browser-action-result.js +19 -10
- package/dist/server/app-browser-entry.js +269 -297
- package/dist/server/app-browser-error.d.ts +10 -3
- package/dist/server/app-browser-error.js +47 -6
- package/dist/server/app-browser-history-controller.d.ts +104 -0
- package/dist/server/app-browser-history-controller.js +210 -0
- package/dist/server/app-browser-hydration.d.ts +2 -0
- package/dist/server/app-browser-hydration.js +1 -0
- package/dist/server/app-browser-navigation-controller.d.ts +7 -4
- package/dist/server/app-browser-navigation-controller.js +33 -9
- package/dist/server/app-browser-rsc-redirect.d.ts +11 -2
- package/dist/server/app-browser-rsc-redirect.js +30 -8
- package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
- package/dist/server/app-browser-server-action-navigation.js +9 -0
- package/dist/server/app-browser-state.js +4 -7
- package/dist/server/app-browser-stream.js +86 -43
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-elements-wire.d.ts +6 -1
- package/dist/server/app-elements-wire.js +14 -4
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-fallback-renderer.d.ts +3 -1
- package/dist/server/app-fallback-renderer.js +6 -2
- package/dist/server/app-middleware.js +1 -0
- package/dist/server/app-optimistic-routing.js +24 -3
- package/dist/server/app-page-boundary-render.d.ts +3 -1
- package/dist/server/app-page-boundary-render.js +31 -16
- package/dist/server/app-page-cache-render.d.ts +53 -0
- package/dist/server/app-page-cache-render.js +91 -0
- package/dist/server/app-page-cache.d.ts +16 -2
- package/dist/server/app-page-cache.js +71 -8
- package/dist/server/app-page-dispatch.d.ts +34 -0
- package/dist/server/app-page-dispatch.js +167 -97
- package/dist/server/app-page-element-builder.d.ts +23 -2
- package/dist/server/app-page-element-builder.js +42 -10
- package/dist/server/app-page-execution.d.ts +7 -2
- package/dist/server/app-page-execution.js +53 -18
- package/dist/server/app-page-probe.d.ts +1 -0
- package/dist/server/app-page-probe.js +4 -0
- package/dist/server/app-page-render-observation.d.ts +3 -1
- package/dist/server/app-page-render-observation.js +17 -1
- package/dist/server/app-page-render.d.ts +13 -2
- package/dist/server/app-page-render.js +48 -17
- package/dist/server/app-page-request.d.ts +3 -0
- package/dist/server/app-page-request.js +5 -3
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +5 -1
- package/dist/server/app-page-route-wiring.js +21 -11
- package/dist/server/app-page-stream.d.ts +16 -9
- package/dist/server/app-page-stream.js +12 -9
- package/dist/server/app-pages-bridge.d.ts +18 -0
- package/dist/server/app-pages-bridge.js +22 -5
- package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
- package/dist/server/app-ppr-fallback-shell-render.js +26 -0
- package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
- package/dist/server/app-ppr-fallback-shell.js +8 -1
- package/dist/server/app-route-handler-dispatch.js +9 -2
- package/dist/server/app-route-handler-policy.d.ts +1 -0
- package/dist/server/app-route-handler-response.js +11 -10
- package/dist/server/app-route-handler-runtime.js +12 -1
- package/dist/server/app-router-entry.js +5 -0
- package/dist/server/app-rsc-cache-busting.js +2 -0
- package/dist/server/app-rsc-handler.d.ts +25 -0
- package/dist/server/app-rsc-handler.js +153 -53
- package/dist/server/app-rsc-response-finalizer.js +1 -1
- package/dist/server/app-rsc-route-matching.d.ts +3 -0
- package/dist/server/app-rsc-route-matching.js +2 -0
- package/dist/server/app-segment-config.d.ts +9 -1
- package/dist/server/app-segment-config.js +12 -3
- package/dist/server/app-server-action-execution.d.ts +12 -0
- package/dist/server/app-server-action-execution.js +47 -15
- package/dist/server/app-ssr-entry.d.ts +2 -0
- package/dist/server/app-ssr-entry.js +81 -8
- package/dist/server/app-ssr-stream.js +9 -1
- package/dist/server/cache-control.js +4 -0
- package/dist/server/dev-lockfile.js +2 -1
- package/dist/server/dev-server.d.ts +2 -2
- package/dist/server/dev-server.js +287 -63
- package/dist/server/headers.d.ts +8 -1
- package/dist/server/headers.js +8 -1
- package/dist/server/hybrid-route-priority.d.ts +22 -0
- package/dist/server/hybrid-route-priority.js +33 -0
- package/dist/server/image-optimization.d.ts +18 -9
- package/dist/server/image-optimization.js +37 -23
- package/dist/server/implicit-tags.d.ts +2 -1
- package/dist/server/implicit-tags.js +4 -1
- package/dist/server/instrumentation-runtime.d.ts +6 -0
- package/dist/server/instrumentation-runtime.js +8 -0
- package/dist/server/isr-decision.d.ts +79 -0
- package/dist/server/isr-decision.js +70 -0
- package/dist/server/metadata-route-response.js +5 -3
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +11 -7
- package/dist/server/middleware.js +1 -0
- package/dist/server/navigation-planner.d.ts +186 -22
- package/dist/server/navigation-planner.js +302 -0
- package/dist/server/navigation-trace.d.ts +18 -1
- package/dist/server/navigation-trace.js +18 -1
- package/dist/server/normalize-path.d.ts +0 -8
- package/dist/server/normalize-path.js +3 -1
- package/dist/server/otel-tracer-extension.d.ts +45 -0
- package/dist/server/otel-tracer-extension.js +89 -0
- package/dist/server/pages-api-route.d.ts +20 -3
- package/dist/server/pages-api-route.js +19 -3
- package/dist/server/pages-asset-tags.d.ts +16 -4
- package/dist/server/pages-asset-tags.js +22 -12
- package/dist/server/pages-data-route.d.ts +8 -1
- package/dist/server/pages-data-route.js +16 -3
- package/dist/server/pages-get-initial-props.d.ts +54 -4
- package/dist/server/pages-get-initial-props.js +43 -1
- package/dist/server/pages-node-compat.d.ts +3 -11
- package/dist/server/pages-node-compat.js +175 -122
- package/dist/server/pages-page-data.d.ts +39 -2
- package/dist/server/pages-page-data.js +261 -46
- package/dist/server/pages-page-handler.d.ts +5 -2
- package/dist/server/pages-page-handler.js +78 -25
- package/dist/server/pages-page-response.d.ts +47 -2
- package/dist/server/pages-page-response.js +73 -9
- package/dist/server/pages-readiness.d.ts +1 -1
- package/dist/server/pages-request-pipeline.d.ts +16 -1
- package/dist/server/pages-request-pipeline.js +96 -38
- package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
- package/dist/server/pregenerated-concrete-paths.js +2 -19
- package/dist/server/prerender-manifest.d.ts +33 -0
- package/dist/server/prerender-manifest.js +54 -0
- package/dist/server/prerender-route-params.d.ts +1 -2
- package/dist/server/prod-server.d.ts +39 -1
- package/dist/server/prod-server.js +107 -37
- package/dist/server/request-pipeline.d.ts +3 -15
- package/dist/server/request-pipeline.js +58 -47
- package/dist/server/rsc-stream-hints.d.ts +5 -1
- package/dist/server/rsc-stream-hints.js +6 -1
- package/dist/server/seed-cache.js +10 -18
- package/dist/shims/app-router-scroll-state.d.ts +3 -1
- package/dist/shims/app-router-scroll-state.js +14 -2
- package/dist/shims/app-router-scroll.d.ts +3 -0
- package/dist/shims/app-router-scroll.js +28 -18
- package/dist/shims/cache-runtime.js +12 -4
- package/dist/shims/cache.d.ts +1 -0
- package/dist/shims/cache.js +1 -1
- package/dist/shims/cdn-cache.d.ts +5 -5
- package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
- package/dist/shims/dynamic-preload-chunks.js +79 -0
- package/dist/shims/dynamic.d.ts +4 -0
- package/dist/shims/dynamic.js +4 -2
- package/dist/shims/error-boundary.d.ts +6 -4
- package/dist/shims/error-boundary.js +7 -0
- package/dist/shims/error.js +38 -11
- package/dist/shims/error.react-server.d.ts +9 -0
- package/dist/shims/error.react-server.js +6 -0
- package/dist/shims/fetch-cache.d.ts +11 -1
- package/dist/shims/fetch-cache.js +55 -20
- package/dist/shims/hash-scroll.js +6 -1
- package/dist/shims/head.js +6 -1
- package/dist/shims/headers.d.ts +16 -2
- package/dist/shims/headers.js +66 -5
- package/dist/shims/image-config.js +7 -1
- package/dist/shims/internal/als-registry.js +28 -1
- package/dist/shims/internal/app-route-detection.d.ts +6 -3
- package/dist/shims/internal/app-route-detection.js +18 -23
- package/dist/shims/internal/app-router-context.d.ts +5 -0
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
- package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
- package/dist/shims/internal/navigation-untracked.d.ts +35 -0
- package/dist/shims/internal/navigation-untracked.js +55 -0
- package/dist/shims/internal/pages-data-target.d.ts +7 -2
- package/dist/shims/internal/pages-data-target.js +17 -8
- package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
- package/dist/shims/internal/pages-router-accessor.js +13 -0
- package/dist/shims/internal/router-context.d.ts +2 -1
- package/dist/shims/internal/router-context.js +3 -1
- package/dist/shims/link.js +12 -5
- package/dist/shims/metadata.d.ts +6 -2
- package/dist/shims/metadata.js +32 -14
- package/dist/shims/navigation.d.ts +14 -17
- package/dist/shims/navigation.js +93 -46
- package/dist/shims/ppr-fallback-shell.d.ts +5 -1
- package/dist/shims/ppr-fallback-shell.js +28 -7
- package/dist/shims/router.d.ts +13 -2
- package/dist/shims/router.js +434 -116
- package/dist/shims/script-nonce-context.d.ts +1 -1
- package/dist/shims/script-nonce-context.js +11 -3
- package/dist/shims/server.d.ts +33 -2
- package/dist/shims/server.js +75 -18
- package/dist/shims/slot.js +1 -1
- package/dist/shims/unified-request-context.js +2 -0
- package/dist/typegen.js +1 -0
- package/dist/utils/built-asset-url.d.ts +4 -0
- package/dist/utils/built-asset-url.js +11 -0
- package/dist/utils/client-build-manifest.js +15 -5
- package/dist/utils/client-runtime-metadata.d.ts +45 -0
- package/dist/utils/client-runtime-metadata.js +63 -0
- package/dist/utils/commonjs-loader.d.ts +16 -0
- package/dist/utils/commonjs-loader.js +100 -0
- package/dist/utils/deployment-id.d.ts +8 -0
- package/dist/utils/deployment-id.js +22 -0
- package/dist/utils/hash.d.ts +17 -1
- package/dist/utils/hash.js +36 -1
- package/dist/utils/html-limited-bots.d.ts +18 -1
- package/dist/utils/html-limited-bots.js +23 -1
- package/dist/utils/lazy-chunks.d.ts +27 -1
- package/dist/utils/lazy-chunks.js +65 -1
- package/dist/utils/manifest-paths.d.ts +20 -2
- package/dist/utils/manifest-paths.js +38 -3
- package/dist/utils/parse-cookie.d.ts +13 -0
- package/dist/utils/parse-cookie.js +52 -0
- package/dist/utils/path.d.ts +8 -1
- package/dist/utils/path.js +13 -1
- package/package.json +2 -2
- package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
- package/dist/shims/internal/parse-cookie-header.js +0 -30
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
//#region src/server/normalize-path.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Re-encode path delimiter characters that were decoded by decodeURIComponent.
|
|
4
|
-
* After decoding a URL segment, characters like / # ? \ need to be re-encoded
|
|
5
|
-
* so they don't change the path structure.
|
|
6
|
-
*
|
|
7
|
-
* Ported from Next.js: packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts
|
|
8
|
-
* https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts
|
|
9
|
-
*/
|
|
10
2
|
declare function escapePathDelimiters(segment: string, escapeEncoded?: boolean): string;
|
|
11
3
|
/**
|
|
12
4
|
* Decode a URL pathname segment-by-segment, preserving encoded path delimiters.
|
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
* Ported from Next.js: packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts
|
|
8
8
|
* https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/router/utils/escape-path-delimiters.ts
|
|
9
9
|
*/
|
|
10
|
+
const PATH_DELIMITERS_RE = /([/#?])/gi;
|
|
11
|
+
const PATH_DELIMITERS_ENCODED_RE = /([/#?]|%(2f|23|3f|5c))/gi;
|
|
10
12
|
function escapePathDelimiters(segment, escapeEncoded) {
|
|
11
|
-
return segment.replace(
|
|
13
|
+
return segment.replace(escapeEncoded ? PATH_DELIMITERS_ENCODED_RE : PATH_DELIMITERS_RE, (char) => encodeURIComponent(char));
|
|
12
14
|
}
|
|
13
15
|
/**
|
|
14
16
|
* Decode a URL pathname segment-by-segment, preserving encoded path delimiters.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/server/otel-tracer-extension.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* OpenTelemetry tracer provider extension for Cache Components.
|
|
4
|
+
*
|
|
5
|
+
* When `cacheComponents: true` is enabled in next.config, component renders
|
|
6
|
+
* go through multiple phases (warmup → resume). During these phases, the
|
|
7
|
+
* `workUnitAsyncStorage` carries a prerender or cache store. Without this
|
|
8
|
+
* extension, calls to `tracer.startSpan()` / `tracer.startActiveSpan()` from
|
|
9
|
+
* inside user RSC code would inherit that prerender context, causing:
|
|
10
|
+
*
|
|
11
|
+
* 1. Spans to reuse the same trace ID across requests (the frozen prerender
|
|
12
|
+
* context bleeds into the runtime resume render).
|
|
13
|
+
* 2. Spans not being created at all during fallback resume (the work unit
|
|
14
|
+
* context gates span creation in some OTel SDK implementations).
|
|
15
|
+
*
|
|
16
|
+
* The fix mirrors Next.js's `instrumentation-node-extensions.ts`:
|
|
17
|
+
* - Wrap `tracer.startSpan` to exit `workUnitAsyncStorage` before creating
|
|
18
|
+
* the span, ensuring a clean context for span ID generation.
|
|
19
|
+
* - Wrap `tracer.startActiveSpan` similarly and re-enter the work unit store
|
|
20
|
+
* for the callback, so that the callback runs with the correct request
|
|
21
|
+
* context restored.
|
|
22
|
+
*
|
|
23
|
+
* This extension is intentionally a no-op when:
|
|
24
|
+
* - `@opentelemetry/api` is not installed (graceful degradation).
|
|
25
|
+
* - No OTel tracer provider has been registered (provider is the noop provider).
|
|
26
|
+
* - `workUnitAsyncStorage` has no active store (non-render contexts).
|
|
27
|
+
*
|
|
28
|
+
* References:
|
|
29
|
+
* - packages/next/src/server/lib/router-utils/instrumentation-node-extensions.ts
|
|
30
|
+
* - https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/instrumentation-node-extensions.ts
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Extend the registered OTel tracer provider so that `startSpan` and
|
|
34
|
+
* `startActiveSpan` exit the `workUnitAsyncStorage` context before creating
|
|
35
|
+
* spans. This prevents the prerender/cache work unit store from leaking into
|
|
36
|
+
* span ID generation during Cache Component fallback resumes.
|
|
37
|
+
*
|
|
38
|
+
* Safe to call multiple times — subsequent calls are no-ops once the provider
|
|
39
|
+
* has been wrapped.
|
|
40
|
+
*
|
|
41
|
+
* Must only be called in Node.js environments (not Edge runtime).
|
|
42
|
+
*/
|
|
43
|
+
declare function extendTracerProviderForCacheComponents(): void;
|
|
44
|
+
//#endregion
|
|
45
|
+
export { extendTracerProviderForCacheComponents };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { workUnitAsyncStorage } from "../shims/internal/work-unit-async-storage.js";
|
|
2
|
+
//#region src/server/otel-tracer-extension.ts
|
|
3
|
+
/**
|
|
4
|
+
* OpenTelemetry tracer provider extension for Cache Components.
|
|
5
|
+
*
|
|
6
|
+
* When `cacheComponents: true` is enabled in next.config, component renders
|
|
7
|
+
* go through multiple phases (warmup → resume). During these phases, the
|
|
8
|
+
* `workUnitAsyncStorage` carries a prerender or cache store. Without this
|
|
9
|
+
* extension, calls to `tracer.startSpan()` / `tracer.startActiveSpan()` from
|
|
10
|
+
* inside user RSC code would inherit that prerender context, causing:
|
|
11
|
+
*
|
|
12
|
+
* 1. Spans to reuse the same trace ID across requests (the frozen prerender
|
|
13
|
+
* context bleeds into the runtime resume render).
|
|
14
|
+
* 2. Spans not being created at all during fallback resume (the work unit
|
|
15
|
+
* context gates span creation in some OTel SDK implementations).
|
|
16
|
+
*
|
|
17
|
+
* The fix mirrors Next.js's `instrumentation-node-extensions.ts`:
|
|
18
|
+
* - Wrap `tracer.startSpan` to exit `workUnitAsyncStorage` before creating
|
|
19
|
+
* the span, ensuring a clean context for span ID generation.
|
|
20
|
+
* - Wrap `tracer.startActiveSpan` similarly and re-enter the work unit store
|
|
21
|
+
* for the callback, so that the callback runs with the correct request
|
|
22
|
+
* context restored.
|
|
23
|
+
*
|
|
24
|
+
* This extension is intentionally a no-op when:
|
|
25
|
+
* - `@opentelemetry/api` is not installed (graceful degradation).
|
|
26
|
+
* - No OTel tracer provider has been registered (provider is the noop provider).
|
|
27
|
+
* - `workUnitAsyncStorage` has no active store (non-render contexts).
|
|
28
|
+
*
|
|
29
|
+
* References:
|
|
30
|
+
* - packages/next/src/server/lib/router-utils/instrumentation-node-extensions.ts
|
|
31
|
+
* - https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/instrumentation-node-extensions.ts
|
|
32
|
+
*/
|
|
33
|
+
const extendedProviders = /* @__PURE__ */ new WeakSet();
|
|
34
|
+
const USE_CACHE_FUNCTION_SYMBOL = Symbol.for("vinext.useCacheFunction");
|
|
35
|
+
function isUseCacheFn(fn) {
|
|
36
|
+
return typeof fn === "function" && fn[USE_CACHE_FUNCTION_SYMBOL] === true;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Extend the registered OTel tracer provider so that `startSpan` and
|
|
40
|
+
* `startActiveSpan` exit the `workUnitAsyncStorage` context before creating
|
|
41
|
+
* spans. This prevents the prerender/cache work unit store from leaking into
|
|
42
|
+
* span ID generation during Cache Component fallback resumes.
|
|
43
|
+
*
|
|
44
|
+
* Safe to call multiple times — subsequent calls are no-ops once the provider
|
|
45
|
+
* has been wrapped.
|
|
46
|
+
*
|
|
47
|
+
* Must only be called in Node.js environments (not Edge runtime).
|
|
48
|
+
*/
|
|
49
|
+
function extendTracerProviderForCacheComponents() {
|
|
50
|
+
let api;
|
|
51
|
+
try {
|
|
52
|
+
const req = globalThis.require;
|
|
53
|
+
if (typeof req === "function") api = req("@opentelemetry/api");
|
|
54
|
+
} catch {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (!api) return;
|
|
58
|
+
const provider = api.trace.getTracerProvider();
|
|
59
|
+
if (!provider || typeof provider.getTracer !== "function") return;
|
|
60
|
+
if (extendedProviders.has(provider)) return;
|
|
61
|
+
extendedProviders.add(provider);
|
|
62
|
+
const originalGetTracer = provider.getTracer.bind(provider);
|
|
63
|
+
const wrappedTracers = /* @__PURE__ */ new WeakSet();
|
|
64
|
+
provider.getTracer = (...args) => {
|
|
65
|
+
const tracer = originalGetTracer(...args);
|
|
66
|
+
if (!tracer || wrappedTracers.has(tracer)) return tracer;
|
|
67
|
+
const originalStartSpan = tracer.startSpan;
|
|
68
|
+
if (typeof originalStartSpan === "function") tracer.startSpan = (...startSpanArgs) => workUnitAsyncStorage.exit(() => originalStartSpan.apply(tracer, startSpanArgs));
|
|
69
|
+
const originalStartActiveSpan = tracer.startActiveSpan;
|
|
70
|
+
if (typeof originalStartActiveSpan === "function") tracer.startActiveSpan = (...startActiveSpanArgs) => {
|
|
71
|
+
const workUnitStore = workUnitAsyncStorage.getStore();
|
|
72
|
+
if (!workUnitStore) return originalStartActiveSpan.apply(tracer, startActiveSpanArgs);
|
|
73
|
+
let fnIdx = 0;
|
|
74
|
+
if (startActiveSpanArgs.length === 2 && typeof startActiveSpanArgs[1] === "function") fnIdx = 1;
|
|
75
|
+
else if (startActiveSpanArgs.length === 3 && typeof startActiveSpanArgs[2] === "function") fnIdx = 2;
|
|
76
|
+
else if (startActiveSpanArgs.length > 3 && typeof startActiveSpanArgs[3] === "function") fnIdx = 3;
|
|
77
|
+
if (fnIdx > 0) {
|
|
78
|
+
const originalFn = startActiveSpanArgs[fnIdx];
|
|
79
|
+
if (isUseCacheFn(originalFn)) console.error("A Cache Function (`use cache`) was passed to startActiveSpan which means it will receive a Span argument with a possibly random ID on every invocation leading to cache misses. Provide a wrapping function around the Cache Function that does not forward the Span argument to avoid this issue.");
|
|
80
|
+
startActiveSpanArgs[fnIdx] = (...cbArgs) => workUnitAsyncStorage.run(workUnitStore, originalFn, ...cbArgs);
|
|
81
|
+
}
|
|
82
|
+
return workUnitAsyncStorage.exit(() => originalStartActiveSpan.apply(tracer, startActiveSpanArgs));
|
|
83
|
+
};
|
|
84
|
+
wrappedTracers.add(tracer);
|
|
85
|
+
return tracer;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
export { extendTracerProviderForCacheComponents };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NextI18nConfig } from "../config/next-config.js";
|
|
1
2
|
import { Route } from "../routing/pages-router.js";
|
|
2
3
|
import { ExecutionContextLike } from "../shims/request-context.js";
|
|
3
4
|
import { PagesReqResRequest, PagesReqResResponse, PagesRequestQuery } from "./pages-node-compat.js";
|
|
@@ -12,8 +13,7 @@ type PagesApiRouteConfig = {
|
|
|
12
13
|
* `bodyParser: false` is critical for webhook handlers (Stripe, GitHub,
|
|
13
14
|
* Slack, etc.) that need to read the raw bytes to verify an HMAC
|
|
14
15
|
* signature. With it set, `req.body` is left undefined and the raw stream
|
|
15
|
-
*
|
|
16
|
-
* code can consume it.
|
|
16
|
+
* remains available through the Node-readable request object.
|
|
17
17
|
*
|
|
18
18
|
* @see https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config
|
|
19
19
|
*/
|
|
@@ -22,9 +22,21 @@ type PagesApiRouteConfig = {
|
|
|
22
22
|
sizeLimit?: string | number;
|
|
23
23
|
};
|
|
24
24
|
responseLimit?: boolean | string | number;
|
|
25
|
+
/**
|
|
26
|
+
* `externalResolver: true` declares that the response is sent by an
|
|
27
|
+
* external resolver (e.g. express/connect proxy middleware) that may
|
|
28
|
+
* complete after the handler's promise settles. Next.js uses it to
|
|
29
|
+
* suppress the "API resolved without sending a response" dev warning;
|
|
30
|
+
* vinext additionally uses it to suppress the auto-`end()` safety net,
|
|
31
|
+
* which would otherwise resolve an empty response before the external
|
|
32
|
+
* resolver writes.
|
|
33
|
+
*
|
|
34
|
+
* @see https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config
|
|
35
|
+
*/
|
|
36
|
+
externalResolver?: boolean;
|
|
25
37
|
};
|
|
26
38
|
};
|
|
27
|
-
type PagesNodeApiRouteHandler = (req: PagesReqResRequest, res: PagesReqResResponse) =>
|
|
39
|
+
type PagesNodeApiRouteHandler = (req: PagesReqResRequest, res: PagesReqResResponse) => unknown;
|
|
28
40
|
type PagesEdgeApiRouteHandler = (request: Request) => Response | Promise<Response>;
|
|
29
41
|
type PagesApiRouteModule = {
|
|
30
42
|
/**
|
|
@@ -60,6 +72,11 @@ type HandlePagesApiRouteOptions = {
|
|
|
60
72
|
reportRequestError?: (error: Error, routePattern: string) => void | Promise<void>;
|
|
61
73
|
request: Request;
|
|
62
74
|
url: string;
|
|
75
|
+
nextConfig?: {
|
|
76
|
+
basePath?: string;
|
|
77
|
+
i18n?: NextI18nConfig | null;
|
|
78
|
+
trailingSlash?: boolean;
|
|
79
|
+
};
|
|
63
80
|
};
|
|
64
81
|
declare function handlePagesApiRoute(options: HandlePagesApiRouteOptions): Promise<Response>;
|
|
65
82
|
//#endregion
|
|
@@ -2,7 +2,8 @@ import "./server-globals.js";
|
|
|
2
2
|
import { runWithExecutionContext } from "../shims/request-context.js";
|
|
3
3
|
import { NextRequest } from "../shims/server.js";
|
|
4
4
|
import { internalServerErrorResponse } from "./http-error-responses.js";
|
|
5
|
-
import {
|
|
5
|
+
import { cloneRequestWithUrl } from "./request-pipeline.js";
|
|
6
|
+
import { mergeRouteParamsIntoQuery, parseQueryString, urlQueryToSearchParams } from "../utils/query.js";
|
|
6
7
|
import { PagesBodyParseError } from "./pages-media-type.js";
|
|
7
8
|
import { isEdgeApiRuntime } from "./edge-api-runtime.js";
|
|
8
9
|
import { resolveBodyParserConfig } from "./pages-body-parser-config.js";
|
|
@@ -14,6 +15,12 @@ function resolveModuleRuntime(module) {
|
|
|
14
15
|
function buildPagesApiQuery(url, params) {
|
|
15
16
|
return mergeRouteParamsIntoQuery(parseQueryString(url), params);
|
|
16
17
|
}
|
|
18
|
+
function createEdgeApiRequest(request, url, params) {
|
|
19
|
+
const resolvedUrl = new URL(request.url);
|
|
20
|
+
resolvedUrl.search = urlQueryToSearchParams(buildPagesApiQuery(url, params)).toString();
|
|
21
|
+
const resolvedUrlString = resolvedUrl.toString();
|
|
22
|
+
return resolvedUrlString === request.url ? request : cloneRequestWithUrl(request, resolvedUrlString);
|
|
23
|
+
}
|
|
17
24
|
function isEdgeApiRouteModule(module) {
|
|
18
25
|
return typeof module.default === "function" && isEdgeApiRuntime(resolveModuleRuntime(module));
|
|
19
26
|
}
|
|
@@ -29,7 +36,11 @@ async function _handlePagesApiRoute(options) {
|
|
|
29
36
|
const { route, params } = options.match;
|
|
30
37
|
try {
|
|
31
38
|
if (isEdgeApiRouteModule(route.module)) {
|
|
32
|
-
const nextRequest = new NextRequest(options.request)
|
|
39
|
+
const nextRequest = new NextRequest(createEdgeApiRequest(options.request, options.url, params), options.nextConfig ? { nextConfig: {
|
|
40
|
+
basePath: options.nextConfig.basePath,
|
|
41
|
+
i18n: options.nextConfig.i18n ?? void 0,
|
|
42
|
+
trailingSlash: options.nextConfig.trailingSlash
|
|
43
|
+
} } : void 0);
|
|
33
44
|
const response = await route.module.default(nextRequest);
|
|
34
45
|
if (response instanceof Response) return response;
|
|
35
46
|
throw new Error("Edge API route did not return a Response");
|
|
@@ -43,8 +54,13 @@ async function _handlePagesApiRoute(options) {
|
|
|
43
54
|
request: options.request,
|
|
44
55
|
url: options.url
|
|
45
56
|
});
|
|
57
|
+
let resWasPiped = false;
|
|
58
|
+
res.once("pipe", () => {
|
|
59
|
+
resWasPiped = true;
|
|
60
|
+
});
|
|
61
|
+
const externalResolver = route.module.config?.api?.externalResolver || false;
|
|
46
62
|
await route.module.default(req, res);
|
|
47
|
-
res.end();
|
|
63
|
+
if (!externalResolver && !resWasPiped && !res.headersSent) res.end();
|
|
48
64
|
return await responsePromise;
|
|
49
65
|
} catch (error) {
|
|
50
66
|
if (error instanceof PagesBodyParseError) return new Response(error.message, {
|
|
@@ -23,11 +23,14 @@ declare function resolveSsrManifest(manifest: Record<string, string[]> | null |
|
|
|
23
23
|
*/
|
|
24
24
|
declare function getManifestFilesForModule(manifest: Record<string, string[]> | null | undefined, moduleId: string | null | undefined): string[] | null;
|
|
25
25
|
/**
|
|
26
|
-
* Find the first `.js` file in the manifest for `moduleId` and return
|
|
27
|
-
*
|
|
28
|
-
* the matched page or the `_app` module
|
|
26
|
+
* Find the first `.js` file in the manifest for `moduleId` and return the URL it
|
|
27
|
+
* is actually SERVED from. Used to resolve the client-navigation / hydration URL
|
|
28
|
+
* for the matched page or the `_app` module (it is `import()`ed on the client),
|
|
29
|
+
* so it must point at the served location: `assetPrefix` replaces `basePath` for
|
|
30
|
+
* asset URLs. SSR-manifest values are base-anchored; re-anchor under any
|
|
31
|
+
* configured `assetPrefix` (default `""` keeps the legacy `"/" + file`).
|
|
29
32
|
*/
|
|
30
|
-
declare function resolveClientModuleUrl(manifest: Record<string, string[]> | null | undefined, moduleId: string | null | undefined): string | undefined;
|
|
33
|
+
declare function resolveClientModuleUrl(manifest: Record<string, string[]> | null | undefined, moduleId: string | null | undefined, basePath?: string, assetPrefix?: string, _deploymentId?: string): string | undefined;
|
|
31
34
|
type CollectAssetTagsOptions = {
|
|
32
35
|
/**
|
|
33
36
|
* SSR manifest mapping module file paths to their associated asset list.
|
|
@@ -46,6 +49,15 @@ type CollectAssetTagsOptions = {
|
|
|
46
49
|
* default.
|
|
47
50
|
*/
|
|
48
51
|
disableOptimizedLoading: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Configured `basePath` / `assetPrefix`. SSR-manifest values are base-anchored
|
|
54
|
+
* (needed for the lazy-chunk membership test), but the EMITTED href must point
|
|
55
|
+
* where the asset is actually served — `assetPrefix` replaces `basePath` for
|
|
56
|
+
* asset URLs. Default `""` (both unset) keeps the legacy `"/" + value` href.
|
|
57
|
+
*/
|
|
58
|
+
basePath?: string;
|
|
59
|
+
assetPrefix?: string;
|
|
60
|
+
deploymentId?: string;
|
|
49
61
|
};
|
|
50
62
|
/**
|
|
51
63
|
* Build the HTML `<link>` and `<script>` tag string for the SSR response.
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { appendDeploymentIdQuery } from "../utils/deployment-id.js";
|
|
1
2
|
import { createNonceAttribute } from "./html.js";
|
|
3
|
+
import { assetServingUrlFromBaseAnchored } from "../utils/manifest-paths.js";
|
|
2
4
|
//#region src/server/pages-asset-tags.ts
|
|
3
5
|
/**
|
|
4
6
|
* Pages Router SSR asset-tag helpers.
|
|
@@ -33,18 +35,20 @@ function getManifestFilesForModule(manifest, moduleId) {
|
|
|
33
35
|
return null;
|
|
34
36
|
}
|
|
35
37
|
/**
|
|
36
|
-
* Find the first `.js` file in the manifest for `moduleId` and return
|
|
37
|
-
*
|
|
38
|
-
* the matched page or the `_app` module
|
|
38
|
+
* Find the first `.js` file in the manifest for `moduleId` and return the URL it
|
|
39
|
+
* is actually SERVED from. Used to resolve the client-navigation / hydration URL
|
|
40
|
+
* for the matched page or the `_app` module (it is `import()`ed on the client),
|
|
41
|
+
* so it must point at the served location: `assetPrefix` replaces `basePath` for
|
|
42
|
+
* asset URLs. SSR-manifest values are base-anchored; re-anchor under any
|
|
43
|
+
* configured `assetPrefix` (default `""` keeps the legacy `"/" + file`).
|
|
39
44
|
*/
|
|
40
|
-
function resolveClientModuleUrl(manifest, moduleId) {
|
|
45
|
+
function resolveClientModuleUrl(manifest, moduleId, basePath = "", assetPrefix = "", _deploymentId) {
|
|
41
46
|
const files = getManifestFilesForModule(resolveSsrManifest(manifest), moduleId);
|
|
42
47
|
if (!files) return void 0;
|
|
43
48
|
for (let i = 0; i < files.length; i++) {
|
|
44
|
-
|
|
49
|
+
const file = files[i];
|
|
45
50
|
if (!file || !file.endsWith(".js")) continue;
|
|
46
|
-
|
|
47
|
-
return file;
|
|
51
|
+
return assetServingUrlFromBaseAnchored(file, basePath, assetPrefix);
|
|
48
52
|
}
|
|
49
53
|
}
|
|
50
54
|
/**
|
|
@@ -67,13 +71,19 @@ function collectAssetTags(options) {
|
|
|
67
71
|
const seen = /* @__PURE__ */ new Set();
|
|
68
72
|
const nonceAttr = createNonceAttribute(options.scriptNonce);
|
|
69
73
|
const deferAttr = options.disableOptimizedLoading ? "" : " defer";
|
|
74
|
+
const basePath = options.basePath ?? "";
|
|
75
|
+
const assetPrefix = options.assetPrefix ?? "";
|
|
76
|
+
const href = (value) => {
|
|
77
|
+
const url = assetServingUrlFromBaseAnchored(value, basePath, assetPrefix);
|
|
78
|
+
return value.endsWith(".js") ? url : appendDeploymentIdQuery(url, options.deploymentId);
|
|
79
|
+
};
|
|
70
80
|
const lazyChunks = typeof globalThis !== "undefined" && globalThis.__VINEXT_LAZY_CHUNKS__ || null;
|
|
71
81
|
const lazySet = lazyChunks && lazyChunks.length > 0 ? new Set(lazyChunks) : null;
|
|
72
82
|
if (typeof globalThis !== "undefined" && globalThis.__VINEXT_CLIENT_ENTRY__) {
|
|
73
83
|
const entry = globalThis.__VINEXT_CLIENT_ENTRY__;
|
|
74
84
|
seen.add(entry);
|
|
75
|
-
tags.push("<link rel=\"modulepreload\"" + nonceAttr + " href=\"
|
|
76
|
-
tags.push("<script type=\"module\"" + deferAttr + nonceAttr + " src=\"
|
|
85
|
+
tags.push("<link rel=\"modulepreload\"" + nonceAttr + " href=\"" + href(entry) + "\" />");
|
|
86
|
+
tags.push("<script type=\"module\"" + deferAttr + nonceAttr + " src=\"" + href(entry) + "\" crossorigin><\/script>");
|
|
77
87
|
}
|
|
78
88
|
if (m) {
|
|
79
89
|
const allFiles = [];
|
|
@@ -102,11 +112,11 @@ function collectAssetTags(options) {
|
|
|
102
112
|
if (tf.charAt(0) === "/") tf = tf.slice(1);
|
|
103
113
|
if (seen.has(tf)) continue;
|
|
104
114
|
seen.add(tf);
|
|
105
|
-
if (tf.endsWith(".css")) tags.push("<link rel=\"stylesheet\"" + nonceAttr + " href=\"
|
|
115
|
+
if (tf.endsWith(".css")) tags.push("<link rel=\"stylesheet\"" + nonceAttr + " href=\"" + href(tf) + "\" />");
|
|
106
116
|
else if (tf.endsWith(".js")) {
|
|
107
117
|
if (lazySet && lazySet.has(tf)) continue;
|
|
108
|
-
tags.push("<link rel=\"modulepreload\"" + nonceAttr + " href=\"
|
|
109
|
-
tags.push("<script type=\"module\"" + deferAttr + nonceAttr + " src=\"
|
|
118
|
+
tags.push("<link rel=\"modulepreload\"" + nonceAttr + " href=\"" + href(tf) + "\" />");
|
|
119
|
+
tags.push("<script type=\"module\"" + deferAttr + nonceAttr + " src=\"" + href(tf) + "\" crossorigin><\/script>");
|
|
110
120
|
}
|
|
111
121
|
}
|
|
112
122
|
}
|
|
@@ -60,6 +60,13 @@ declare function parseNextDataPathname(pathname: string, buildId: string): NextD
|
|
|
60
60
|
* { pageProps: {...}, /* optional locale data, redirect markers, etc. *\/ }
|
|
61
61
|
*/
|
|
62
62
|
declare function buildNextDataJsonResponse(pageProps: Record<string, unknown>, safeJsonStringify: (value: unknown) => string, init?: ResponseInit): Response;
|
|
63
|
+
/**
|
|
64
|
+
* Build a `_next/data` JSON response from the full Pages props object returned
|
|
65
|
+
* through `_app.getInitialProps`. Next.js serializes the same outer props
|
|
66
|
+
* object that would be passed to `<App />`, so custom app-level props remain
|
|
67
|
+
* siblings of `pageProps` in the data envelope.
|
|
68
|
+
*/
|
|
69
|
+
declare function buildNextDataPropsJsonResponse(props: Record<string, unknown>, safeJsonStringify: (value: unknown) => string, init?: ResponseInit): Response;
|
|
63
70
|
/**
|
|
64
71
|
* Build the 404 response Next.js returns for an unknown `_next/data` page.
|
|
65
72
|
* Next.js renders this as a normal 404 page, but the body shape that clients
|
|
@@ -111,4 +118,4 @@ type NormalizePagesDataRequestResult = {
|
|
|
111
118
|
*/
|
|
112
119
|
declare function normalizePagesDataRequest(request: Request, buildId: string | null): NormalizePagesDataRequestResult;
|
|
113
120
|
//#endregion
|
|
114
|
-
export { buildNextDataJsonResponse, buildNextDataNotFoundResponse, isNextDataPathname, normalizePagesDataRequest, parseNextDataPathname };
|
|
121
|
+
export { buildNextDataJsonResponse, buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, isNextDataPathname, normalizePagesDataRequest, parseNextDataPathname };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
|
|
1
2
|
//#region src/server/pages-data-route.ts
|
|
2
3
|
/**
|
|
3
4
|
* Helpers for the Pages Router `/_next/data/{buildId}/{...page}.json` endpoint.
|
|
@@ -65,7 +66,16 @@ function parseNextDataPathname(pathname, buildId) {
|
|
|
65
66
|
* { pageProps: {...}, /* optional locale data, redirect markers, etc. *\/ }
|
|
66
67
|
*/
|
|
67
68
|
function buildNextDataJsonResponse(pageProps, safeJsonStringify, init) {
|
|
68
|
-
|
|
69
|
+
return buildNextDataPropsJsonResponse({ pageProps }, safeJsonStringify, init);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Build a `_next/data` JSON response from the full Pages props object returned
|
|
73
|
+
* through `_app.getInitialProps`. Next.js serializes the same outer props
|
|
74
|
+
* object that would be passed to `<App />`, so custom app-level props remain
|
|
75
|
+
* siblings of `pageProps` in the data envelope.
|
|
76
|
+
*/
|
|
77
|
+
function buildNextDataPropsJsonResponse(props, safeJsonStringify, init) {
|
|
78
|
+
const body = safeJsonStringify(props);
|
|
69
79
|
return new Response(body, {
|
|
70
80
|
status: init?.status ?? 200,
|
|
71
81
|
statusText: init?.statusText,
|
|
@@ -87,9 +97,12 @@ function buildNextDataJsonResponse(pageProps, safeJsonStringify, init) {
|
|
|
87
97
|
* before checking the status code.
|
|
88
98
|
*/
|
|
89
99
|
function buildNextDataNotFoundResponse() {
|
|
100
|
+
const headers = { "Content-Type": "application/json" };
|
|
101
|
+
const deploymentId = process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID;
|
|
102
|
+
if (deploymentId) headers[NEXTJS_DEPLOYMENT_ID_HEADER] = deploymentId;
|
|
90
103
|
return new Response("{}", {
|
|
91
104
|
status: 404,
|
|
92
|
-
headers
|
|
105
|
+
headers
|
|
93
106
|
});
|
|
94
107
|
}
|
|
95
108
|
/**
|
|
@@ -138,4 +151,4 @@ function normalizePagesDataRequest(request, buildId) {
|
|
|
138
151
|
};
|
|
139
152
|
}
|
|
140
153
|
//#endregion
|
|
141
|
-
export { buildNextDataJsonResponse, buildNextDataNotFoundResponse, isNextDataPathname, normalizePagesDataRequest, parseNextDataPathname };
|
|
154
|
+
export { buildNextDataJsonResponse, buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, isNextDataPathname, normalizePagesDataRequest, parseNextDataPathname };
|
|
@@ -3,6 +3,48 @@ type PagesGetInitialPropsContext = {
|
|
|
3
3
|
req?: unknown;
|
|
4
4
|
res?: unknown;
|
|
5
5
|
err?: unknown;
|
|
6
|
+
pathname?: string;
|
|
7
|
+
query?: Record<string, unknown>;
|
|
8
|
+
asPath?: string;
|
|
9
|
+
locale?: string;
|
|
10
|
+
locales?: string[];
|
|
11
|
+
defaultLocale?: string;
|
|
12
|
+
} & Record<string, unknown>;
|
|
13
|
+
declare function hasPagesGetInitialProps(component: unknown): boolean;
|
|
14
|
+
declare function isResponseSent(res: unknown): boolean;
|
|
15
|
+
declare function loadPagesGetInitialProps(component: unknown, context: PagesGetInitialPropsContext): Promise<Record<string, unknown> | null>;
|
|
16
|
+
/**
|
|
17
|
+
* Decision returned by {@link loadDevAppInitialProps}.
|
|
18
|
+
*
|
|
19
|
+
* - `skip`: the custom `App` has no `getInitialProps`; the caller renders with
|
|
20
|
+
* its existing props unchanged.
|
|
21
|
+
* - `response-sent`: `_app.getInitialProps` ended the response itself (wrote
|
|
22
|
+
* headers / body); the caller must stop and not render.
|
|
23
|
+
* - `render`: the caller should render with the returned `pageProps` /
|
|
24
|
+
* `renderProps`.
|
|
25
|
+
*/
|
|
26
|
+
type DevAppInitialPropsResult = {
|
|
27
|
+
kind: "skip";
|
|
28
|
+
} | {
|
|
29
|
+
kind: "response-sent";
|
|
30
|
+
} | {
|
|
31
|
+
kind: "render";
|
|
32
|
+
pageProps: Record<string, unknown>;
|
|
33
|
+
renderProps: Record<string, unknown> & {
|
|
34
|
+
pageProps: unknown;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
type DevAppInitialPropsContext = {
|
|
38
|
+
appComponent: unknown;
|
|
39
|
+
/**
|
|
40
|
+
* Builds the `AppTree` element passed to `getInitialProps`. Injected so this
|
|
41
|
+
* module stays free of React; the dev SSR handler supplies the real
|
|
42
|
+
* `React.createElement` closure.
|
|
43
|
+
*/
|
|
44
|
+
appTree: (appTreeProps: Record<string, unknown>) => unknown;
|
|
45
|
+
component: unknown;
|
|
46
|
+
req: unknown;
|
|
47
|
+
res: unknown;
|
|
6
48
|
pathname: string;
|
|
7
49
|
query: Record<string, unknown>;
|
|
8
50
|
asPath: string;
|
|
@@ -10,8 +52,16 @@ type PagesGetInitialPropsContext = {
|
|
|
10
52
|
locales?: string[];
|
|
11
53
|
defaultLocale?: string;
|
|
12
54
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Run the custom `App`'s `getInitialProps` for the dev SSR render path and
|
|
57
|
+
* return a decision the caller applies.
|
|
58
|
+
*
|
|
59
|
+
* This is the dev-server counterpart to the production page-data resolver's
|
|
60
|
+
* app-initial-props loading. It is invoked lazily — only when a request is
|
|
61
|
+
* actually going to render (cache miss / on-demand revalidation), never on an
|
|
62
|
+
* ISR cache HIT/STALE that serves cached HTML verbatim — so userland `App`
|
|
63
|
+
* data code does not run on the cache hot path.
|
|
64
|
+
*/
|
|
65
|
+
declare function loadDevAppInitialProps(ctx: DevAppInitialPropsContext): Promise<DevAppInitialPropsResult>;
|
|
16
66
|
//#endregion
|
|
17
|
-
export { hasPagesGetInitialProps, isResponseSent, loadPagesGetInitialProps };
|
|
67
|
+
export { DevAppInitialPropsContext, DevAppInitialPropsResult, hasPagesGetInitialProps, isResponseSent, loadDevAppInitialProps, loadPagesGetInitialProps };
|
|
@@ -46,5 +46,47 @@ async function loadPagesGetInitialProps(component, context) {
|
|
|
46
46
|
if (!isPropsObject(result)) throw new Error(`"${getDisplayName(component)}.getInitialProps()" should resolve to an object. But found "${describeInitialPropsValue(result)}" instead.`);
|
|
47
47
|
return result;
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Run the custom `App`'s `getInitialProps` for the dev SSR render path and
|
|
51
|
+
* return a decision the caller applies.
|
|
52
|
+
*
|
|
53
|
+
* This is the dev-server counterpart to the production page-data resolver's
|
|
54
|
+
* app-initial-props loading. It is invoked lazily — only when a request is
|
|
55
|
+
* actually going to render (cache miss / on-demand revalidation), never on an
|
|
56
|
+
* ISR cache HIT/STALE that serves cached HTML verbatim — so userland `App`
|
|
57
|
+
* data code does not run on the cache hot path.
|
|
58
|
+
*/
|
|
59
|
+
async function loadDevAppInitialProps(ctx) {
|
|
60
|
+
if (!hasPagesGetInitialProps(ctx.appComponent)) return { kind: "skip" };
|
|
61
|
+
const initialProps = await loadPagesGetInitialProps(ctx.appComponent, {
|
|
62
|
+
AppTree: ctx.appTree,
|
|
63
|
+
Component: ctx.component,
|
|
64
|
+
router: {
|
|
65
|
+
pathname: ctx.pathname,
|
|
66
|
+
query: ctx.query,
|
|
67
|
+
asPath: ctx.asPath
|
|
68
|
+
},
|
|
69
|
+
ctx: {
|
|
70
|
+
req: ctx.req,
|
|
71
|
+
res: ctx.res,
|
|
72
|
+
pathname: ctx.pathname,
|
|
73
|
+
query: ctx.query,
|
|
74
|
+
asPath: ctx.asPath,
|
|
75
|
+
locale: ctx.locale,
|
|
76
|
+
locales: ctx.locales,
|
|
77
|
+
defaultLocale: ctx.defaultLocale
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
if (isResponseSent(ctx.res)) return { kind: "response-sent" };
|
|
81
|
+
const initialPageProps = isPropsObject(initialProps) ? initialProps.pageProps : void 0;
|
|
82
|
+
return {
|
|
83
|
+
kind: "render",
|
|
84
|
+
pageProps: isPropsObject(initialPageProps) ? initialPageProps : {},
|
|
85
|
+
renderProps: isPropsObject(initialProps) ? {
|
|
86
|
+
...initialProps,
|
|
87
|
+
pageProps: initialPageProps
|
|
88
|
+
} : { pageProps: initialPageProps }
|
|
89
|
+
};
|
|
90
|
+
}
|
|
49
91
|
//#endregion
|
|
50
|
-
export { hasPagesGetInitialProps, isResponseSent, loadPagesGetInitialProps };
|
|
92
|
+
export { hasPagesGetInitialProps, isResponseSent, loadDevAppInitialProps, loadPagesGetInitialProps };
|
|
@@ -1,34 +1,26 @@
|
|
|
1
1
|
import { PagesBodyParseError } from "./pages-media-type.js";
|
|
2
2
|
import { RevalidateOptions } from "./pages-revalidate.js";
|
|
3
|
+
import { Readable, Writable } from "node:stream";
|
|
3
4
|
|
|
4
5
|
//#region src/server/pages-node-compat.d.ts
|
|
5
6
|
type PagesRequestQuery = Record<string, string | string[]>;
|
|
6
|
-
type PagesReqResRequest = {
|
|
7
|
+
type PagesReqResRequest = Readable & {
|
|
7
8
|
method: string;
|
|
8
9
|
url: string;
|
|
9
10
|
headers: Record<string, string>;
|
|
10
11
|
query: PagesRequestQuery;
|
|
11
12
|
body: unknown;
|
|
12
13
|
cookies: Record<string, string>;
|
|
13
|
-
/**
|
|
14
|
-
* Async-iterator hook so handlers can `for await (const chunk of req)` —
|
|
15
|
-
* matching Node's `IncomingMessage` contract. Critical for the
|
|
16
|
-
* `bodyParser: false` opt-out (webhook signature verification etc.) where
|
|
17
|
-
* `req.body` is left undefined and user code is expected to drain the raw
|
|
18
|
-
* stream off `req` itself.
|
|
19
|
-
*/
|
|
20
|
-
[Symbol.asyncIterator]: () => AsyncIterator<Uint8Array>;
|
|
21
14
|
};
|
|
22
15
|
type PagesReqResHeaders = {
|
|
23
16
|
[key: string]: string | number | boolean | string[];
|
|
24
17
|
};
|
|
25
|
-
type PagesReqResResponse = {
|
|
18
|
+
type PagesReqResResponse = Writable & {
|
|
26
19
|
statusCode: number;
|
|
27
20
|
readonly headersSent: boolean;
|
|
28
21
|
writeHead: (code: number, headers?: PagesReqResHeaders) => PagesReqResResponse;
|
|
29
22
|
setHeader: (name: string, value: string | number | boolean | string[]) => PagesReqResResponse;
|
|
30
23
|
getHeader: (name: string) => string | number | boolean | string[] | undefined;
|
|
31
|
-
end: (data?: BodyInit | null) => void;
|
|
32
24
|
status: (code: number) => PagesReqResResponse;
|
|
33
25
|
json: (data: unknown) => void;
|
|
34
26
|
send: (data: unknown) => void;
|