vinext 0.1.0 → 0.1.2
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/assets-ignore.d.ts +32 -0
- package/dist/build/assets-ignore.js +48 -0
- package/dist/build/client-build-config.d.ts +33 -1
- package/dist/build/client-build-config.js +66 -1
- package/dist/check.js +4 -3
- package/dist/cli.js +2 -0
- package/dist/client/navigation-runtime.d.ts +11 -2
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/client/vinext-next-data.d.ts +2 -1
- package/dist/client/window-next.d.ts +6 -4
- package/dist/config/config-matchers.d.ts +31 -5
- package/dist/config/config-matchers.js +50 -3
- package/dist/config/next-config.d.ts +29 -3
- package/dist/config/next-config.js +32 -2
- package/dist/deploy.js +47 -304
- package/dist/entries/app-rsc-entry.d.ts +8 -2
- package/dist/entries/app-rsc-entry.js +61 -5
- package/dist/entries/app-rsc-manifest.js +20 -2
- package/dist/entries/pages-client-entry.js +1 -1
- package/dist/entries/pages-server-entry.js +16 -7
- package/dist/index.d.ts +0 -2
- package/dist/index.js +233 -280
- package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
- package/dist/plugins/dynamic-preload-metadata.js +415 -0
- package/dist/plugins/og-assets.js +2 -2
- package/dist/plugins/optimize-imports.d.ts +8 -4
- package/dist/plugins/optimize-imports.js +16 -12
- package/dist/plugins/postcss.js +18 -14
- package/dist/plugins/require-context.d.ts +6 -0
- package/dist/plugins/require-context.js +184 -0
- package/dist/plugins/sass.d.ts +53 -24
- package/dist/plugins/sass.js +249 -1
- 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 +35 -2
- package/dist/routing/app-route-graph.js +179 -8
- package/dist/routing/file-matcher.js +1 -1
- package/dist/routing/route-pattern.d.ts +2 -1
- package/dist/routing/route-pattern.js +16 -1
- package/dist/server/api-handler.js +4 -0
- package/dist/server/app-browser-entry.js +155 -215
- package/dist/server/app-browser-error.d.ts +4 -1
- package/dist/server/app-browser-error.js +7 -1
- 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-interception-context.d.ts +2 -1
- package/dist/server/app-browser-interception-context.js +15 -2
- package/dist/server/app-browser-navigation-controller.d.ts +13 -2
- package/dist/server/app-browser-navigation-controller.js +83 -4
- package/dist/server/app-browser-popstate.d.ts +12 -3
- package/dist/server/app-browser-popstate.js +19 -4
- 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-state.d.ts +3 -0
- package/dist/server/app-browser-state.js +10 -10
- package/dist/server/app-browser-visible-commit.js +10 -8
- package/dist/server/app-fallback-renderer.d.ts +2 -1
- package/dist/server/app-fallback-renderer.js +3 -1
- package/dist/server/app-history-state.d.ts +45 -1
- package/dist/server/app-history-state.js +109 -1
- package/dist/server/app-middleware.js +1 -0
- package/dist/server/app-optimistic-routing.js +22 -1
- package/dist/server/app-page-boundary-render.d.ts +2 -1
- package/dist/server/app-page-boundary-render.js +45 -21
- package/dist/server/app-page-cache.js +9 -7
- package/dist/server/app-page-dispatch.d.ts +14 -0
- package/dist/server/app-page-dispatch.js +21 -6
- package/dist/server/app-page-element-builder.d.ts +23 -2
- package/dist/server/app-page-element-builder.js +58 -17
- package/dist/server/app-page-execution.d.ts +1 -1
- package/dist/server/app-page-execution.js +32 -17
- package/dist/server/app-page-render.d.ts +7 -1
- package/dist/server/app-page-render.js +11 -16
- package/dist/server/app-page-request.d.ts +9 -6
- package/dist/server/app-page-request.js +14 -10
- package/dist/server/app-page-response.d.ts +2 -2
- package/dist/server/app-page-response.js +2 -2
- package/dist/server/app-page-route-wiring.d.ts +3 -1
- package/dist/server/app-page-route-wiring.js +10 -8
- package/dist/server/app-page-stream.d.ts +37 -7
- package/dist/server/app-page-stream.js +36 -6
- package/dist/server/app-pages-bridge.d.ts +16 -0
- package/dist/server/app-pages-bridge.js +23 -3
- package/dist/server/app-route-handler-cache.d.ts +1 -0
- package/dist/server/app-route-handler-cache.js +1 -0
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +2 -0
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-response.js +11 -10
- package/dist/server/app-route-handler-runtime.d.ts +1 -0
- package/dist/server/app-route-handler-runtime.js +15 -3
- package/dist/server/app-rsc-handler.d.ts +1 -0
- package/dist/server/app-rsc-handler.js +5 -4
- package/dist/server/app-rsc-response-finalizer.js +1 -1
- package/dist/server/app-rsc-route-matching.d.ts +20 -1
- package/dist/server/app-rsc-route-matching.js +29 -4
- package/dist/server/app-server-action-execution.d.ts +22 -1
- package/dist/server/app-server-action-execution.js +73 -12
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +19 -3
- package/dist/server/app-ssr-stream.js +9 -1
- package/dist/server/dev-lockfile.js +2 -1
- package/dist/server/dev-server.d.ts +1 -1
- package/dist/server/dev-server.js +97 -43
- package/dist/server/headers.d.ts +8 -1
- package/dist/server/headers.js +8 -1
- package/dist/server/instrumentation-runtime.d.ts +6 -0
- package/dist/server/instrumentation-runtime.js +8 -0
- package/dist/server/isr-cache.d.ts +37 -1
- package/dist/server/isr-cache.js +85 -1
- 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 +62 -1
- package/dist/server/navigation-planner.js +193 -3
- package/dist/server/navigation-trace.d.ts +12 -2
- package/dist/server/navigation-trace.js +11 -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 +14 -3
- package/dist/server/pages-api-route.js +6 -1
- package/dist/server/pages-asset-tags.d.ts +15 -4
- package/dist/server/pages-asset-tags.js +18 -12
- package/dist/server/pages-data-route.js +5 -1
- package/dist/server/pages-node-compat.d.ts +5 -11
- package/dist/server/pages-node-compat.js +175 -118
- package/dist/server/pages-page-data.d.ts +38 -7
- package/dist/server/pages-page-data.js +64 -18
- package/dist/server/pages-page-handler.d.ts +10 -2
- package/dist/server/pages-page-handler.js +49 -20
- package/dist/server/pages-page-response.d.ts +55 -2
- package/dist/server/pages-page-response.js +74 -6
- package/dist/server/pages-readiness.d.ts +36 -0
- package/dist/server/pages-readiness.js +21 -0
- package/dist/server/pages-request-pipeline.d.ts +113 -0
- package/dist/server/pages-request-pipeline.js +230 -0
- package/dist/server/pages-revalidate.d.ts +15 -0
- package/dist/server/pages-revalidate.js +19 -0
- package/dist/server/prod-server.d.ts +45 -3
- package/dist/server/prod-server.js +182 -234
- package/dist/server/socket-error-backstop.d.ts +19 -1
- package/dist/server/socket-error-backstop.js +77 -4
- package/dist/shims/app-router-scroll.js +22 -4
- package/dist/shims/cache-runtime.js +39 -2
- package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
- package/dist/shims/dynamic-preload-chunks.js +77 -0
- package/dist/shims/dynamic.d.ts +4 -0
- package/dist/shims/dynamic.js +4 -2
- package/dist/shims/error-boundary.d.ts +17 -7
- package/dist/shims/error-boundary.js +8 -1
- package/dist/shims/error.js +37 -11
- package/dist/shims/fetch-cache.d.ts +22 -1
- package/dist/shims/fetch-cache.js +28 -1
- package/dist/shims/hash-scroll.d.ts +1 -0
- package/dist/shims/hash-scroll.js +3 -1
- package/dist/shims/head.js +6 -1
- package/dist/shims/headers.d.ts +16 -2
- package/dist/shims/headers.js +37 -1
- package/dist/shims/image-config.js +7 -1
- package/dist/shims/internal/app-route-detection.d.ts +6 -3
- package/dist/shims/internal/app-route-detection.js +10 -6
- package/dist/shims/internal/app-router-context.d.ts +5 -0
- package/dist/shims/internal/link-status-registry.d.ts +43 -0
- package/dist/shims/internal/link-status-registry.js +42 -0
- package/dist/shims/internal/route-pattern-for-warning.d.ts +27 -0
- package/dist/shims/internal/route-pattern-for-warning.js +40 -0
- package/dist/shims/internal/utils.d.ts +1 -0
- package/dist/shims/link.js +20 -6
- package/dist/shims/metadata.d.ts +6 -2
- package/dist/shims/metadata.js +32 -14
- package/dist/shims/navigation.d.ts +9 -18
- package/dist/shims/navigation.js +96 -23
- package/dist/shims/router-state.d.ts +1 -0
- package/dist/shims/router-state.js +2 -0
- package/dist/shims/router.d.ts +6 -3
- package/dist/shims/router.js +156 -22
- 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 +17 -1
- package/dist/shims/server.js +31 -6
- package/dist/shims/slot.js +1 -1
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/typegen.js +1 -0
- package/dist/utils/client-build-manifest.d.ts +8 -1
- package/dist/utils/client-build-manifest.js +41 -6
- package/dist/utils/client-entry-manifest.d.ts +11 -0
- package/dist/utils/client-entry-manifest.js +29 -0
- package/dist/utils/client-runtime-metadata.d.ts +45 -0
- package/dist/utils/client-runtime-metadata.js +63 -0
- package/dist/utils/hash.d.ts +17 -1
- package/dist/utils/hash.js +36 -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/path.d.ts +2 -1
- package/dist/utils/path.js +5 -1
- package/package.json +6 -2
|
@@ -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 };
|
|
@@ -12,8 +12,7 @@ type PagesApiRouteConfig = {
|
|
|
12
12
|
* `bodyParser: false` is critical for webhook handlers (Stripe, GitHub,
|
|
13
13
|
* Slack, etc.) that need to read the raw bytes to verify an HMAC
|
|
14
14
|
* signature. With it set, `req.body` is left undefined and the raw stream
|
|
15
|
-
*
|
|
16
|
-
* code can consume it.
|
|
15
|
+
* remains available through the Node-readable request object.
|
|
17
16
|
*
|
|
18
17
|
* @see https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config
|
|
19
18
|
*/
|
|
@@ -22,9 +21,21 @@ type PagesApiRouteConfig = {
|
|
|
22
21
|
sizeLimit?: string | number;
|
|
23
22
|
};
|
|
24
23
|
responseLimit?: boolean | string | number;
|
|
24
|
+
/**
|
|
25
|
+
* `externalResolver: true` declares that the response is sent by an
|
|
26
|
+
* external resolver (e.g. express/connect proxy middleware) that may
|
|
27
|
+
* complete after the handler's promise settles. Next.js uses it to
|
|
28
|
+
* suppress the "API resolved without sending a response" dev warning;
|
|
29
|
+
* vinext additionally uses it to suppress the auto-`end()` safety net,
|
|
30
|
+
* which would otherwise resolve an empty response before the external
|
|
31
|
+
* resolver writes.
|
|
32
|
+
*
|
|
33
|
+
* @see https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config
|
|
34
|
+
*/
|
|
35
|
+
externalResolver?: boolean;
|
|
25
36
|
};
|
|
26
37
|
};
|
|
27
|
-
type PagesNodeApiRouteHandler = (req: PagesReqResRequest, res: PagesReqResResponse) =>
|
|
38
|
+
type PagesNodeApiRouteHandler = (req: PagesReqResRequest, res: PagesReqResResponse) => unknown;
|
|
28
39
|
type PagesEdgeApiRouteHandler = (request: Request) => Response | Promise<Response>;
|
|
29
40
|
type PagesApiRouteModule = {
|
|
30
41
|
/**
|
|
@@ -43,8 +43,13 @@ async function _handlePagesApiRoute(options) {
|
|
|
43
43
|
request: options.request,
|
|
44
44
|
url: options.url
|
|
45
45
|
});
|
|
46
|
+
let resWasPiped = false;
|
|
47
|
+
res.once("pipe", () => {
|
|
48
|
+
resWasPiped = true;
|
|
49
|
+
});
|
|
50
|
+
const externalResolver = route.module.config?.api?.externalResolver || false;
|
|
46
51
|
await route.module.default(req, res);
|
|
47
|
-
res.end();
|
|
52
|
+
if (!externalResolver && !resWasPiped && !res.headersSent) res.end();
|
|
48
53
|
return await responsePromise;
|
|
49
54
|
} catch (error) {
|
|
50
55
|
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): string | undefined;
|
|
31
34
|
type CollectAssetTagsOptions = {
|
|
32
35
|
/**
|
|
33
36
|
* SSR manifest mapping module file paths to their associated asset list.
|
|
@@ -46,6 +49,14 @@ 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;
|
|
49
60
|
};
|
|
50
61
|
/**
|
|
51
62
|
* Build the HTML `<link>` and `<script>` tag string for the SSR response.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createNonceAttribute } from "./html.js";
|
|
2
|
+
import { assetServingUrlFromBaseAnchored } from "../utils/manifest-paths.js";
|
|
2
3
|
//#region src/server/pages-asset-tags.ts
|
|
3
4
|
/**
|
|
4
5
|
* Pages Router SSR asset-tag helpers.
|
|
@@ -33,18 +34,20 @@ function getManifestFilesForModule(manifest, moduleId) {
|
|
|
33
34
|
return null;
|
|
34
35
|
}
|
|
35
36
|
/**
|
|
36
|
-
* Find the first `.js` file in the manifest for `moduleId` and return
|
|
37
|
-
*
|
|
38
|
-
* the matched page or the `_app` module
|
|
37
|
+
* Find the first `.js` file in the manifest for `moduleId` and return the URL it
|
|
38
|
+
* is actually SERVED from. Used to resolve the client-navigation / hydration URL
|
|
39
|
+
* for the matched page or the `_app` module (it is `import()`ed on the client),
|
|
40
|
+
* so it must point at the served location: `assetPrefix` replaces `basePath` for
|
|
41
|
+
* asset URLs. SSR-manifest values are base-anchored; re-anchor under any
|
|
42
|
+
* configured `assetPrefix` (default `""` keeps the legacy `"/" + file`).
|
|
39
43
|
*/
|
|
40
|
-
function resolveClientModuleUrl(manifest, moduleId) {
|
|
44
|
+
function resolveClientModuleUrl(manifest, moduleId, basePath = "", assetPrefix = "") {
|
|
41
45
|
const files = getManifestFilesForModule(resolveSsrManifest(manifest), moduleId);
|
|
42
46
|
if (!files) return void 0;
|
|
43
47
|
for (let i = 0; i < files.length; i++) {
|
|
44
|
-
|
|
48
|
+
const file = files[i];
|
|
45
49
|
if (!file || !file.endsWith(".js")) continue;
|
|
46
|
-
|
|
47
|
-
return file;
|
|
50
|
+
return assetServingUrlFromBaseAnchored(file, basePath, assetPrefix);
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
53
|
/**
|
|
@@ -67,13 +70,16 @@ function collectAssetTags(options) {
|
|
|
67
70
|
const seen = /* @__PURE__ */ new Set();
|
|
68
71
|
const nonceAttr = createNonceAttribute(options.scriptNonce);
|
|
69
72
|
const deferAttr = options.disableOptimizedLoading ? "" : " defer";
|
|
73
|
+
const basePath = options.basePath ?? "";
|
|
74
|
+
const assetPrefix = options.assetPrefix ?? "";
|
|
75
|
+
const href = (value) => assetServingUrlFromBaseAnchored(value, basePath, assetPrefix);
|
|
70
76
|
const lazyChunks = typeof globalThis !== "undefined" && globalThis.__VINEXT_LAZY_CHUNKS__ || null;
|
|
71
77
|
const lazySet = lazyChunks && lazyChunks.length > 0 ? new Set(lazyChunks) : null;
|
|
72
78
|
if (typeof globalThis !== "undefined" && globalThis.__VINEXT_CLIENT_ENTRY__) {
|
|
73
79
|
const entry = globalThis.__VINEXT_CLIENT_ENTRY__;
|
|
74
80
|
seen.add(entry);
|
|
75
|
-
tags.push("<link rel=\"modulepreload\"" + nonceAttr + " href=\"
|
|
76
|
-
tags.push("<script type=\"module\"" + deferAttr + nonceAttr + " src=\"
|
|
81
|
+
tags.push("<link rel=\"modulepreload\"" + nonceAttr + " href=\"" + href(entry) + "\" />");
|
|
82
|
+
tags.push("<script type=\"module\"" + deferAttr + nonceAttr + " src=\"" + href(entry) + "\" crossorigin><\/script>");
|
|
77
83
|
}
|
|
78
84
|
if (m) {
|
|
79
85
|
const allFiles = [];
|
|
@@ -102,11 +108,11 @@ function collectAssetTags(options) {
|
|
|
102
108
|
if (tf.charAt(0) === "/") tf = tf.slice(1);
|
|
103
109
|
if (seen.has(tf)) continue;
|
|
104
110
|
seen.add(tf);
|
|
105
|
-
if (tf.endsWith(".css")) tags.push("<link rel=\"stylesheet\"" + nonceAttr + " href=\"
|
|
111
|
+
if (tf.endsWith(".css")) tags.push("<link rel=\"stylesheet\"" + nonceAttr + " href=\"" + href(tf) + "\" />");
|
|
106
112
|
else if (tf.endsWith(".js")) {
|
|
107
113
|
if (lazySet && lazySet.has(tf)) continue;
|
|
108
|
-
tags.push("<link rel=\"modulepreload\"" + nonceAttr + " href=\"
|
|
109
|
-
tags.push("<script type=\"module\"" + deferAttr + nonceAttr + " src=\"
|
|
114
|
+
tags.push("<link rel=\"modulepreload\"" + nonceAttr + " href=\"" + href(tf) + "\" />");
|
|
115
|
+
tags.push("<script type=\"module\"" + deferAttr + nonceAttr + " src=\"" + href(tf) + "\" crossorigin><\/script>");
|
|
110
116
|
}
|
|
111
117
|
}
|
|
112
118
|
}
|
|
@@ -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.
|
|
@@ -87,9 +88,12 @@ function buildNextDataJsonResponse(pageProps, safeJsonStringify, init) {
|
|
|
87
88
|
* before checking the status code.
|
|
88
89
|
*/
|
|
89
90
|
function buildNextDataNotFoundResponse() {
|
|
91
|
+
const headers = { "Content-Type": "application/json" };
|
|
92
|
+
const deploymentId = process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID;
|
|
93
|
+
if (deploymentId) headers[NEXTJS_DEPLOYMENT_ID_HEADER] = deploymentId;
|
|
90
94
|
return new Response("{}", {
|
|
91
95
|
status: 404,
|
|
92
|
-
headers
|
|
96
|
+
headers
|
|
93
97
|
});
|
|
94
98
|
}
|
|
95
99
|
/**
|
|
@@ -1,38 +1,32 @@
|
|
|
1
1
|
import { PagesBodyParseError } from "./pages-media-type.js";
|
|
2
|
+
import { RevalidateOptions } from "./pages-revalidate.js";
|
|
3
|
+
import { Readable, Writable } from "node:stream";
|
|
2
4
|
|
|
3
5
|
//#region src/server/pages-node-compat.d.ts
|
|
4
6
|
type PagesRequestQuery = Record<string, string | string[]>;
|
|
5
|
-
type PagesReqResRequest = {
|
|
7
|
+
type PagesReqResRequest = Readable & {
|
|
6
8
|
method: string;
|
|
7
9
|
url: string;
|
|
8
10
|
headers: Record<string, string>;
|
|
9
11
|
query: PagesRequestQuery;
|
|
10
12
|
body: unknown;
|
|
11
13
|
cookies: Record<string, string>;
|
|
12
|
-
/**
|
|
13
|
-
* Async-iterator hook so handlers can `for await (const chunk of req)` —
|
|
14
|
-
* matching Node's `IncomingMessage` contract. Critical for the
|
|
15
|
-
* `bodyParser: false` opt-out (webhook signature verification etc.) where
|
|
16
|
-
* `req.body` is left undefined and user code is expected to drain the raw
|
|
17
|
-
* stream off `req` itself.
|
|
18
|
-
*/
|
|
19
|
-
[Symbol.asyncIterator]: () => AsyncIterator<Uint8Array>;
|
|
20
14
|
};
|
|
21
15
|
type PagesReqResHeaders = {
|
|
22
16
|
[key: string]: string | number | boolean | string[];
|
|
23
17
|
};
|
|
24
|
-
type PagesReqResResponse = {
|
|
18
|
+
type PagesReqResResponse = Writable & {
|
|
25
19
|
statusCode: number;
|
|
26
20
|
readonly headersSent: boolean;
|
|
27
21
|
writeHead: (code: number, headers?: PagesReqResHeaders) => PagesReqResResponse;
|
|
28
22
|
setHeader: (name: string, value: string | number | boolean | string[]) => PagesReqResResponse;
|
|
29
23
|
getHeader: (name: string) => string | number | boolean | string[] | undefined;
|
|
30
|
-
end: (data?: BodyInit | null) => void;
|
|
31
24
|
status: (code: number) => PagesReqResResponse;
|
|
32
25
|
json: (data: unknown) => void;
|
|
33
26
|
send: (data: unknown) => void;
|
|
34
27
|
redirect: (statusOrUrl: number | string, url?: string) => void;
|
|
35
28
|
getHeaders: () => PagesReqResHeaders;
|
|
29
|
+
revalidate: (urlPath: string, opts?: RevalidateOptions) => Promise<void>;
|
|
36
30
|
};
|
|
37
31
|
type CreatePagesReqResOptions = {
|
|
38
32
|
body: unknown;
|
|
@@ -2,7 +2,9 @@ import { parseCookies } from "../config/config-matchers.js";
|
|
|
2
2
|
import { readStreamAsTextWithLimit } from "../utils/text-stream.js";
|
|
3
3
|
import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-media-type.js";
|
|
4
4
|
import { DEFAULT_PAGES_API_BODY_SIZE_LIMIT } from "./pages-body-parser-config.js";
|
|
5
|
+
import { performOnDemandRevalidate } from "./pages-revalidate.js";
|
|
5
6
|
import { decode } from "node:querystring";
|
|
7
|
+
import { Readable, Writable } from "node:stream";
|
|
6
8
|
//#region src/server/pages-node-compat.ts
|
|
7
9
|
const MAX_PAGES_API_BODY_SIZE = DEFAULT_PAGES_API_BODY_SIZE_LIMIT;
|
|
8
10
|
async function readPagesRequestBodyWithLimit(request, maxBytes) {
|
|
@@ -40,137 +42,192 @@ async function parsePagesApiBody(request, maxBytes = MAX_PAGES_API_BODY_SIZE) {
|
|
|
40
42
|
if (mediaType === "application/x-www-form-urlencoded") return decode(rawBody);
|
|
41
43
|
return rawBody;
|
|
42
44
|
}
|
|
45
|
+
async function* requestBodyChunks(request) {
|
|
46
|
+
if (!request.body || request.bodyUsed) return;
|
|
47
|
+
const reader = request.body.getReader();
|
|
48
|
+
try {
|
|
49
|
+
for (;;) {
|
|
50
|
+
const { value, done } = await reader.read();
|
|
51
|
+
if (done) return;
|
|
52
|
+
yield Buffer.from(value.buffer, value.byteOffset, value.byteLength);
|
|
53
|
+
}
|
|
54
|
+
} finally {
|
|
55
|
+
try {
|
|
56
|
+
await reader.cancel();
|
|
57
|
+
} catch {}
|
|
58
|
+
reader.releaseLock();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function createRequestReadable(request) {
|
|
62
|
+
return Readable.from(requestBodyChunks(request), { objectMode: false });
|
|
63
|
+
}
|
|
64
|
+
var PagesResponseStream = class extends Writable {
|
|
65
|
+
resolveResponse;
|
|
66
|
+
rejectResponse;
|
|
67
|
+
requestHeaders;
|
|
68
|
+
resStatusCode = 200;
|
|
69
|
+
resHeaders = {};
|
|
70
|
+
setCookieHeaders = [];
|
|
71
|
+
resolved = false;
|
|
72
|
+
controller = null;
|
|
73
|
+
bufferedChunks = [];
|
|
74
|
+
streamEnded = false;
|
|
75
|
+
constructor(resolveResponse, rejectResponse, requestHeaders) {
|
|
76
|
+
super();
|
|
77
|
+
this.resolveResponse = resolveResponse;
|
|
78
|
+
this.rejectResponse = rejectResponse;
|
|
79
|
+
this.requestHeaders = requestHeaders;
|
|
80
|
+
this.once("error", (err) => {
|
|
81
|
+
if (!this.resolved) {
|
|
82
|
+
this.resolved = true;
|
|
83
|
+
this.rejectResponse(err);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
get statusCode() {
|
|
88
|
+
return this.resStatusCode;
|
|
89
|
+
}
|
|
90
|
+
set statusCode(code) {
|
|
91
|
+
this.resStatusCode = code;
|
|
92
|
+
}
|
|
93
|
+
get headersSent() {
|
|
94
|
+
return this.writableEnded || this.resolved;
|
|
95
|
+
}
|
|
96
|
+
writeHead(code, headers) {
|
|
97
|
+
this.resStatusCode = code;
|
|
98
|
+
if (headers) for (const [key, value] of Object.entries(headers)) this.setHeaderValue(key, value, { replaceSetCookie: false });
|
|
99
|
+
return this;
|
|
100
|
+
}
|
|
101
|
+
setHeader(name, value) {
|
|
102
|
+
this.setHeaderValue(name, value, { replaceSetCookie: true });
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
getHeader(name) {
|
|
106
|
+
if (name.toLowerCase() === "set-cookie") return this.setCookieHeaders.length > 0 ? this.setCookieHeaders : void 0;
|
|
107
|
+
return this.resHeaders[name.toLowerCase()];
|
|
108
|
+
}
|
|
109
|
+
status(code) {
|
|
110
|
+
this.resStatusCode = code;
|
|
111
|
+
return this;
|
|
112
|
+
}
|
|
113
|
+
json(data) {
|
|
114
|
+
this.resHeaders["content-type"] = "application/json";
|
|
115
|
+
this.end(JSON.stringify(data));
|
|
116
|
+
}
|
|
117
|
+
send(data) {
|
|
118
|
+
if (Buffer.isBuffer(data)) {
|
|
119
|
+
if (!this.resHeaders["content-type"]) this.resHeaders["content-type"] = "application/octet-stream";
|
|
120
|
+
this.resHeaders["content-length"] = String(data.length);
|
|
121
|
+
this.end(data);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (typeof data === "object" && data !== null) {
|
|
125
|
+
this.resHeaders["content-type"] = "application/json";
|
|
126
|
+
this.end(JSON.stringify(data));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (!this.resHeaders["content-type"]) this.resHeaders["content-type"] = "text/plain";
|
|
130
|
+
this.end(String(data));
|
|
131
|
+
}
|
|
132
|
+
redirect(statusOrUrl, url) {
|
|
133
|
+
if (typeof statusOrUrl === "string") this.writeHead(307, { Location: statusOrUrl });
|
|
134
|
+
else this.writeHead(statusOrUrl, { Location: url ?? "" });
|
|
135
|
+
this.end();
|
|
136
|
+
}
|
|
137
|
+
getHeaders() {
|
|
138
|
+
const headers = { ...this.resHeaders };
|
|
139
|
+
if (this.setCookieHeaders.length > 0) headers["set-cookie"] = this.setCookieHeaders;
|
|
140
|
+
return headers;
|
|
141
|
+
}
|
|
142
|
+
async revalidate(urlPath, opts) {
|
|
143
|
+
await performOnDemandRevalidate(this.requestHeaders, urlPath, opts);
|
|
144
|
+
}
|
|
145
|
+
_write(chunk, encoding, callback) {
|
|
146
|
+
const buffer = typeof chunk === "string" ? Buffer.from(chunk, encoding) : Buffer.from(chunk);
|
|
147
|
+
if (this.controller && !this.streamEnded) try {
|
|
148
|
+
this.controller.enqueue(buffer);
|
|
149
|
+
} catch {}
|
|
150
|
+
else this.bufferedChunks.push(buffer);
|
|
151
|
+
this.resolveOnce();
|
|
152
|
+
callback();
|
|
153
|
+
}
|
|
154
|
+
_final(callback) {
|
|
155
|
+
this.streamEnded = true;
|
|
156
|
+
if (this.controller) try {
|
|
157
|
+
this.controller.close();
|
|
158
|
+
} catch {}
|
|
159
|
+
this.resolveOnce();
|
|
160
|
+
callback();
|
|
161
|
+
}
|
|
162
|
+
_destroy(error, callback) {
|
|
163
|
+
this.streamEnded = true;
|
|
164
|
+
if (!this.resolved) if (error) {
|
|
165
|
+
this.resolved = true;
|
|
166
|
+
this.rejectResponse(error);
|
|
167
|
+
} else this.resolveOnce();
|
|
168
|
+
if (this.controller) try {
|
|
169
|
+
if (error) this.controller.error(error);
|
|
170
|
+
else this.controller.close();
|
|
171
|
+
} catch {}
|
|
172
|
+
callback(error);
|
|
173
|
+
}
|
|
174
|
+
setHeaderValue(name, value, options) {
|
|
175
|
+
if (name.toLowerCase() === "set-cookie") {
|
|
176
|
+
if (options.replaceSetCookie) this.setCookieHeaders.length = 0;
|
|
177
|
+
if (Array.isArray(value)) this.setCookieHeaders.push(...value.map(String));
|
|
178
|
+
else this.setCookieHeaders.push(String(value));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
this.resHeaders[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : value;
|
|
182
|
+
}
|
|
183
|
+
resolveOnce() {
|
|
184
|
+
if (this.resolved) return;
|
|
185
|
+
this.resolved = true;
|
|
186
|
+
const headers = new Headers();
|
|
187
|
+
for (const [key, value] of Object.entries(this.resHeaders)) headers.set(key, String(value));
|
|
188
|
+
for (const cookie of this.setCookieHeaders) headers.append("set-cookie", cookie);
|
|
189
|
+
const stream = new ReadableStream({
|
|
190
|
+
start: (controller) => {
|
|
191
|
+
this.controller = controller;
|
|
192
|
+
for (const buffer of this.bufferedChunks) try {
|
|
193
|
+
controller.enqueue(buffer);
|
|
194
|
+
} catch {}
|
|
195
|
+
this.bufferedChunks.length = 0;
|
|
196
|
+
if (this.streamEnded) try {
|
|
197
|
+
controller.close();
|
|
198
|
+
} catch {}
|
|
199
|
+
},
|
|
200
|
+
cancel: (reason) => {
|
|
201
|
+
this.bufferedChunks.length = 0;
|
|
202
|
+
this.destroy(reason instanceof Error ? reason : /* @__PURE__ */ new Error("Response body cancelled"));
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
this.resolveResponse(new Response(stream, {
|
|
206
|
+
status: this.resStatusCode,
|
|
207
|
+
headers
|
|
208
|
+
}));
|
|
209
|
+
}
|
|
210
|
+
};
|
|
43
211
|
function createPagesReqRes(options) {
|
|
44
212
|
const headersObj = {};
|
|
45
213
|
for (const [key, value] of options.request.headers) headersObj[key.toLowerCase()] = value;
|
|
46
|
-
const
|
|
47
|
-
const reqAsyncIterator = () => {
|
|
48
|
-
if (!requestBody) return { next() {
|
|
49
|
-
return Promise.resolve({
|
|
50
|
-
value: void 0,
|
|
51
|
-
done: true
|
|
52
|
-
});
|
|
53
|
-
} };
|
|
54
|
-
const reader = requestBody.getReader();
|
|
55
|
-
return {
|
|
56
|
-
async next() {
|
|
57
|
-
const { value, done } = await reader.read();
|
|
58
|
-
if (done) return {
|
|
59
|
-
value: void 0,
|
|
60
|
-
done: true
|
|
61
|
-
};
|
|
62
|
-
return {
|
|
63
|
-
value,
|
|
64
|
-
done: false
|
|
65
|
-
};
|
|
66
|
-
},
|
|
67
|
-
async return() {
|
|
68
|
-
try {
|
|
69
|
-
await reader.cancel();
|
|
70
|
-
} catch {}
|
|
71
|
-
return {
|
|
72
|
-
value: void 0,
|
|
73
|
-
done: true
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
};
|
|
78
|
-
const req = {
|
|
214
|
+
const req = Object.assign(createRequestReadable(options.request), {
|
|
79
215
|
method: options.request.method,
|
|
80
216
|
url: options.url,
|
|
81
217
|
headers: headersObj,
|
|
82
218
|
query: options.query,
|
|
83
219
|
body: options.body,
|
|
84
|
-
cookies: parseCookies(options.request.headers.get("cookie"))
|
|
85
|
-
|
|
86
|
-
};
|
|
87
|
-
let resStatusCode = 200;
|
|
88
|
-
const resHeaders = {};
|
|
89
|
-
const setCookieHeaders = [];
|
|
90
|
-
let resBody = null;
|
|
91
|
-
let ended = false;
|
|
220
|
+
cookies: parseCookies(options.request.headers.get("cookie"))
|
|
221
|
+
});
|
|
92
222
|
let resolveResponse;
|
|
93
|
-
|
|
223
|
+
let rejectResponse;
|
|
224
|
+
const responsePromise = new Promise((resolve, reject) => {
|
|
94
225
|
resolveResponse = resolve;
|
|
226
|
+
rejectResponse = reject;
|
|
95
227
|
});
|
|
96
|
-
const res = {
|
|
97
|
-
get statusCode() {
|
|
98
|
-
return resStatusCode;
|
|
99
|
-
},
|
|
100
|
-
set statusCode(code) {
|
|
101
|
-
resStatusCode = code;
|
|
102
|
-
},
|
|
103
|
-
get headersSent() {
|
|
104
|
-
return ended;
|
|
105
|
-
},
|
|
106
|
-
writeHead(code, headers) {
|
|
107
|
-
resStatusCode = code;
|
|
108
|
-
if (headers) for (const [key, value] of Object.entries(headers)) if (key.toLowerCase() === "set-cookie") if (Array.isArray(value)) setCookieHeaders.push(...value.map(String));
|
|
109
|
-
else setCookieHeaders.push(String(value));
|
|
110
|
-
else resHeaders[key.toLowerCase()] = Array.isArray(value) ? value.join(", ") : value;
|
|
111
|
-
return res;
|
|
112
|
-
},
|
|
113
|
-
setHeader(name, value) {
|
|
114
|
-
if (name.toLowerCase() === "set-cookie") {
|
|
115
|
-
setCookieHeaders.length = 0;
|
|
116
|
-
if (Array.isArray(value)) setCookieHeaders.push(...value.map(String));
|
|
117
|
-
else setCookieHeaders.push(String(value));
|
|
118
|
-
} else resHeaders[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : value;
|
|
119
|
-
return res;
|
|
120
|
-
},
|
|
121
|
-
getHeader(name) {
|
|
122
|
-
if (name.toLowerCase() === "set-cookie") return setCookieHeaders.length > 0 ? setCookieHeaders : void 0;
|
|
123
|
-
return resHeaders[name.toLowerCase()];
|
|
124
|
-
},
|
|
125
|
-
end(data) {
|
|
126
|
-
if (ended) return;
|
|
127
|
-
ended = true;
|
|
128
|
-
if (data !== void 0 && data !== null) resBody = data;
|
|
129
|
-
const headers = new Headers();
|
|
130
|
-
for (const [key, value] of Object.entries(resHeaders)) headers.set(key, String(value));
|
|
131
|
-
for (const cookie of setCookieHeaders) headers.append("set-cookie", cookie);
|
|
132
|
-
resolveResponse(new Response(resBody, {
|
|
133
|
-
status: resStatusCode,
|
|
134
|
-
headers
|
|
135
|
-
}));
|
|
136
|
-
},
|
|
137
|
-
status(code) {
|
|
138
|
-
resStatusCode = code;
|
|
139
|
-
return res;
|
|
140
|
-
},
|
|
141
|
-
json(data) {
|
|
142
|
-
resHeaders["content-type"] = "application/json";
|
|
143
|
-
res.end(JSON.stringify(data));
|
|
144
|
-
},
|
|
145
|
-
send(data) {
|
|
146
|
-
if (Buffer.isBuffer(data)) {
|
|
147
|
-
if (!resHeaders["content-type"]) resHeaders["content-type"] = "application/octet-stream";
|
|
148
|
-
resHeaders["content-length"] = String(data.length);
|
|
149
|
-
res.end(new Uint8Array(data));
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
if (typeof data === "object" && data !== null) {
|
|
153
|
-
resHeaders["content-type"] = "application/json";
|
|
154
|
-
res.end(JSON.stringify(data));
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
if (!resHeaders["content-type"]) resHeaders["content-type"] = "text/plain";
|
|
158
|
-
res.end(String(data));
|
|
159
|
-
},
|
|
160
|
-
redirect(statusOrUrl, url) {
|
|
161
|
-
if (typeof statusOrUrl === "string") res.writeHead(307, { Location: statusOrUrl });
|
|
162
|
-
else res.writeHead(statusOrUrl, { Location: url ?? "" });
|
|
163
|
-
res.end();
|
|
164
|
-
},
|
|
165
|
-
getHeaders() {
|
|
166
|
-
const headers = { ...resHeaders };
|
|
167
|
-
if (setCookieHeaders.length > 0) headers["set-cookie"] = setCookieHeaders;
|
|
168
|
-
return headers;
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
228
|
return {
|
|
172
229
|
req,
|
|
173
|
-
res,
|
|
230
|
+
res: new PagesResponseStream(resolveResponse, rejectResponse, options.request.headers),
|
|
174
231
|
responsePromise
|
|
175
232
|
};
|
|
176
233
|
}
|