vinext 0.0.40 → 0.0.42
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 +1 -2
- package/dist/build/client-build-config.d.ts +119 -0
- package/dist/build/client-build-config.js +149 -0
- package/dist/build/client-build-config.js.map +1 -0
- package/dist/build/layout-classification-types.d.ts +62 -0
- package/dist/build/layout-classification-types.js +1 -0
- package/dist/build/layout-classification.d.ts +60 -0
- package/dist/build/layout-classification.js +98 -0
- package/dist/build/layout-classification.js.map +1 -0
- package/dist/build/report.d.ts +15 -1
- package/dist/build/report.js +50 -1
- package/dist/build/report.js.map +1 -1
- package/dist/build/route-classification-manifest.d.ts +53 -0
- package/dist/build/route-classification-manifest.js +145 -0
- package/dist/build/route-classification-manifest.js.map +1 -0
- package/dist/build/run-prerender.js +1 -1
- package/dist/build/ssr-manifest.d.ts +19 -0
- package/dist/build/ssr-manifest.js +71 -0
- package/dist/build/ssr-manifest.js.map +1 -0
- package/dist/check.js +4 -4
- package/dist/check.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/client/entry.js +1 -1
- package/dist/config/config-matchers.js +1 -0
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/entries/app-rsc-entry.js +341 -114
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.js +205 -199
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/index.d.ts +1 -169
- package/dist/index.js +113 -432
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +1 -1
- package/dist/init.js +2 -2
- package/dist/init.js.map +1 -1
- package/dist/plugins/fonts.d.ts +49 -1
- package/dist/plugins/fonts.js +97 -3
- package/dist/plugins/fonts.js.map +1 -1
- package/dist/plugins/postcss.d.ts +27 -0
- package/dist/plugins/postcss.js +94 -0
- package/dist/plugins/postcss.js.map +1 -0
- package/dist/plugins/strip-server-exports.d.ts +14 -0
- package/dist/plugins/strip-server-exports.js +73 -0
- package/dist/plugins/strip-server-exports.js.map +1 -0
- package/dist/routing/app-router.d.ts +6 -4
- package/dist/routing/app-router.js +21 -22
- package/dist/routing/app-router.js.map +1 -1
- package/dist/server/app-browser-entry.js +235 -97
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-error.d.ts +8 -0
- package/dist/server/app-browser-error.js +9 -0
- package/dist/server/app-browser-error.js.map +1 -0
- package/dist/server/app-browser-state.d.ts +93 -0
- package/dist/server/app-browser-state.js +132 -0
- package/dist/server/app-browser-state.js.map +1 -0
- package/dist/server/app-elements.d.ts +92 -0
- package/dist/server/app-elements.js +122 -0
- package/dist/server/app-elements.js.map +1 -0
- package/dist/server/app-page-boundary-render.d.ts +3 -1
- package/dist/server/app-page-boundary-render.js +41 -1
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +6 -3
- package/dist/server/app-page-cache.js +14 -8
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-execution.d.ts +36 -3
- package/dist/server/app-page-execution.js +50 -10
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-probe.d.ts +10 -4
- package/dist/server/app-page-probe.js +24 -15
- package/dist/server/app-page-probe.js.map +1 -1
- package/dist/server/app-page-render.d.ts +8 -4
- package/dist/server/app-page-render.js +15 -4
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +52 -4
- package/dist/server/app-page-request.js +86 -16
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.d.ts +4 -11
- package/dist/server/app-page-response.js +7 -19
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +22 -8
- package/dist/server/app-page-route-wiring.js +219 -81
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +4 -1
- package/dist/server/app-page-stream.js +2 -1
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-render-dependency.d.ts +13 -0
- package/dist/server/app-render-dependency.js +35 -0
- package/dist/server/app-render-dependency.js.map +1 -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-execution.js.map +1 -1
- package/dist/server/app-route-handler-response.js +2 -1
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-route-handler-runtime.d.ts +1 -0
- package/dist/server/app-route-handler-runtime.js +26 -1
- package/dist/server/app-route-handler-runtime.js.map +1 -1
- package/dist/server/app-ssr-entry.d.ts +3 -1
- package/dist/server/app-ssr-entry.js +23 -19
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-stream.d.ts +1 -1
- package/dist/server/app-ssr-stream.js +4 -4
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/csp.d.ts +12 -0
- package/dist/server/csp.js +46 -0
- package/dist/server/csp.js.map +1 -0
- package/dist/server/dev-server.js +22 -18
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/html.d.ts +4 -1
- package/dist/server/html.js +11 -1
- package/dist/server/html.js.map +1 -1
- package/dist/server/middleware-response-headers.d.ts +12 -0
- package/dist/server/middleware-response-headers.js +23 -0
- package/dist/server/middleware-response-headers.js.map +1 -0
- package/dist/server/middleware.js +1 -5
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/pages-page-data.d.ts +1 -0
- package/dist/server/pages-page-data.js +2 -2
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-response.d.ts +2 -1
- package/dist/server/pages-page-response.js +16 -14
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/prod-server.d.ts +3 -3
- package/dist/server/prod-server.js +5 -4
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +15 -1
- package/dist/server/request-pipeline.js +88 -5
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/shims/cache-runtime.d.ts +1 -0
- package/dist/shims/cache-runtime.js +0 -5
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +1 -0
- package/dist/shims/cache.js +1 -8
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/client-hook-error.d.ts +14 -0
- package/dist/shims/client-hook-error.js +19 -0
- package/dist/shims/client-hook-error.js.map +1 -0
- package/dist/shims/constants.d.ts +3 -3
- package/dist/shims/constants.js +3 -3
- package/dist/shims/constants.js.map +1 -1
- package/dist/shims/document.d.ts +6 -6
- package/dist/shims/error-boundary.d.ts +4 -4
- package/dist/shims/error-boundary.js +1 -1
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/form.d.ts +3 -3
- package/dist/shims/head-state.d.ts +1 -0
- package/dist/shims/head-state.js +0 -5
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/headers.d.ts +11 -0
- package/dist/shims/headers.js +13 -10
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/i18n-state.d.ts +1 -0
- package/dist/shims/i18n-state.js +0 -4
- package/dist/shims/i18n-state.js.map +1 -1
- package/dist/shims/internal/app-router-context.d.ts +6 -6
- package/dist/shims/internal/router-context.d.ts +2 -2
- package/dist/shims/layout-segment-context.d.ts +2 -2
- package/dist/shims/link.js +19 -11
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +3 -3
- package/dist/shims/navigation-state.d.ts +2 -0
- package/dist/shims/navigation-state.js +0 -13
- package/dist/shims/navigation-state.js.map +1 -1
- package/dist/shims/navigation.d.ts +55 -8
- package/dist/shims/navigation.js +97 -23
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/navigation.react-server.d.ts +14 -0
- package/dist/shims/navigation.react-server.js +29 -0
- package/dist/shims/navigation.react-server.js.map +1 -0
- package/dist/shims/request-context.d.ts +1 -0
- package/dist/shims/request-context.js +0 -9
- package/dist/shims/request-context.js.map +1 -1
- package/dist/shims/request-state-types.d.ts +1 -1
- package/dist/shims/router-state.d.ts +1 -0
- package/dist/shims/router-state.js +0 -5
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/script-nonce-context.d.ts +12 -0
- package/dist/shims/script-nonce-context.js +17 -0
- package/dist/shims/script-nonce-context.js.map +1 -0
- package/dist/shims/script.js +41 -10
- package/dist/shims/script.js.map +1 -1
- package/dist/shims/server.js +6 -1
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/slot.d.ts +11 -7
- package/dist/shims/slot.js +28 -19
- package/dist/shims/slot.js.map +1 -1
- package/dist/shims/unified-request-context.d.ts +2 -0
- package/dist/shims/unified-request-context.js +0 -14
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/shims/url-safety.js +25 -4
- package/dist/shims/url-safety.js.map +1 -1
- package/dist/utils/mdx-scan.d.ts +10 -0
- package/dist/utils/mdx-scan.js +36 -0
- package/dist/utils/mdx-scan.js.map +1 -0
- package/dist/utils/public-routes.d.ts +5 -0
- package/dist/utils/public-routes.js +50 -0
- package/dist/utils/public-routes.js.map +1 -0
- package/package.json +9 -9
- package/dist/plugins/fix-use-server-closure-collision.d.ts +0 -29
- package/dist/plugins/fix-use-server-closure-collision.js +0 -204
- package/dist/plugins/fix-use-server-closure-collision.js.map +0 -1
package/dist/shims/script.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { escapeInlineContent } from "./head.js";
|
|
3
|
+
import { useScriptNonce } from "./script-nonce-context.js";
|
|
3
4
|
import React, { useEffect, useRef } from "react";
|
|
4
5
|
//#region src/shims/script.tsx
|
|
5
6
|
/**
|
|
@@ -15,6 +16,25 @@ import React, { useEffect, useRef } from "react";
|
|
|
15
16
|
* - "worker": sets type="text/partytown" (requires Partytown setup)
|
|
16
17
|
*/
|
|
17
18
|
const loadedScripts = /* @__PURE__ */ new Set();
|
|
19
|
+
function getClientAutoNonce() {
|
|
20
|
+
if (typeof document === "undefined") return void 0;
|
|
21
|
+
const existingNonceElement = document.querySelector("[nonce]");
|
|
22
|
+
if (!(existingNonceElement instanceof HTMLElement)) return;
|
|
23
|
+
return existingNonceElement.nonce || existingNonceElement.getAttribute("nonce") || void 0;
|
|
24
|
+
}
|
|
25
|
+
function resolveScriptNonce(explicitNonce, contextualNonce) {
|
|
26
|
+
if (typeof explicitNonce === "string" && explicitNonce.length > 0) return explicitNonce;
|
|
27
|
+
if (typeof window === "undefined") return contextualNonce;
|
|
28
|
+
return getClientAutoNonce();
|
|
29
|
+
}
|
|
30
|
+
function buildBeforeInteractiveScriptProps(options) {
|
|
31
|
+
const scriptProps = { ...options.rest };
|
|
32
|
+
if (options.src) scriptProps.src = options.src;
|
|
33
|
+
if (options.id) scriptProps.id = options.id;
|
|
34
|
+
if (options.resolvedNonce) scriptProps.nonce = options.resolvedNonce;
|
|
35
|
+
if (options.dangerouslySetInnerHTML) scriptProps.dangerouslySetInnerHTML = { __html: escapeInlineContent(options.dangerouslySetInnerHTML.__html, "script") };
|
|
36
|
+
return scriptProps;
|
|
37
|
+
}
|
|
18
38
|
/**
|
|
19
39
|
* Load a script imperatively (outside of React).
|
|
20
40
|
*/
|
|
@@ -26,11 +46,13 @@ function handleClientScriptLoad(props) {
|
|
|
26
46
|
const el = document.createElement("script");
|
|
27
47
|
if (src) el.src = src;
|
|
28
48
|
if (id) el.id = id;
|
|
49
|
+
const resolvedNonce = resolveScriptNonce(rest.nonce);
|
|
29
50
|
for (const [attr, value] of Object.entries(rest)) {
|
|
30
51
|
if (attr === "dangerouslySetInnerHTML" || attr === "className") continue;
|
|
31
52
|
if (typeof value === "string") el.setAttribute(attr, value);
|
|
32
53
|
else if (typeof value === "boolean" && value) el.setAttribute(attr, "");
|
|
33
54
|
}
|
|
55
|
+
if (resolvedNonce && !el.getAttribute("nonce")) el.setAttribute("nonce", resolvedNonce);
|
|
34
56
|
if (children && typeof children === "string") el.textContent = children;
|
|
35
57
|
if (onLoad) el.addEventListener("load", onLoad);
|
|
36
58
|
if (onError) el.addEventListener("error", onError);
|
|
@@ -47,9 +69,12 @@ function Script(props) {
|
|
|
47
69
|
const { src, id, strategy = "afterInteractive", onLoad, onReady, onError, children, dangerouslySetInnerHTML, ...rest } = props;
|
|
48
70
|
const hasMounted = useRef(false);
|
|
49
71
|
const key = id ?? src ?? "";
|
|
72
|
+
const contextualNonce = useScriptNonce();
|
|
73
|
+
const resolvedNonce = resolveScriptNonce(rest.nonce, contextualNonce);
|
|
50
74
|
useEffect(() => {
|
|
51
75
|
if (hasMounted.current) return;
|
|
52
76
|
hasMounted.current = true;
|
|
77
|
+
if (strategy === "beforeInteractive") return;
|
|
53
78
|
if (key && loadedScripts.has(key)) {
|
|
54
79
|
onReady?.();
|
|
55
80
|
return;
|
|
@@ -65,6 +90,7 @@ function Script(props) {
|
|
|
65
90
|
for (const [attr, value] of Object.entries(rest)) if (attr === "className") el.setAttribute("class", String(value));
|
|
66
91
|
else if (typeof value === "string") el.setAttribute(attr, value);
|
|
67
92
|
else if (typeof value === "boolean" && value) el.setAttribute(attr, "");
|
|
93
|
+
if (resolvedNonce && !el.getAttribute("nonce")) el.setAttribute("nonce", resolvedNonce);
|
|
68
94
|
if (strategy === "worker") el.setAttribute("type", "text/partytown");
|
|
69
95
|
if (dangerouslySetInnerHTML?.__html) el.innerHTML = dangerouslySetInnerHTML.__html;
|
|
70
96
|
else if (children && typeof children === "string") el.textContent = children;
|
|
@@ -93,21 +119,26 @@ function Script(props) {
|
|
|
93
119
|
children,
|
|
94
120
|
dangerouslySetInnerHTML,
|
|
95
121
|
key,
|
|
122
|
+
resolvedNonce,
|
|
96
123
|
rest
|
|
97
124
|
]);
|
|
98
125
|
if (typeof window === "undefined") {
|
|
99
|
-
if (strategy === "beforeInteractive") {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
return React.createElement("script", scriptProps, children);
|
|
108
|
-
}
|
|
126
|
+
if (strategy === "beforeInteractive") return React.createElement("script", buildBeforeInteractiveScriptProps({
|
|
127
|
+
src,
|
|
128
|
+
id,
|
|
129
|
+
rest,
|
|
130
|
+
resolvedNonce,
|
|
131
|
+
dangerouslySetInnerHTML
|
|
132
|
+
}), children);
|
|
109
133
|
return null;
|
|
110
134
|
}
|
|
135
|
+
if (strategy === "beforeInteractive") return React.createElement("script", buildBeforeInteractiveScriptProps({
|
|
136
|
+
src,
|
|
137
|
+
id,
|
|
138
|
+
rest,
|
|
139
|
+
resolvedNonce,
|
|
140
|
+
dangerouslySetInnerHTML
|
|
141
|
+
}), children);
|
|
111
142
|
return null;
|
|
112
143
|
}
|
|
113
144
|
//#endregion
|
package/dist/shims/script.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"script.js","names":[],"sources":["../../src/shims/script.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * next/script shim\n *\n * Provides the <Script> component for loading third-party scripts with\n * configurable loading strategies.\n *\n * Strategies:\n * - \"beforeInteractive\": rendered as a <script> tag in SSR output\n * - \"afterInteractive\" (default): loaded client-side after hydration\n * - \"lazyOnload\": deferred until window.load + requestIdleCallback\n * - \"worker\": sets type=\"text/partytown\" (requires Partytown setup)\n */\nimport React, { useEffect, useRef } from \"react\";\nimport { escapeInlineContent } from \"./head.js\";\n\nexport type ScriptProps = {\n /** Script source URL */\n src?: string;\n /** Loading strategy. Default: \"afterInteractive\" */\n strategy?: \"beforeInteractive\" | \"afterInteractive\" | \"lazyOnload\" | \"worker\";\n /** Unique identifier for the script */\n id?: string;\n /** Called when the script has loaded */\n onLoad?: (e: Event) => void;\n /** Called when the script is ready (after load, and on every re-render if already loaded) */\n onReady?: () => void;\n /** Called on script load error */\n onError?: (e: Event) => void;\n /** Inline script content */\n children?: React.ReactNode;\n /** Dangerous inner HTML */\n dangerouslySetInnerHTML?: { __html: string };\n /** Script type attribute */\n type?: string;\n /** Async attribute */\n async?: boolean;\n /** Defer attribute */\n defer?: boolean;\n /** Crossorigin attribute */\n crossOrigin?: string;\n /** Nonce for CSP */\n nonce?: string;\n /** Integrity hash */\n integrity?: string;\n /** Additional attributes */\n [key: string]: unknown;\n};\n\n// Track scripts that have already been loaded to avoid duplicates\nconst loadedScripts = new Set<string>();\n\n/**\n * Load a script imperatively (outside of React).\n */\nexport function handleClientScriptLoad(props: ScriptProps): void {\n const {\n src,\n id,\n onLoad,\n onError,\n strategy: _strategy,\n onReady: _onReady,\n children,\n ...rest\n } = props;\n if (typeof window === \"undefined\") return;\n\n const key = id ?? src ?? \"\";\n if (key && loadedScripts.has(key)) return;\n\n const el = document.createElement(\"script\");\n if (src) el.src = src;\n if (id) el.id = id;\n\n for (const [attr, value] of Object.entries(rest)) {\n if (attr === \"dangerouslySetInnerHTML\" || attr === \"className\") continue;\n if (typeof value === \"string\") {\n el.setAttribute(attr, value);\n } else if (typeof value === \"boolean\" && value) {\n el.setAttribute(attr, \"\");\n }\n }\n\n if (children && typeof children === \"string\") {\n el.textContent = children;\n }\n\n if (onLoad) el.addEventListener(\"load\", onLoad);\n if (onError) el.addEventListener(\"error\", onError);\n\n document.body.appendChild(el);\n if (key) loadedScripts.add(key);\n}\n\n/**\n * Initialize multiple scripts at once (called during app bootstrap).\n */\nexport function initScriptLoader(scripts: ScriptProps[]): void {\n for (const script of scripts) {\n handleClientScriptLoad(script);\n }\n}\n\nfunction Script(props: ScriptProps): React.ReactElement | null {\n const {\n src,\n id,\n strategy = \"afterInteractive\",\n onLoad,\n onReady,\n onError,\n children,\n dangerouslySetInnerHTML,\n ...rest\n } = props;\n\n const hasMounted = useRef(false);\n const key = id ?? src ?? \"\";\n\n // Client path: load scripts via useEffect based on strategy.\n // useEffect never runs during SSR, so it's safe to call unconditionally.\n useEffect(() => {\n if (hasMounted.current) return;\n hasMounted.current = true;\n\n // Already loaded — just fire onReady\n if (key && loadedScripts.has(key)) {\n onReady?.();\n return;\n }\n\n const load = () => {\n if (key && loadedScripts.has(key)) {\n onReady?.();\n return;\n }\n\n const el = document.createElement(\"script\");\n if (src) el.src = src;\n if (id) el.id = id;\n\n for (const [attr, value] of Object.entries(rest)) {\n if (attr === \"className\") {\n el.setAttribute(\"class\", String(value));\n } else if (typeof value === \"string\") {\n el.setAttribute(attr, value);\n } else if (typeof value === \"boolean\" && value) {\n el.setAttribute(attr, \"\");\n }\n }\n\n if (strategy === \"worker\") {\n el.setAttribute(\"type\", \"text/partytown\");\n }\n\n if (dangerouslySetInnerHTML?.__html) {\n // Intentional: mirrors the Next.js <Script> API where dangerouslySetInnerHTML\n // is developer-supplied inline script content (not user input). The prop name\n // itself signals developer awareness of the XSS risk, consistent with React's\n // design. User-supplied data must never flow into this prop.\n el.innerHTML = dangerouslySetInnerHTML.__html as string;\n } else if (children && typeof children === \"string\") {\n el.textContent = children;\n }\n\n el.addEventListener(\"load\", (e) => {\n if (key) loadedScripts.add(key);\n onLoad?.(e);\n onReady?.();\n });\n\n if (onError) {\n el.addEventListener(\"error\", onError);\n }\n\n document.body.appendChild(el);\n };\n\n if (strategy === \"lazyOnload\") {\n // Wait for window load, then use idle callback\n if (document.readyState === \"complete\") {\n if (typeof requestIdleCallback === \"function\") {\n requestIdleCallback(load);\n } else {\n setTimeout(load, 1);\n }\n } else {\n window.addEventListener(\"load\", () => {\n if (typeof requestIdleCallback === \"function\") {\n requestIdleCallback(load);\n } else {\n setTimeout(load, 1);\n }\n });\n }\n } else {\n // \"afterInteractive\" (default), \"beforeInteractive\" (client re-mount), \"worker\"\n load();\n }\n }, [src, id, strategy, onLoad, onReady, onError, children, dangerouslySetInnerHTML, key, rest]);\n\n // SSR path: only \"beforeInteractive\" renders a <script> tag server-side\n if (typeof window === \"undefined\") {\n if (strategy === \"beforeInteractive\") {\n const scriptProps: Record<string, unknown> = { ...rest };\n if (src) scriptProps.src = src;\n if (id) scriptProps.id = id;\n if (dangerouslySetInnerHTML) {\n // Escape closing </script> sequences in inline content so the HTML\n // parser doesn't prematurely terminate the element during SSR.\n const raw = dangerouslySetInnerHTML.__html;\n scriptProps.dangerouslySetInnerHTML = {\n __html: escapeInlineContent(raw, \"script\"),\n };\n }\n return React.createElement(\"script\", scriptProps, children);\n }\n // Other strategies don't render during SSR\n return null;\n }\n\n // The component itself renders nothing — scripts are injected imperatively\n return null;\n}\n\nexport default Script;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"script.js","names":[],"sources":["../../src/shims/script.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * next/script shim\n *\n * Provides the <Script> component for loading third-party scripts with\n * configurable loading strategies.\n *\n * Strategies:\n * - \"beforeInteractive\": rendered as a <script> tag in SSR output\n * - \"afterInteractive\" (default): loaded client-side after hydration\n * - \"lazyOnload\": deferred until window.load + requestIdleCallback\n * - \"worker\": sets type=\"text/partytown\" (requires Partytown setup)\n */\nimport React, { useEffect, useRef } from \"react\";\nimport { escapeInlineContent } from \"./head.js\";\nimport { useScriptNonce } from \"./script-nonce-context.js\";\n\nexport type ScriptProps = {\n /** Script source URL */\n src?: string;\n /** Loading strategy. Default: \"afterInteractive\" */\n strategy?: \"beforeInteractive\" | \"afterInteractive\" | \"lazyOnload\" | \"worker\";\n /** Unique identifier for the script */\n id?: string;\n /** Called when the script has loaded */\n onLoad?: (e: Event) => void;\n /** Called when the script is ready (after load, and on every re-render if already loaded) */\n onReady?: () => void;\n /** Called on script load error */\n onError?: (e: Event) => void;\n /** Inline script content */\n children?: React.ReactNode;\n /** Dangerous inner HTML */\n dangerouslySetInnerHTML?: { __html: string };\n /** Script type attribute */\n type?: string;\n /** Async attribute */\n async?: boolean;\n /** Defer attribute */\n defer?: boolean;\n /** Crossorigin attribute */\n crossOrigin?: string;\n /** Nonce for CSP */\n nonce?: string;\n /** Integrity hash */\n integrity?: string;\n /** Additional attributes */\n [key: string]: unknown;\n};\n\n// Track scripts that have already been loaded to avoid duplicates\nconst loadedScripts = new Set<string>();\n\nfunction getClientAutoNonce(): string | undefined {\n if (typeof document === \"undefined\") return undefined;\n\n const existingNonceElement = document.querySelector(\"[nonce]\");\n if (!(existingNonceElement instanceof HTMLElement)) {\n return undefined;\n }\n\n return existingNonceElement.nonce || existingNonceElement.getAttribute(\"nonce\") || undefined;\n}\n\nfunction resolveScriptNonce(explicitNonce: unknown, contextualNonce?: string): string | undefined {\n if (typeof explicitNonce === \"string\" && explicitNonce.length > 0) {\n return explicitNonce;\n }\n\n if (typeof window === \"undefined\") {\n return contextualNonce;\n }\n\n return getClientAutoNonce();\n}\n\nfunction buildBeforeInteractiveScriptProps(options: {\n src?: string;\n id?: string;\n rest: Record<string, unknown>;\n resolvedNonce?: string;\n dangerouslySetInnerHTML?: { __html: string };\n}): Record<string, unknown> {\n const scriptProps: Record<string, unknown> = { ...options.rest };\n if (options.src) scriptProps.src = options.src;\n if (options.id) scriptProps.id = options.id;\n if (options.resolvedNonce) {\n scriptProps.nonce = options.resolvedNonce;\n }\n if (options.dangerouslySetInnerHTML) {\n scriptProps.dangerouslySetInnerHTML = {\n __html: escapeInlineContent(options.dangerouslySetInnerHTML.__html, \"script\"),\n };\n }\n return scriptProps;\n}\n\n/**\n * Load a script imperatively (outside of React).\n */\nexport function handleClientScriptLoad(props: ScriptProps): void {\n const {\n src,\n id,\n onLoad,\n onError,\n strategy: _strategy,\n onReady: _onReady,\n children,\n ...rest\n } = props;\n if (typeof window === \"undefined\") return;\n\n const key = id ?? src ?? \"\";\n if (key && loadedScripts.has(key)) return;\n\n const el = document.createElement(\"script\");\n if (src) el.src = src;\n if (id) el.id = id;\n const resolvedNonce = resolveScriptNonce(rest.nonce);\n\n for (const [attr, value] of Object.entries(rest)) {\n if (attr === \"dangerouslySetInnerHTML\" || attr === \"className\") continue;\n if (typeof value === \"string\") {\n el.setAttribute(attr, value);\n } else if (typeof value === \"boolean\" && value) {\n el.setAttribute(attr, \"\");\n }\n }\n if (resolvedNonce && !el.getAttribute(\"nonce\")) {\n el.setAttribute(\"nonce\", resolvedNonce);\n }\n\n if (children && typeof children === \"string\") {\n el.textContent = children;\n }\n\n if (onLoad) el.addEventListener(\"load\", onLoad);\n if (onError) el.addEventListener(\"error\", onError);\n\n document.body.appendChild(el);\n if (key) loadedScripts.add(key);\n}\n\n/**\n * Initialize multiple scripts at once (called during app bootstrap).\n */\nexport function initScriptLoader(scripts: ScriptProps[]): void {\n for (const script of scripts) {\n handleClientScriptLoad(script);\n }\n}\n\nfunction Script(props: ScriptProps): React.ReactElement | null {\n const {\n src,\n id,\n strategy = \"afterInteractive\",\n onLoad,\n onReady,\n onError,\n children,\n dangerouslySetInnerHTML,\n ...rest\n } = props;\n\n const hasMounted = useRef(false);\n const key = id ?? src ?? \"\";\n const contextualNonce = useScriptNonce();\n const resolvedNonce = resolveScriptNonce(rest.nonce, contextualNonce);\n\n // Client path: load scripts via useEffect based on strategy.\n // useEffect never runs during SSR, so it's safe to call unconditionally.\n useEffect(() => {\n if (hasMounted.current) return;\n hasMounted.current = true;\n\n if (strategy === \"beforeInteractive\") {\n return;\n }\n\n // Already loaded — just fire onReady\n if (key && loadedScripts.has(key)) {\n onReady?.();\n return;\n }\n\n const load = () => {\n if (key && loadedScripts.has(key)) {\n onReady?.();\n return;\n }\n\n const el = document.createElement(\"script\");\n if (src) el.src = src;\n if (id) el.id = id;\n\n for (const [attr, value] of Object.entries(rest)) {\n if (attr === \"className\") {\n el.setAttribute(\"class\", String(value));\n } else if (typeof value === \"string\") {\n el.setAttribute(attr, value);\n } else if (typeof value === \"boolean\" && value) {\n el.setAttribute(attr, \"\");\n }\n }\n if (resolvedNonce && !el.getAttribute(\"nonce\")) {\n el.setAttribute(\"nonce\", resolvedNonce);\n }\n\n if (strategy === \"worker\") {\n el.setAttribute(\"type\", \"text/partytown\");\n }\n\n if (dangerouslySetInnerHTML?.__html) {\n // Intentional: mirrors the Next.js <Script> API where dangerouslySetInnerHTML\n // is developer-supplied inline script content (not user input). The prop name\n // itself signals developer awareness of the XSS risk, consistent with React's\n // design. User-supplied data must never flow into this prop.\n el.innerHTML = dangerouslySetInnerHTML.__html as string;\n } else if (children && typeof children === \"string\") {\n el.textContent = children;\n }\n\n el.addEventListener(\"load\", (e) => {\n if (key) loadedScripts.add(key);\n onLoad?.(e);\n onReady?.();\n });\n\n if (onError) {\n el.addEventListener(\"error\", onError);\n }\n\n document.body.appendChild(el);\n };\n\n if (strategy === \"lazyOnload\") {\n // Wait for window load, then use idle callback\n if (document.readyState === \"complete\") {\n if (typeof requestIdleCallback === \"function\") {\n requestIdleCallback(load);\n } else {\n setTimeout(load, 1);\n }\n } else {\n window.addEventListener(\"load\", () => {\n if (typeof requestIdleCallback === \"function\") {\n requestIdleCallback(load);\n } else {\n setTimeout(load, 1);\n }\n });\n }\n } else {\n // \"afterInteractive\" (default), \"beforeInteractive\" (client re-mount), \"worker\"\n load();\n }\n }, [\n src,\n id,\n strategy,\n onLoad,\n onReady,\n onError,\n children,\n dangerouslySetInnerHTML,\n key,\n resolvedNonce,\n rest,\n ]);\n\n // SSR path: only \"beforeInteractive\" renders a <script> tag server-side\n if (typeof window === \"undefined\") {\n if (strategy === \"beforeInteractive\") {\n return React.createElement(\n \"script\",\n buildBeforeInteractiveScriptProps({\n src,\n id,\n rest,\n resolvedNonce,\n dangerouslySetInnerHTML,\n }),\n children,\n );\n }\n // Other strategies don't render during SSR\n return null;\n }\n\n if (strategy === \"beforeInteractive\") {\n return React.createElement(\n \"script\",\n buildBeforeInteractiveScriptProps({\n src,\n id,\n rest,\n resolvedNonce,\n dangerouslySetInnerHTML,\n }),\n children,\n );\n }\n\n // The component itself renders nothing — scripts are injected imperatively\n return null;\n}\n\nexport default Script;\n"],"mappings":"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"}
|
package/dist/shims/server.js
CHANGED
|
@@ -347,16 +347,21 @@ var RequestCookies = class {
|
|
|
347
347
|
cookieName = nameOrOptions.name;
|
|
348
348
|
cookieValue = nameOrOptions.value;
|
|
349
349
|
}
|
|
350
|
+
validateCookieName(cookieName);
|
|
350
351
|
this._parsed.set(cookieName, cookieValue);
|
|
351
352
|
this._syncHeader();
|
|
352
353
|
return this;
|
|
353
354
|
}
|
|
354
355
|
delete(names) {
|
|
355
356
|
if (Array.isArray(names)) {
|
|
356
|
-
const results = names.map((name) =>
|
|
357
|
+
const results = names.map((name) => {
|
|
358
|
+
validateCookieName(name);
|
|
359
|
+
return this._parsed.delete(name);
|
|
360
|
+
});
|
|
357
361
|
this._syncHeader();
|
|
358
362
|
return results;
|
|
359
363
|
}
|
|
364
|
+
validateCookieName(names);
|
|
360
365
|
const result = this._parsed.delete(names);
|
|
361
366
|
this._syncHeader();
|
|
362
367
|
return result;
|
package/dist/shims/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":[],"sources":["../../src/shims/server.ts"],"sourcesContent":["/**\n * next/server shim\n *\n * Provides NextRequest, NextResponse, and related types that work with\n * standard Web APIs (Request/Response). This means they work on Node,\n * Cloudflare Workers, Deno, and any WinterCG-compatible runtime.\n *\n * This is a pragmatic subset — we implement the most commonly used APIs\n * rather than bug-for-bug parity with Next.js internals.\n */\n\nimport { encodeMiddlewareRequestHeaders } from \"../server/middleware-request-headers.js\";\nimport { parseCookieHeader } from \"./internal/parse-cookie-header.js\";\nimport { getRequestExecutionContext } from \"./request-context.js\";\n\n// ---------------------------------------------------------------------------\n// Inlined cache-scope guard for after()\n//\n// We cannot statically import throwIfInsideCacheScope from headers.ts here\n// because headers.ts contains the \"use cache\" directive string in its error\n// message, which causes Vite's use-cache transform to include it in the module\n// graph. If headers.ts is pulled in via static import from server.ts, the\n// transform fires on it in Pages Router fixtures that lack @vitejs/plugin-rsc.\n//\n// The connection() function in this file avoids the same problem by using\n// `await import(\"./headers.js\")` (dynamic import, async function). after()\n// must remain synchronous, so we inline the check using the same Symbol.for\n// keys that cache-runtime.ts and cache.ts register their ALS instances with.\n// ---------------------------------------------------------------------------\n\nconst _USE_CACHE_ALS_KEY = Symbol.for(\"vinext.cacheRuntime.contextAls\");\nconst _UNSTABLE_CACHE_ALS_KEY = Symbol.for(\"vinext.unstableCache.als\");\nconst _g = globalThis as unknown as Record<PropertyKey, unknown>;\n\nfunction _throwIfInsideCacheScope(apiName: string): void {\n const cacheAls = _g[_USE_CACHE_ALS_KEY] as { getStore(): unknown } | undefined;\n if (cacheAls?.getStore() != null) {\n throw new Error(\n `\\`${apiName}\\` cannot be called inside \"use cache\". ` +\n `If you need this data inside a cached function, call \\`${apiName}\\` ` +\n \"outside and pass the required data as an argument.\",\n );\n }\n const unstableAls = _g[_UNSTABLE_CACHE_ALS_KEY] as { getStore(): unknown } | undefined;\n if (unstableAls?.getStore() === true) {\n throw new Error(\n `\\`${apiName}\\` cannot be called inside a function cached with \\`unstable_cache()\\`. ` +\n `If you need this data inside a cached function, call \\`${apiName}\\` ` +\n \"outside and pass the required data as an argument.\",\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// NextRequest\n// ---------------------------------------------------------------------------\n\nexport class NextRequest extends Request {\n private _nextUrl: NextURL;\n private _cookies: RequestCookies;\n\n constructor(\n input: URL | RequestInfo,\n init?: RequestInit & {\n nextConfig?: {\n basePath?: string;\n i18n?: { locales: string[]; defaultLocale: string };\n };\n },\n ) {\n // Strip nextConfig before passing to super() — it's vinext-internal,\n // not a valid RequestInit property.\n const { nextConfig: _nextConfig, ...requestInit } = init ?? {};\n // Handle the case where input is a Request object - we need to extract URL and init\n // to avoid Node.js undici issues with passing Request objects directly to super()\n if (input instanceof Request) {\n const req = input;\n super(req.url, {\n method: req.method,\n headers: req.headers,\n body: req.body,\n // @ts-expect-error - duplex is not in RequestInit type but needed for streams\n duplex: req.body ? \"half\" : undefined,\n ...requestInit,\n });\n } else {\n super(input, requestInit);\n }\n const url =\n typeof input === \"string\"\n ? new URL(input, \"http://localhost\")\n : input instanceof URL\n ? input\n : new URL(input.url, \"http://localhost\");\n const urlConfig: NextURLConfig | undefined = _nextConfig\n ? { basePath: _nextConfig.basePath, nextConfig: { i18n: _nextConfig.i18n } }\n : undefined;\n this._nextUrl = new NextURL(url, undefined, urlConfig);\n this._cookies = new RequestCookies(this.headers);\n }\n\n get nextUrl(): NextURL {\n return this._nextUrl;\n }\n\n get cookies(): RequestCookies {\n return this._cookies;\n }\n\n /**\n * Client IP address. Prefers Cloudflare's trusted CF-Connecting-IP header\n * over the spoofable X-Forwarded-For. Returns undefined if unavailable.\n */\n get ip(): string | undefined {\n return (\n this.headers.get(\"cf-connecting-ip\") ??\n this.headers.get(\"x-real-ip\") ??\n this.headers.get(\"x-forwarded-for\")?.split(\",\")[0]?.trim() ??\n undefined\n );\n }\n\n /**\n * Geolocation data. Platform-dependent (e.g., Cloudflare, Vercel).\n * Returns undefined if not available.\n */\n get geo():\n | { city?: string; country?: string; region?: string; latitude?: string; longitude?: string }\n | undefined {\n // Check Cloudflare-style headers, Vercel-style headers\n const country =\n this.headers.get(\"cf-ipcountry\") ?? this.headers.get(\"x-vercel-ip-country\") ?? undefined;\n if (!country) return undefined;\n return {\n country,\n city: this.headers.get(\"cf-ipcity\") ?? this.headers.get(\"x-vercel-ip-city\") ?? undefined,\n region:\n this.headers.get(\"cf-region\") ??\n this.headers.get(\"x-vercel-ip-country-region\") ??\n undefined,\n latitude:\n this.headers.get(\"cf-iplatitude\") ?? this.headers.get(\"x-vercel-ip-latitude\") ?? undefined,\n longitude:\n this.headers.get(\"cf-iplongitude\") ??\n this.headers.get(\"x-vercel-ip-longitude\") ??\n undefined,\n };\n }\n\n /**\n * The build ID of the Next.js application.\n * Delegates to `nextUrl.buildId` to match Next.js API surface.\n * Can be used in middleware to detect deployment skew between client and server.\n */\n get buildId(): string | undefined {\n return this._nextUrl.buildId;\n }\n}\n\n// ---------------------------------------------------------------------------\n// NextResponse\n// ---------------------------------------------------------------------------\n\n/** Valid HTTP redirect status codes, matching Next.js's REDIRECTS set. */\nconst REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);\n\nexport class NextResponse<_Body = unknown> extends Response {\n private _cookies: ResponseCookies;\n\n constructor(body?: BodyInit | null, init?: ResponseInit) {\n super(body, init);\n this._cookies = new ResponseCookies(this.headers);\n }\n\n get cookies(): ResponseCookies {\n return this._cookies;\n }\n\n /**\n * Create a JSON response.\n */\n static json<JsonBody>(body: JsonBody, init?: ResponseInit): NextResponse<JsonBody> {\n const headers = new Headers(init?.headers);\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n return new NextResponse(JSON.stringify(body), {\n ...init,\n headers,\n }) as NextResponse<JsonBody>;\n }\n\n /**\n * Create a redirect response.\n */\n static redirect(url: string | URL, init?: number | ResponseInit): NextResponse {\n const status = typeof init === \"number\" ? init : (init?.status ?? 307);\n if (!REDIRECT_STATUSES.has(status)) {\n throw new RangeError(`Failed to execute \"redirect\" on \"response\": Invalid status code`);\n }\n const destination = typeof url === \"string\" ? url : url.toString();\n const headers = new Headers(typeof init === \"object\" ? init?.headers : undefined);\n headers.set(\"Location\", destination);\n return new NextResponse(null, { status, headers });\n }\n\n /**\n * Create a rewrite response (middleware pattern).\n * Sets the x-middleware-rewrite header.\n */\n static rewrite(destination: string | URL, init?: MiddlewareResponseInit): NextResponse {\n const url = typeof destination === \"string\" ? destination : destination.toString();\n const headers = new Headers(init?.headers);\n headers.set(\"x-middleware-rewrite\", url);\n if (init?.request?.headers) {\n encodeMiddlewareRequestHeaders(headers, init.request.headers);\n }\n return new NextResponse(null, { ...init, headers });\n }\n\n /**\n * Continue to the next handler (middleware pattern).\n * Sets the x-middleware-next header.\n */\n static next(init?: MiddlewareResponseInit): NextResponse {\n const headers = new Headers(init?.headers);\n headers.set(\"x-middleware-next\", \"1\");\n if (init?.request?.headers) {\n encodeMiddlewareRequestHeaders(headers, init.request.headers);\n }\n return new NextResponse(null, { ...init, headers });\n }\n}\n\n// ---------------------------------------------------------------------------\n// NextURL — lightweight URL wrapper with pathname helpers\n// ---------------------------------------------------------------------------\n\nexport type NextURLConfig = {\n basePath?: string;\n nextConfig?: {\n i18n?: {\n locales: string[];\n defaultLocale: string;\n };\n };\n};\n\nexport class NextURL {\n /** Internal URL stores the pathname WITHOUT basePath or locale prefix. */\n private _url: URL;\n private _basePath: string;\n private _locale: string | undefined;\n private _defaultLocale: string | undefined;\n private _locales: string[] | undefined;\n\n constructor(input: string | URL, base?: string | URL, config?: NextURLConfig) {\n this._url = new URL(input.toString(), base);\n this._basePath = config?.basePath ?? \"\";\n this._stripBasePath();\n const i18n = config?.nextConfig?.i18n;\n if (i18n) {\n this._locales = [...i18n.locales];\n this._defaultLocale = i18n.defaultLocale;\n this._analyzeLocale(this._locales);\n }\n }\n\n /** Strip basePath prefix from the internal pathname. */\n private _stripBasePath(): void {\n if (!this._basePath) return;\n const { pathname } = this._url;\n if (pathname === this._basePath || pathname.startsWith(this._basePath + \"/\")) {\n this._url.pathname = pathname.slice(this._basePath.length) || \"/\";\n }\n }\n\n /** Extract locale from pathname, stripping it from the internal URL. */\n private _analyzeLocale(locales: string[]): void {\n const segments = this._url.pathname.split(\"/\");\n const candidate = segments[1]?.toLowerCase();\n const match = locales.find((l) => l.toLowerCase() === candidate);\n if (match) {\n this._locale = match;\n this._url.pathname = \"/\" + segments.slice(2).join(\"/\");\n } else {\n this._locale = this._defaultLocale;\n }\n }\n\n /**\n * Reconstruct the full pathname with basePath + locale prefix.\n * Mirrors Next.js's internal formatPathname().\n */\n private _formatPathname(): string {\n // Build prefix: basePath + locale (skip defaultLocale — Next.js omits it)\n let prefix = this._basePath;\n if (this._locale && this._locale !== this._defaultLocale) {\n prefix += \"/\" + this._locale;\n }\n if (!prefix) return this._url.pathname;\n const inner = this._url.pathname;\n return inner === \"/\" ? prefix : prefix + inner;\n }\n\n get href(): string {\n const formatted = this._formatPathname();\n if (formatted === this._url.pathname) return this._url.href;\n // Replace pathname in href via string slicing — avoids URL allocation.\n // URL.href is always <origin+auth><pathname><search><hash>.\n const { href, pathname, search, hash } = this._url;\n const baseEnd = href.length - pathname.length - search.length - hash.length;\n return href.slice(0, baseEnd) + formatted + search + hash;\n }\n set href(value: string) {\n this._url.href = value;\n this._stripBasePath();\n if (this._locales) this._analyzeLocale(this._locales);\n }\n\n get origin(): string {\n return this._url.origin;\n }\n\n get protocol(): string {\n return this._url.protocol;\n }\n set protocol(value: string) {\n this._url.protocol = value;\n }\n\n get username(): string {\n return this._url.username;\n }\n set username(value: string) {\n this._url.username = value;\n }\n\n get password(): string {\n return this._url.password;\n }\n set password(value: string) {\n this._url.password = value;\n }\n\n get host(): string {\n return this._url.host;\n }\n set host(value: string) {\n this._url.host = value;\n }\n\n get hostname(): string {\n return this._url.hostname;\n }\n set hostname(value: string) {\n this._url.hostname = value;\n }\n\n get port(): string {\n return this._url.port;\n }\n set port(value: string) {\n this._url.port = value;\n }\n\n /** Returns the pathname WITHOUT basePath or locale prefix. */\n get pathname(): string {\n return this._url.pathname;\n }\n set pathname(value: string) {\n this._url.pathname = value;\n }\n\n get search(): string {\n return this._url.search;\n }\n set search(value: string) {\n this._url.search = value;\n }\n\n get searchParams(): URLSearchParams {\n return this._url.searchParams;\n }\n\n get hash(): string {\n return this._url.hash;\n }\n set hash(value: string) {\n this._url.hash = value;\n }\n\n get basePath(): string {\n return this._basePath;\n }\n set basePath(value: string) {\n this._basePath = value === \"\" ? \"\" : value.startsWith(\"/\") ? value : \"/\" + value;\n }\n\n get locale(): string {\n return this._locale ?? \"\";\n }\n set locale(value: string | undefined) {\n if (this._locales) {\n if (!value) {\n this._locale = this._defaultLocale;\n return;\n }\n if (!this._locales.includes(value)) {\n throw new TypeError(\n `The locale \"${value}\" is not in the configured locales: ${this._locales.join(\", \")}`,\n );\n }\n }\n this._locale = this._locales ? value : this._locale;\n }\n\n get defaultLocale(): string | undefined {\n return this._defaultLocale;\n }\n\n get locales(): string[] | undefined {\n return this._locales ? [...this._locales] : undefined;\n }\n\n clone(): NextURL {\n const config: NextURLConfig = {\n basePath: this._basePath,\n nextConfig: this._locales\n ? { i18n: { locales: [...this._locales], defaultLocale: this._defaultLocale! } }\n : undefined,\n };\n // Pass the full href (with locale/basePath re-added) so the constructor\n // can re-analyze and extract locale correctly.\n return new NextURL(this.href, undefined, config);\n }\n\n toString(): string {\n return this.href;\n }\n\n /**\n * The build ID of the Next.js application.\n * Set from `generateBuildId` in next.config.js, or a random UUID if not configured.\n * Can be used in middleware to detect deployment skew between client and server.\n * Matches the Next.js API: `request.nextUrl.buildId`.\n */\n get buildId(): string | undefined {\n return process.env.__VINEXT_BUILD_ID ?? undefined;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Cookie helpers (minimal implementations)\n// ---------------------------------------------------------------------------\n\ntype CookieEntry = {\n name: string;\n value: string;\n};\n\nexport class RequestCookies {\n private _headers: Headers;\n private _parsed: Map<string, string>;\n\n constructor(headers: Headers) {\n this._headers = headers;\n this._parsed = parseCookieHeader(headers.get(\"cookie\") ?? \"\");\n }\n\n get(name: string): CookieEntry | undefined {\n const value = this._parsed.get(name);\n return value !== undefined ? { name, value } : undefined;\n }\n\n getAll(nameOrOptions?: string | CookieEntry): CookieEntry[] {\n const name = typeof nameOrOptions === \"string\" ? nameOrOptions : nameOrOptions?.name;\n return [...this._parsed.entries()]\n .filter(([cookieName]) => name === undefined || cookieName === name)\n .map(([cookieName, value]) => ({ name: cookieName, value }));\n }\n\n has(name: string): boolean {\n return this._parsed.has(name);\n }\n\n set(nameOrOptions: string | CookieEntry, value?: string): this {\n let cookieName: string;\n let cookieValue: string;\n if (typeof nameOrOptions === \"string\") {\n cookieName = nameOrOptions;\n cookieValue = value ?? \"\";\n } else {\n cookieName = nameOrOptions.name;\n cookieValue = nameOrOptions.value;\n }\n this._parsed.set(cookieName, cookieValue);\n this._syncHeader();\n return this;\n }\n\n delete(names: string | string[]): boolean | boolean[] {\n if (Array.isArray(names)) {\n const results = names.map((name) => this._parsed.delete(name));\n this._syncHeader();\n return results;\n }\n const result = this._parsed.delete(names);\n this._syncHeader();\n return result;\n }\n\n clear(): this {\n this._parsed.clear();\n this._syncHeader();\n return this;\n }\n\n get size(): number {\n return this._parsed.size;\n }\n\n toString(): string {\n return this._serialize();\n }\n\n private _serialize(): string {\n return [...this._parsed.entries()].map(([n, v]) => `${n}=${encodeURIComponent(v)}`).join(\"; \");\n }\n\n private _syncHeader(): void {\n if (this._parsed.size === 0) {\n this._headers.delete(\"cookie\");\n } else {\n this._headers.set(\"cookie\", this._serialize());\n }\n }\n\n [Symbol.iterator](): IterableIterator<[string, CookieEntry]> {\n const entries = this.getAll().map((c) => [c.name, c] as [string, CookieEntry]);\n return entries[Symbol.iterator]();\n }\n}\n\n/**\n * RFC 6265 §4.1.1: cookie-name is a token (RFC 2616 §2.2).\n * Allowed: any visible ASCII (0x21-0x7E) except separators: ()<>@,;:\\\"/[]?={}\n */\nconst VALID_COOKIE_NAME_RE =\n /^[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2E\\x30-\\x39\\x41-\\x5A\\x5E-\\x7A\\x7C\\x7E]+$/;\n\nfunction validateCookieName(name: string): void {\n if (!name || !VALID_COOKIE_NAME_RE.test(name)) {\n throw new Error(`Invalid cookie name: ${JSON.stringify(name)}`);\n }\n}\n\nfunction validateCookieAttributeValue(value: string, attributeName: string): void {\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (code <= 0x1f || code === 0x7f || value[i] === \";\") {\n throw new Error(`Invalid cookie ${attributeName} value: ${JSON.stringify(value)}`);\n }\n }\n}\n\nexport class ResponseCookies {\n private _headers: Headers;\n /** Internal map keyed by cookie name — single source of truth. */\n private _parsed: Map<string, { serialized: string; entry: CookieEntry }> = new Map();\n\n constructor(headers: Headers) {\n this._headers = headers;\n\n // Hydrate internal map from any existing Set-Cookie headers\n for (const header of headers.getSetCookie()) {\n const eq = header.indexOf(\"=\");\n if (eq === -1) continue;\n const cookieName = header.slice(0, eq);\n const semi = header.indexOf(\";\", eq);\n const raw = header.slice(eq + 1, semi === -1 ? undefined : semi);\n let value: string;\n try {\n value = decodeURIComponent(raw);\n } catch {\n value = raw;\n }\n this._parsed.set(cookieName, { serialized: header, entry: { name: cookieName, value } });\n }\n }\n\n set(\n ...args:\n | [name: string, value: string, options?: CookieOptions]\n | [options: CookieOptions & { name: string; value: string }]\n ): this {\n const [name, value, opts] = parseCookieSetArgs(args);\n validateCookieName(name);\n\n const parts = [`${name}=${encodeURIComponent(value)}`];\n const path = opts?.path ?? \"/\";\n validateCookieAttributeValue(path, \"Path\");\n parts.push(`Path=${path}`);\n if (opts?.domain) {\n validateCookieAttributeValue(opts.domain, \"Domain\");\n parts.push(`Domain=${opts.domain}`);\n }\n if (opts?.maxAge !== undefined) parts.push(`Max-Age=${opts.maxAge}`);\n if (opts?.expires) parts.push(`Expires=${opts.expires.toUTCString()}`);\n if (opts?.httpOnly) parts.push(\"HttpOnly\");\n if (opts?.secure) parts.push(\"Secure\");\n if (opts?.sameSite) parts.push(`SameSite=${opts.sameSite}`);\n\n this._parsed.set(name, { serialized: parts.join(\"; \"), entry: { name, value } });\n this._syncHeaders();\n return this;\n }\n\n get(...args: [name: string] | [options: { name: string }]): CookieEntry | undefined {\n const key = typeof args[0] === \"string\" ? args[0] : args[0].name;\n return this._parsed.get(key)?.entry;\n }\n\n has(name: string): boolean {\n return this._parsed.has(name);\n }\n\n getAll(...args: [name: string] | [options: { name: string }] | []): CookieEntry[] {\n const all = [...this._parsed.values()].map((v) => v.entry);\n if (args.length === 0) return all;\n const key = typeof args[0] === \"string\" ? args[0] : args[0].name;\n return all.filter((c) => c.name === key);\n }\n\n delete(\n ...args:\n | [name: string]\n | [options: Omit<CookieOptions & { name: string }, \"maxAge\" | \"expires\">]\n ): this {\n const [name, opts] =\n typeof args[0] === \"string\" ? [args[0], undefined] : [args[0].name, args[0]];\n return this.set({\n name,\n value: \"\",\n expires: new Date(0),\n path: opts?.path,\n domain: opts?.domain,\n httpOnly: opts?.httpOnly,\n secure: opts?.secure,\n sameSite: opts?.sameSite,\n });\n }\n\n [Symbol.iterator](): IterableIterator<[string, CookieEntry]> {\n const entries: [string, CookieEntry][] = [...this._parsed.values()].map((v) => [\n v.entry.name,\n v.entry,\n ]);\n return entries[Symbol.iterator]();\n }\n\n /** Delete all Set-Cookie headers and re-append from the internal map. */\n private _syncHeaders(): void {\n this._headers.delete(\"Set-Cookie\");\n for (const { serialized } of this._parsed.values()) {\n this._headers.append(\"Set-Cookie\", serialized);\n }\n }\n}\n\ntype CookieOptions = {\n path?: string;\n domain?: string;\n maxAge?: number;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n sameSite?: \"Strict\" | \"Lax\" | \"None\";\n};\n\n/**\n * Parse the overloaded arguments for ResponseCookies.set():\n * - (name, value, options?) — positional form\n * - ({ name, value, ...options }) — object form\n */\nfunction parseCookieSetArgs(\n args:\n | [name: string, value: string, options?: CookieOptions]\n | [options: CookieOptions & { name: string; value: string }],\n): [string, string, CookieOptions | undefined] {\n if (typeof args[0] === \"string\") {\n return [args[0], args[1] as string, args[2] as CookieOptions | undefined];\n }\n const { name, value, ...opts } = args[0];\n return [name, value, opts as CookieOptions];\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type MiddlewareResponseInit = {\n request?: {\n headers?: Headers;\n };\n} & ResponseInit;\n\nexport type NextMiddlewareResult = NextResponse | Response | null | undefined | void;\n\nexport type NextMiddleware = (\n request: NextRequest,\n event: NextFetchEvent,\n) => NextMiddlewareResult | Promise<NextMiddlewareResult>;\n\n/**\n * Minimal NextFetchEvent — extends FetchEvent where available,\n * otherwise provides the waitUntil pattern standalone.\n */\nexport class NextFetchEvent {\n sourcePage: string;\n private _waitUntilPromises: Promise<unknown>[] = [];\n\n constructor(params: { page: string }) {\n this.sourcePage = params.page;\n }\n\n waitUntil(promise: Promise<unknown>): void {\n this._waitUntilPromises.push(promise);\n }\n\n get waitUntilPromises(): Promise<unknown>[] {\n return this._waitUntilPromises;\n }\n\n /** Drain all waitUntil promises. Returns a single promise that settles when all are done. */\n drainWaitUntil(): Promise<PromiseSettledResult<unknown>[]> {\n return Promise.allSettled(this._waitUntilPromises);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Utility exports\n// ---------------------------------------------------------------------------\n\n/**\n * Parse user agent string. Minimal implementation — for full UA parsing,\n * apps should use a dedicated library like `ua-parser-js`.\n */\nexport function userAgentFromString(ua: string | undefined): UserAgent {\n const input = ua ?? \"\";\n return {\n isBot: /bot|crawler|spider|crawling/i.test(input),\n ua: input,\n browser: {},\n device: {},\n engine: {},\n os: {},\n cpu: {},\n };\n}\n\nexport function userAgent({ headers }: { headers: Headers }): UserAgent {\n return userAgentFromString(headers.get(\"user-agent\") ?? undefined);\n}\n\nexport type UserAgent = {\n isBot: boolean;\n ua: string;\n browser: { name?: string; version?: string; major?: string };\n device: { model?: string; type?: string; vendor?: string };\n engine: { name?: string; version?: string };\n os: { name?: string; version?: string };\n cpu: { architecture?: string };\n};\n\n/**\n * after() — schedule work after the response is sent.\n *\n * Uses the platform's `waitUntil` (via the per-request ExecutionContext) when\n * available so the task survives past the response on Cloudflare Workers.\n * Falls back to a fire-and-forget microtask on runtimes without an execution\n * context (e.g. Node.js dev server).\n *\n * Throws when called inside a cached scope — request-specific\n * side-effects must not leak into cached results.\n */\nexport function after<T>(task: Promise<T> | (() => T | Promise<T>)): void {\n _throwIfInsideCacheScope(\"after()\");\n\n const promise = typeof task === \"function\" ? Promise.resolve().then(task) : task;\n // NOTE: vinext runs function tasks concurrently with response streaming (next microtask),\n // whereas Next.js queues them to run strictly after the response is sent via onClose.\n // This is a known simplification — function tasks here are not guaranteed to run\n // after the response completes, only after the current synchronous execution.\n //\n // `.catch()` is attached synchronously in the same tick as `promise` is created, so\n // there is no window where a pre-rejected `task` promise could trigger an\n // `unhandledrejection` event before the handler is in place.\n const guarded = promise.catch((err) => {\n console.error(\"[vinext] after() task failed:\", err);\n });\n\n // TODO: Next.js throws when after() is called outside a request context or when\n // waitUntil is unavailable, preventing silent task loss. vinext falls back to\n // fire-and-forget here, which is correct for the Node.js dev server (where\n // getRequestExecutionContext() always returns null). On Workers, a misconfigured\n // entry that omits runWithExecutionContext would silently drop tasks — consider\n // a one-time console.warn on the fallback path, gated to production only (e.g.\n // `process.env.NODE_ENV === 'production'` or `typeof caches !== 'undefined'` for\n // a Workers runtime check) with a module-level `let _warned = false` guard so it\n // fires at most once and doesn't spam the dev-server console.\n getRequestExecutionContext()?.waitUntil(guarded);\n}\n\n/**\n * connection() — signals that the response requires a live connection\n * (not a static/cached response). Opts the page out of ISR caching\n * and sets Cache-Control: no-store on the response.\n */\nexport async function connection(): Promise<void> {\n const { markDynamicUsage, throwIfInsideCacheScope } = await import(\"./headers.js\");\n throwIfInsideCacheScope(\"connection()\");\n markDynamicUsage();\n}\n\n/**\n * URLPattern re-export — used in middleware for route matching.\n * Available natively in Node 20+, Cloudflare Workers, Deno.\n * Falls back to urlpattern-polyfill if the global is not available.\n */\nexport const URLPattern: typeof globalThis.URLPattern =\n globalThis.URLPattern ??\n (() => {\n throw new Error(\n \"URLPattern is not available in this runtime. \" +\n \"Install the `urlpattern-polyfill` package or upgrade to Node 20+.\",\n );\n });\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","names":[],"sources":["../../src/shims/server.ts"],"sourcesContent":["/**\n * next/server shim\n *\n * Provides NextRequest, NextResponse, and related types that work with\n * standard Web APIs (Request/Response). This means they work on Node,\n * Cloudflare Workers, Deno, and any WinterCG-compatible runtime.\n *\n * This is a pragmatic subset — we implement the most commonly used APIs\n * rather than bug-for-bug parity with Next.js internals.\n */\n\nimport { encodeMiddlewareRequestHeaders } from \"../server/middleware-request-headers.js\";\nimport { parseCookieHeader } from \"./internal/parse-cookie-header.js\";\nimport { getRequestExecutionContext } from \"./request-context.js\";\n\n// ---------------------------------------------------------------------------\n// Inlined cache-scope guard for after()\n//\n// We cannot statically import throwIfInsideCacheScope from headers.ts here\n// because headers.ts contains the \"use cache\" directive string in its error\n// message, which causes Vite's use-cache transform to include it in the module\n// graph. If headers.ts is pulled in via static import from server.ts, the\n// transform fires on it in Pages Router fixtures that lack @vitejs/plugin-rsc.\n//\n// The connection() function in this file avoids the same problem by using\n// `await import(\"./headers.js\")` (dynamic import, async function). after()\n// must remain synchronous, so we inline the check using the same Symbol.for\n// keys that cache-runtime.ts and cache.ts register their ALS instances with.\n// ---------------------------------------------------------------------------\n\nconst _USE_CACHE_ALS_KEY = Symbol.for(\"vinext.cacheRuntime.contextAls\");\nconst _UNSTABLE_CACHE_ALS_KEY = Symbol.for(\"vinext.unstableCache.als\");\nconst _g = globalThis as unknown as Record<PropertyKey, unknown>;\n\nfunction _throwIfInsideCacheScope(apiName: string): void {\n const cacheAls = _g[_USE_CACHE_ALS_KEY] as { getStore(): unknown } | undefined;\n if (cacheAls?.getStore() != null) {\n throw new Error(\n `\\`${apiName}\\` cannot be called inside \"use cache\". ` +\n `If you need this data inside a cached function, call \\`${apiName}\\` ` +\n \"outside and pass the required data as an argument.\",\n );\n }\n const unstableAls = _g[_UNSTABLE_CACHE_ALS_KEY] as { getStore(): unknown } | undefined;\n if (unstableAls?.getStore() === true) {\n throw new Error(\n `\\`${apiName}\\` cannot be called inside a function cached with \\`unstable_cache()\\`. ` +\n `If you need this data inside a cached function, call \\`${apiName}\\` ` +\n \"outside and pass the required data as an argument.\",\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// NextRequest\n// ---------------------------------------------------------------------------\n\nexport class NextRequest extends Request {\n private _nextUrl: NextURL;\n private _cookies: RequestCookies;\n\n constructor(\n input: URL | RequestInfo,\n init?: RequestInit & {\n nextConfig?: {\n basePath?: string;\n i18n?: { locales: string[]; defaultLocale: string };\n };\n },\n ) {\n // Strip nextConfig before passing to super() — it's vinext-internal,\n // not a valid RequestInit property.\n const { nextConfig: _nextConfig, ...requestInit } = init ?? {};\n // Handle the case where input is a Request object - we need to extract URL and init\n // to avoid Node.js undici issues with passing Request objects directly to super()\n if (input instanceof Request) {\n const req = input;\n super(req.url, {\n method: req.method,\n headers: req.headers,\n body: req.body,\n // @ts-expect-error - duplex is not in RequestInit type but needed for streams\n duplex: req.body ? \"half\" : undefined,\n ...requestInit,\n });\n } else {\n super(input, requestInit);\n }\n const url =\n typeof input === \"string\"\n ? new URL(input, \"http://localhost\")\n : input instanceof URL\n ? input\n : new URL(input.url, \"http://localhost\");\n const urlConfig: NextURLConfig | undefined = _nextConfig\n ? { basePath: _nextConfig.basePath, nextConfig: { i18n: _nextConfig.i18n } }\n : undefined;\n this._nextUrl = new NextURL(url, undefined, urlConfig);\n this._cookies = new RequestCookies(this.headers);\n }\n\n get nextUrl(): NextURL {\n return this._nextUrl;\n }\n\n get cookies(): RequestCookies {\n return this._cookies;\n }\n\n /**\n * Client IP address. Prefers Cloudflare's trusted CF-Connecting-IP header\n * over the spoofable X-Forwarded-For. Returns undefined if unavailable.\n */\n get ip(): string | undefined {\n return (\n this.headers.get(\"cf-connecting-ip\") ??\n this.headers.get(\"x-real-ip\") ??\n this.headers.get(\"x-forwarded-for\")?.split(\",\")[0]?.trim() ??\n undefined\n );\n }\n\n /**\n * Geolocation data. Platform-dependent (e.g., Cloudflare, Vercel).\n * Returns undefined if not available.\n */\n get geo():\n | { city?: string; country?: string; region?: string; latitude?: string; longitude?: string }\n | undefined {\n // Check Cloudflare-style headers, Vercel-style headers\n const country =\n this.headers.get(\"cf-ipcountry\") ?? this.headers.get(\"x-vercel-ip-country\") ?? undefined;\n if (!country) return undefined;\n return {\n country,\n city: this.headers.get(\"cf-ipcity\") ?? this.headers.get(\"x-vercel-ip-city\") ?? undefined,\n region:\n this.headers.get(\"cf-region\") ??\n this.headers.get(\"x-vercel-ip-country-region\") ??\n undefined,\n latitude:\n this.headers.get(\"cf-iplatitude\") ?? this.headers.get(\"x-vercel-ip-latitude\") ?? undefined,\n longitude:\n this.headers.get(\"cf-iplongitude\") ??\n this.headers.get(\"x-vercel-ip-longitude\") ??\n undefined,\n };\n }\n\n /**\n * The build ID of the Next.js application.\n * Delegates to `nextUrl.buildId` to match Next.js API surface.\n * Can be used in middleware to detect deployment skew between client and server.\n */\n get buildId(): string | undefined {\n return this._nextUrl.buildId;\n }\n}\n\n// ---------------------------------------------------------------------------\n// NextResponse\n// ---------------------------------------------------------------------------\n\n/** Valid HTTP redirect status codes, matching Next.js's REDIRECTS set. */\nconst REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);\n\nexport class NextResponse<_Body = unknown> extends Response {\n private _cookies: ResponseCookies;\n\n constructor(body?: BodyInit | null, init?: ResponseInit) {\n super(body, init);\n this._cookies = new ResponseCookies(this.headers);\n }\n\n get cookies(): ResponseCookies {\n return this._cookies;\n }\n\n /**\n * Create a JSON response.\n */\n static json<JsonBody>(body: JsonBody, init?: ResponseInit): NextResponse<JsonBody> {\n const headers = new Headers(init?.headers);\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n return new NextResponse(JSON.stringify(body), {\n ...init,\n headers,\n }) as NextResponse<JsonBody>;\n }\n\n /**\n * Create a redirect response.\n */\n static redirect(url: string | URL, init?: number | ResponseInit): NextResponse {\n const status = typeof init === \"number\" ? init : (init?.status ?? 307);\n if (!REDIRECT_STATUSES.has(status)) {\n throw new RangeError(`Failed to execute \"redirect\" on \"response\": Invalid status code`);\n }\n const destination = typeof url === \"string\" ? url : url.toString();\n const headers = new Headers(typeof init === \"object\" ? init?.headers : undefined);\n headers.set(\"Location\", destination);\n return new NextResponse(null, { status, headers });\n }\n\n /**\n * Create a rewrite response (middleware pattern).\n * Sets the x-middleware-rewrite header.\n */\n static rewrite(destination: string | URL, init?: MiddlewareResponseInit): NextResponse {\n const url = typeof destination === \"string\" ? destination : destination.toString();\n const headers = new Headers(init?.headers);\n headers.set(\"x-middleware-rewrite\", url);\n if (init?.request?.headers) {\n encodeMiddlewareRequestHeaders(headers, init.request.headers);\n }\n return new NextResponse(null, { ...init, headers });\n }\n\n /**\n * Continue to the next handler (middleware pattern).\n * Sets the x-middleware-next header.\n */\n static next(init?: MiddlewareResponseInit): NextResponse {\n const headers = new Headers(init?.headers);\n headers.set(\"x-middleware-next\", \"1\");\n if (init?.request?.headers) {\n encodeMiddlewareRequestHeaders(headers, init.request.headers);\n }\n return new NextResponse(null, { ...init, headers });\n }\n}\n\n// ---------------------------------------------------------------------------\n// NextURL — lightweight URL wrapper with pathname helpers\n// ---------------------------------------------------------------------------\n\nexport type NextURLConfig = {\n basePath?: string;\n nextConfig?: {\n i18n?: {\n locales: string[];\n defaultLocale: string;\n };\n };\n};\n\nexport class NextURL {\n /** Internal URL stores the pathname WITHOUT basePath or locale prefix. */\n private _url: URL;\n private _basePath: string;\n private _locale: string | undefined;\n private _defaultLocale: string | undefined;\n private _locales: string[] | undefined;\n\n constructor(input: string | URL, base?: string | URL, config?: NextURLConfig) {\n this._url = new URL(input.toString(), base);\n this._basePath = config?.basePath ?? \"\";\n this._stripBasePath();\n const i18n = config?.nextConfig?.i18n;\n if (i18n) {\n this._locales = [...i18n.locales];\n this._defaultLocale = i18n.defaultLocale;\n this._analyzeLocale(this._locales);\n }\n }\n\n /** Strip basePath prefix from the internal pathname. */\n private _stripBasePath(): void {\n if (!this._basePath) return;\n const { pathname } = this._url;\n if (pathname === this._basePath || pathname.startsWith(this._basePath + \"/\")) {\n this._url.pathname = pathname.slice(this._basePath.length) || \"/\";\n }\n }\n\n /** Extract locale from pathname, stripping it from the internal URL. */\n private _analyzeLocale(locales: string[]): void {\n const segments = this._url.pathname.split(\"/\");\n const candidate = segments[1]?.toLowerCase();\n const match = locales.find((l) => l.toLowerCase() === candidate);\n if (match) {\n this._locale = match;\n this._url.pathname = \"/\" + segments.slice(2).join(\"/\");\n } else {\n this._locale = this._defaultLocale;\n }\n }\n\n /**\n * Reconstruct the full pathname with basePath + locale prefix.\n * Mirrors Next.js's internal formatPathname().\n */\n private _formatPathname(): string {\n // Build prefix: basePath + locale (skip defaultLocale — Next.js omits it)\n let prefix = this._basePath;\n if (this._locale && this._locale !== this._defaultLocale) {\n prefix += \"/\" + this._locale;\n }\n if (!prefix) return this._url.pathname;\n const inner = this._url.pathname;\n return inner === \"/\" ? prefix : prefix + inner;\n }\n\n get href(): string {\n const formatted = this._formatPathname();\n if (formatted === this._url.pathname) return this._url.href;\n // Replace pathname in href via string slicing — avoids URL allocation.\n // URL.href is always <origin+auth><pathname><search><hash>.\n const { href, pathname, search, hash } = this._url;\n const baseEnd = href.length - pathname.length - search.length - hash.length;\n return href.slice(0, baseEnd) + formatted + search + hash;\n }\n set href(value: string) {\n this._url.href = value;\n this._stripBasePath();\n if (this._locales) this._analyzeLocale(this._locales);\n }\n\n get origin(): string {\n return this._url.origin;\n }\n\n get protocol(): string {\n return this._url.protocol;\n }\n set protocol(value: string) {\n this._url.protocol = value;\n }\n\n get username(): string {\n return this._url.username;\n }\n set username(value: string) {\n this._url.username = value;\n }\n\n get password(): string {\n return this._url.password;\n }\n set password(value: string) {\n this._url.password = value;\n }\n\n get host(): string {\n return this._url.host;\n }\n set host(value: string) {\n this._url.host = value;\n }\n\n get hostname(): string {\n return this._url.hostname;\n }\n set hostname(value: string) {\n this._url.hostname = value;\n }\n\n get port(): string {\n return this._url.port;\n }\n set port(value: string) {\n this._url.port = value;\n }\n\n /** Returns the pathname WITHOUT basePath or locale prefix. */\n get pathname(): string {\n return this._url.pathname;\n }\n set pathname(value: string) {\n this._url.pathname = value;\n }\n\n get search(): string {\n return this._url.search;\n }\n set search(value: string) {\n this._url.search = value;\n }\n\n get searchParams(): URLSearchParams {\n return this._url.searchParams;\n }\n\n get hash(): string {\n return this._url.hash;\n }\n set hash(value: string) {\n this._url.hash = value;\n }\n\n get basePath(): string {\n return this._basePath;\n }\n set basePath(value: string) {\n this._basePath = value === \"\" ? \"\" : value.startsWith(\"/\") ? value : \"/\" + value;\n }\n\n get locale(): string {\n return this._locale ?? \"\";\n }\n set locale(value: string | undefined) {\n if (this._locales) {\n if (!value) {\n this._locale = this._defaultLocale;\n return;\n }\n if (!this._locales.includes(value)) {\n throw new TypeError(\n `The locale \"${value}\" is not in the configured locales: ${this._locales.join(\", \")}`,\n );\n }\n }\n this._locale = this._locales ? value : this._locale;\n }\n\n get defaultLocale(): string | undefined {\n return this._defaultLocale;\n }\n\n get locales(): string[] | undefined {\n return this._locales ? [...this._locales] : undefined;\n }\n\n clone(): NextURL {\n const config: NextURLConfig = {\n basePath: this._basePath,\n nextConfig: this._locales\n ? { i18n: { locales: [...this._locales], defaultLocale: this._defaultLocale! } }\n : undefined,\n };\n // Pass the full href (with locale/basePath re-added) so the constructor\n // can re-analyze and extract locale correctly.\n return new NextURL(this.href, undefined, config);\n }\n\n toString(): string {\n return this.href;\n }\n\n /**\n * The build ID of the Next.js application.\n * Set from `generateBuildId` in next.config.js, or a random UUID if not configured.\n * Can be used in middleware to detect deployment skew between client and server.\n * Matches the Next.js API: `request.nextUrl.buildId`.\n */\n get buildId(): string | undefined {\n return process.env.__VINEXT_BUILD_ID ?? undefined;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Cookie helpers (minimal implementations)\n// ---------------------------------------------------------------------------\n\ntype CookieEntry = {\n name: string;\n value: string;\n};\n\nexport class RequestCookies {\n private _headers: Headers;\n private _parsed: Map<string, string>;\n\n constructor(headers: Headers) {\n this._headers = headers;\n this._parsed = parseCookieHeader(headers.get(\"cookie\") ?? \"\");\n }\n\n get(name: string): CookieEntry | undefined {\n const value = this._parsed.get(name);\n return value !== undefined ? { name, value } : undefined;\n }\n\n getAll(nameOrOptions?: string | CookieEntry): CookieEntry[] {\n const name = typeof nameOrOptions === \"string\" ? nameOrOptions : nameOrOptions?.name;\n return [...this._parsed.entries()]\n .filter(([cookieName]) => name === undefined || cookieName === name)\n .map(([cookieName, value]) => ({ name: cookieName, value }));\n }\n\n has(name: string): boolean {\n return this._parsed.has(name);\n }\n\n set(nameOrOptions: string | CookieEntry, value?: string): this {\n let cookieName: string;\n let cookieValue: string;\n if (typeof nameOrOptions === \"string\") {\n cookieName = nameOrOptions;\n cookieValue = value ?? \"\";\n } else {\n cookieName = nameOrOptions.name;\n cookieValue = nameOrOptions.value;\n }\n validateCookieName(cookieName);\n this._parsed.set(cookieName, cookieValue);\n this._syncHeader();\n return this;\n }\n\n delete(names: string | string[]): boolean | boolean[] {\n if (Array.isArray(names)) {\n const results = names.map((name) => {\n validateCookieName(name);\n return this._parsed.delete(name);\n });\n this._syncHeader();\n return results;\n }\n validateCookieName(names);\n const result = this._parsed.delete(names);\n this._syncHeader();\n return result;\n }\n\n clear(): this {\n this._parsed.clear();\n this._syncHeader();\n return this;\n }\n\n get size(): number {\n return this._parsed.size;\n }\n\n toString(): string {\n return this._serialize();\n }\n\n private _serialize(): string {\n return [...this._parsed.entries()].map(([n, v]) => `${n}=${encodeURIComponent(v)}`).join(\"; \");\n }\n\n private _syncHeader(): void {\n if (this._parsed.size === 0) {\n this._headers.delete(\"cookie\");\n } else {\n this._headers.set(\"cookie\", this._serialize());\n }\n }\n\n [Symbol.iterator](): IterableIterator<[string, CookieEntry]> {\n const entries = this.getAll().map((c) => [c.name, c] as [string, CookieEntry]);\n return entries[Symbol.iterator]();\n }\n}\n\n/**\n * RFC 6265 §4.1.1: cookie-name is a token (RFC 2616 §2.2).\n * Allowed: any visible ASCII (0x21-0x7E) except separators: ()<>@,;:\\\"/[]?={}\n */\nconst VALID_COOKIE_NAME_RE =\n /^[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2E\\x30-\\x39\\x41-\\x5A\\x5E-\\x7A\\x7C\\x7E]+$/;\n\nfunction validateCookieName(name: string): void {\n if (!name || !VALID_COOKIE_NAME_RE.test(name)) {\n throw new Error(`Invalid cookie name: ${JSON.stringify(name)}`);\n }\n}\n\nfunction validateCookieAttributeValue(value: string, attributeName: string): void {\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (code <= 0x1f || code === 0x7f || value[i] === \";\") {\n throw new Error(`Invalid cookie ${attributeName} value: ${JSON.stringify(value)}`);\n }\n }\n}\n\nexport class ResponseCookies {\n private _headers: Headers;\n /** Internal map keyed by cookie name — single source of truth. */\n private _parsed: Map<string, { serialized: string; entry: CookieEntry }> = new Map();\n\n constructor(headers: Headers) {\n this._headers = headers;\n\n // Hydrate internal map from any existing Set-Cookie headers\n for (const header of headers.getSetCookie()) {\n const eq = header.indexOf(\"=\");\n if (eq === -1) continue;\n const cookieName = header.slice(0, eq);\n const semi = header.indexOf(\";\", eq);\n const raw = header.slice(eq + 1, semi === -1 ? undefined : semi);\n let value: string;\n try {\n value = decodeURIComponent(raw);\n } catch {\n value = raw;\n }\n this._parsed.set(cookieName, { serialized: header, entry: { name: cookieName, value } });\n }\n }\n\n set(\n ...args:\n | [name: string, value: string, options?: CookieOptions]\n | [options: CookieOptions & { name: string; value: string }]\n ): this {\n const [name, value, opts] = parseCookieSetArgs(args);\n validateCookieName(name);\n\n const parts = [`${name}=${encodeURIComponent(value)}`];\n const path = opts?.path ?? \"/\";\n validateCookieAttributeValue(path, \"Path\");\n parts.push(`Path=${path}`);\n if (opts?.domain) {\n validateCookieAttributeValue(opts.domain, \"Domain\");\n parts.push(`Domain=${opts.domain}`);\n }\n if (opts?.maxAge !== undefined) parts.push(`Max-Age=${opts.maxAge}`);\n if (opts?.expires) parts.push(`Expires=${opts.expires.toUTCString()}`);\n if (opts?.httpOnly) parts.push(\"HttpOnly\");\n if (opts?.secure) parts.push(\"Secure\");\n if (opts?.sameSite) parts.push(`SameSite=${opts.sameSite}`);\n\n this._parsed.set(name, { serialized: parts.join(\"; \"), entry: { name, value } });\n this._syncHeaders();\n return this;\n }\n\n get(...args: [name: string] | [options: { name: string }]): CookieEntry | undefined {\n const key = typeof args[0] === \"string\" ? args[0] : args[0].name;\n return this._parsed.get(key)?.entry;\n }\n\n has(name: string): boolean {\n return this._parsed.has(name);\n }\n\n getAll(...args: [name: string] | [options: { name: string }] | []): CookieEntry[] {\n const all = [...this._parsed.values()].map((v) => v.entry);\n if (args.length === 0) return all;\n const key = typeof args[0] === \"string\" ? args[0] : args[0].name;\n return all.filter((c) => c.name === key);\n }\n\n delete(\n ...args:\n | [name: string]\n | [options: Omit<CookieOptions & { name: string }, \"maxAge\" | \"expires\">]\n ): this {\n const [name, opts] =\n typeof args[0] === \"string\" ? [args[0], undefined] : [args[0].name, args[0]];\n return this.set({\n name,\n value: \"\",\n expires: new Date(0),\n path: opts?.path,\n domain: opts?.domain,\n httpOnly: opts?.httpOnly,\n secure: opts?.secure,\n sameSite: opts?.sameSite,\n });\n }\n\n [Symbol.iterator](): IterableIterator<[string, CookieEntry]> {\n const entries: [string, CookieEntry][] = [...this._parsed.values()].map((v) => [\n v.entry.name,\n v.entry,\n ]);\n return entries[Symbol.iterator]();\n }\n\n /** Delete all Set-Cookie headers and re-append from the internal map. */\n private _syncHeaders(): void {\n this._headers.delete(\"Set-Cookie\");\n for (const { serialized } of this._parsed.values()) {\n this._headers.append(\"Set-Cookie\", serialized);\n }\n }\n}\n\ntype CookieOptions = {\n path?: string;\n domain?: string;\n maxAge?: number;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n sameSite?: \"Strict\" | \"Lax\" | \"None\";\n};\n\n/**\n * Parse the overloaded arguments for ResponseCookies.set():\n * - (name, value, options?) — positional form\n * - ({ name, value, ...options }) — object form\n */\nfunction parseCookieSetArgs(\n args:\n | [name: string, value: string, options?: CookieOptions]\n | [options: CookieOptions & { name: string; value: string }],\n): [string, string, CookieOptions | undefined] {\n if (typeof args[0] === \"string\") {\n return [args[0], args[1] as string, args[2] as CookieOptions | undefined];\n }\n const { name, value, ...opts } = args[0];\n return [name, value, opts as CookieOptions];\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type MiddlewareResponseInit = {\n request?: {\n headers?: Headers;\n };\n} & ResponseInit;\n\nexport type NextMiddlewareResult = NextResponse | Response | null | undefined | void;\n\nexport type NextMiddleware = (\n request: NextRequest,\n event: NextFetchEvent,\n) => NextMiddlewareResult | Promise<NextMiddlewareResult>;\n\n/**\n * Minimal NextFetchEvent — extends FetchEvent where available,\n * otherwise provides the waitUntil pattern standalone.\n */\nexport class NextFetchEvent {\n sourcePage: string;\n private _waitUntilPromises: Promise<unknown>[] = [];\n\n constructor(params: { page: string }) {\n this.sourcePage = params.page;\n }\n\n waitUntil(promise: Promise<unknown>): void {\n this._waitUntilPromises.push(promise);\n }\n\n get waitUntilPromises(): Promise<unknown>[] {\n return this._waitUntilPromises;\n }\n\n /** Drain all waitUntil promises. Returns a single promise that settles when all are done. */\n drainWaitUntil(): Promise<PromiseSettledResult<unknown>[]> {\n return Promise.allSettled(this._waitUntilPromises);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Utility exports\n// ---------------------------------------------------------------------------\n\n/**\n * Parse user agent string. Minimal implementation — for full UA parsing,\n * apps should use a dedicated library like `ua-parser-js`.\n */\nexport function userAgentFromString(ua: string | undefined): UserAgent {\n const input = ua ?? \"\";\n return {\n isBot: /bot|crawler|spider|crawling/i.test(input),\n ua: input,\n browser: {},\n device: {},\n engine: {},\n os: {},\n cpu: {},\n };\n}\n\nexport function userAgent({ headers }: { headers: Headers }): UserAgent {\n return userAgentFromString(headers.get(\"user-agent\") ?? undefined);\n}\n\nexport type UserAgent = {\n isBot: boolean;\n ua: string;\n browser: { name?: string; version?: string; major?: string };\n device: { model?: string; type?: string; vendor?: string };\n engine: { name?: string; version?: string };\n os: { name?: string; version?: string };\n cpu: { architecture?: string };\n};\n\n/**\n * after() — schedule work after the response is sent.\n *\n * Uses the platform's `waitUntil` (via the per-request ExecutionContext) when\n * available so the task survives past the response on Cloudflare Workers.\n * Falls back to a fire-and-forget microtask on runtimes without an execution\n * context (e.g. Node.js dev server).\n *\n * Throws when called inside a cached scope — request-specific\n * side-effects must not leak into cached results.\n */\nexport function after<T>(task: Promise<T> | (() => T | Promise<T>)): void {\n _throwIfInsideCacheScope(\"after()\");\n\n const promise = typeof task === \"function\" ? Promise.resolve().then(task) : task;\n // NOTE: vinext runs function tasks concurrently with response streaming (next microtask),\n // whereas Next.js queues them to run strictly after the response is sent via onClose.\n // This is a known simplification — function tasks here are not guaranteed to run\n // after the response completes, only after the current synchronous execution.\n //\n // `.catch()` is attached synchronously in the same tick as `promise` is created, so\n // there is no window where a pre-rejected `task` promise could trigger an\n // `unhandledrejection` event before the handler is in place.\n const guarded = promise.catch((err) => {\n console.error(\"[vinext] after() task failed:\", err);\n });\n\n // TODO: Next.js throws when after() is called outside a request context or when\n // waitUntil is unavailable, preventing silent task loss. vinext falls back to\n // fire-and-forget here, which is correct for the Node.js dev server (where\n // getRequestExecutionContext() always returns null). On Workers, a misconfigured\n // entry that omits runWithExecutionContext would silently drop tasks — consider\n // a one-time console.warn on the fallback path, gated to production only (e.g.\n // `process.env.NODE_ENV === 'production'` or `typeof caches !== 'undefined'` for\n // a Workers runtime check) with a module-level `let _warned = false` guard so it\n // fires at most once and doesn't spam the dev-server console.\n getRequestExecutionContext()?.waitUntil(guarded);\n}\n\n/**\n * connection() — signals that the response requires a live connection\n * (not a static/cached response). Opts the page out of ISR caching\n * and sets Cache-Control: no-store on the response.\n */\nexport async function connection(): Promise<void> {\n const { markDynamicUsage, throwIfInsideCacheScope } = await import(\"./headers.js\");\n throwIfInsideCacheScope(\"connection()\");\n markDynamicUsage();\n}\n\n/**\n * URLPattern re-export — used in middleware for route matching.\n * Available natively in Node 20+, Cloudflare Workers, Deno.\n * Falls back to urlpattern-polyfill if the global is not available.\n */\nexport const URLPattern: typeof globalThis.URLPattern =\n globalThis.URLPattern ??\n (() => {\n throw new Error(\n \"URLPattern is not available in this runtime. \" +\n \"Install the `urlpattern-polyfill` package or upgrade to Node 20+.\",\n );\n });\n"],"mappings":"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"}
|
package/dist/shims/slot.d.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import { AppElementValue, AppElements, UNMATCHED_SLOT } from "../server/app-elements.js";
|
|
1
2
|
import * as React$1 from "react";
|
|
2
|
-
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
|
+
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
4
|
|
|
4
5
|
//#region src/shims/slot.d.ts
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Holds resolved AppElements (not a Promise). React 19's use(Promise) during
|
|
8
|
+
* hydration triggers "async Client Component" for native Promises that lack
|
|
9
|
+
* React's internal .status property. Storing resolved values sidesteps this.
|
|
10
|
+
*/
|
|
11
|
+
declare const ElementsContext: React$1.Context<Readonly<Record<string, AppElementValue>>>;
|
|
8
12
|
declare const ChildrenContext: React$1.Context<React$1.ReactNode>;
|
|
9
13
|
declare const ParallelSlotsContext: React$1.Context<Readonly<Record<string, React$1.ReactNode>> | null>;
|
|
10
|
-
declare function
|
|
14
|
+
declare function mergeElements(prev: AppElements, next: AppElements, clearAbsentSlots?: boolean): AppElements;
|
|
11
15
|
declare function Slot({
|
|
12
16
|
id,
|
|
13
17
|
children,
|
|
@@ -16,7 +20,7 @@ declare function Slot({
|
|
|
16
20
|
id: string;
|
|
17
21
|
children?: React$1.ReactNode;
|
|
18
22
|
parallelSlots?: Readonly<Record<string, React$1.ReactNode>>;
|
|
19
|
-
}): react_jsx_runtime0.JSX.Element | null;
|
|
23
|
+
}): _$react_jsx_runtime0.JSX.Element | null;
|
|
20
24
|
declare function Children(): React$1.ReactNode;
|
|
21
25
|
declare function ParallelSlot({
|
|
22
26
|
name
|
|
@@ -24,5 +28,5 @@ declare function ParallelSlot({
|
|
|
24
28
|
name: string;
|
|
25
29
|
}): string | number | bigint | boolean | React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>> | Iterable<React$1.ReactNode> | Promise<string | number | bigint | boolean | React$1.ReactPortal | React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>> | Iterable<React$1.ReactNode> | null | undefined> | null;
|
|
26
30
|
//#endregion
|
|
27
|
-
export { Children, ChildrenContext,
|
|
31
|
+
export { Children, ChildrenContext, ElementsContext, ParallelSlot, ParallelSlotsContext, Slot, UNMATCHED_SLOT, mergeElements };
|
|
28
32
|
//# sourceMappingURL=slot.d.ts.map
|
package/dist/shims/slot.js
CHANGED
|
@@ -1,32 +1,41 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { UNMATCHED_SLOT } from "../server/app-elements.js";
|
|
2
3
|
import { notFound } from "./navigation.js";
|
|
3
4
|
import * as React$1 from "react";
|
|
4
5
|
import { jsx } from "react/jsx-runtime";
|
|
5
6
|
//#region src/shims/slot.tsx
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
const EMPTY_ELEMENTS = Object.freeze({});
|
|
8
|
+
const warnedMissingEntryIds = /* @__PURE__ */ new Set();
|
|
9
|
+
/**
|
|
10
|
+
* Holds resolved AppElements (not a Promise). React 19's use(Promise) during
|
|
11
|
+
* hydration triggers "async Client Component" for native Promises that lack
|
|
12
|
+
* React's internal .status property. Storing resolved values sidesteps this.
|
|
13
|
+
*/
|
|
14
|
+
const ElementsContext = React$1.createContext(EMPTY_ELEMENTS);
|
|
10
15
|
const ChildrenContext = React$1.createContext(null);
|
|
11
16
|
const ParallelSlotsContext = React$1.createContext(null);
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
function mergeElements(prev, next, clearAbsentSlots = false) {
|
|
18
|
+
const merged = {
|
|
19
|
+
...prev,
|
|
20
|
+
...next
|
|
21
|
+
};
|
|
22
|
+
for (const key of Object.keys(merged)) if (key.startsWith("slot:") && merged[key] === UNMATCHED_SLOT && Object.hasOwn(prev, key)) merged[key] = prev[key];
|
|
23
|
+
if (clearAbsentSlots) {
|
|
24
|
+
for (const key of Object.keys(merged)) if (key.startsWith("slot:") && !Object.hasOwn(next, key)) delete merged[key];
|
|
17
25
|
}
|
|
18
|
-
const cached = nextCache.get(next);
|
|
19
|
-
if (cached) return cached;
|
|
20
|
-
const merged = Promise.all([prev, next]).then(([prevElements, nextElements]) => ({
|
|
21
|
-
...prevElements,
|
|
22
|
-
...nextElements
|
|
23
|
-
}));
|
|
24
|
-
nextCache.set(next, merged);
|
|
25
26
|
return merged;
|
|
26
27
|
}
|
|
27
28
|
function Slot({ id, children, parallelSlots }) {
|
|
28
|
-
const elements = React$1.
|
|
29
|
-
if (!Object.hasOwn(elements, id))
|
|
29
|
+
const elements = React$1.useContext(ElementsContext);
|
|
30
|
+
if (!Object.hasOwn(elements, id)) {
|
|
31
|
+
if (process.env.NODE_ENV !== "production" && !id.startsWith("slot:")) {
|
|
32
|
+
if (!warnedMissingEntryIds.has(id)) {
|
|
33
|
+
warnedMissingEntryIds.add(id);
|
|
34
|
+
console.warn("[vinext] Missing App Router element entry during render: " + id);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
30
39
|
const element = elements[id];
|
|
31
40
|
if (element === UNMATCHED_SLOT) notFound();
|
|
32
41
|
return /* @__PURE__ */ jsx(ParallelSlotsContext.Provider, {
|
|
@@ -44,6 +53,6 @@ function ParallelSlot({ name }) {
|
|
|
44
53
|
return React$1.useContext(ParallelSlotsContext)?.[name] ?? null;
|
|
45
54
|
}
|
|
46
55
|
//#endregion
|
|
47
|
-
export { Children, ChildrenContext, ElementsContext, ParallelSlot, ParallelSlotsContext, Slot, UNMATCHED_SLOT,
|
|
56
|
+
export { Children, ChildrenContext, ElementsContext, ParallelSlot, ParallelSlotsContext, Slot, UNMATCHED_SLOT, mergeElements };
|
|
48
57
|
|
|
49
58
|
//# sourceMappingURL=slot.js.map
|
package/dist/shims/slot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slot.js","names":["React"],"sources":["../../src/shims/slot.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {
|
|
1
|
+
{"version":3,"file":"slot.js","names":["React"],"sources":["../../src/shims/slot.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { UNMATCHED_SLOT, type AppElementValue, type AppElements } from \"../server/app-elements.js\";\nimport { notFound } from \"./navigation.js\";\n\nconst EMPTY_ELEMENTS: AppElements = Object.freeze({});\nconst warnedMissingEntryIds = new Set<string>();\n\nexport { UNMATCHED_SLOT };\n\n/**\n * Holds resolved AppElements (not a Promise). React 19's use(Promise) during\n * hydration triggers \"async Client Component\" for native Promises that lack\n * React's internal .status property. Storing resolved values sidesteps this.\n */\nexport const ElementsContext = React.createContext<AppElements>(EMPTY_ELEMENTS);\n\nexport const ChildrenContext = React.createContext<React.ReactNode>(null);\n\nexport const ParallelSlotsContext = React.createContext<Readonly<\n Record<string, React.ReactNode>\n> | null>(null);\n\nexport function mergeElements(\n prev: AppElements,\n next: AppElements,\n clearAbsentSlots = false,\n): AppElements {\n const merged: Record<string, AppElementValue> = { ...prev, ...next };\n // On soft navigation, unmatched parallel slots preserve their previous subtree\n // instead of firing notFound(). Only hard navigation (full page load) should 404.\n // This matches Next.js behavior for parallel route persistence.\n for (const key of Object.keys(merged)) {\n if (key.startsWith(\"slot:\") && merged[key] === UNMATCHED_SLOT && Object.hasOwn(prev, key)) {\n merged[key] = prev[key];\n }\n }\n // On traversal (browser back/forward), the server renders the full destination\n // route tree. A slot absent from next means the destination route tree does not\n // include it, so clear it rather than keeping the stale prev value. This only\n // runs for traversals because soft forward navigations may omit parent layout\n // slots that should be preserved.\n if (clearAbsentSlots) {\n for (const key of Object.keys(merged)) {\n if (key.startsWith(\"slot:\") && !Object.hasOwn(next, key)) {\n delete merged[key];\n }\n }\n }\n return merged;\n}\n\nexport function Slot({\n id,\n children,\n parallelSlots,\n}: {\n id: string;\n children?: React.ReactNode;\n parallelSlots?: Readonly<Record<string, React.ReactNode>>;\n}) {\n const elements = React.useContext(ElementsContext);\n\n if (!Object.hasOwn(elements, id)) {\n if (process.env.NODE_ENV !== \"production\" && !id.startsWith(\"slot:\")) {\n if (!warnedMissingEntryIds.has(id)) {\n warnedMissingEntryIds.add(id);\n console.warn(\"[vinext] Missing App Router element entry during render: \" + id);\n }\n }\n return null;\n }\n\n const element = elements[id];\n if (element === UNMATCHED_SLOT) {\n notFound();\n }\n\n return (\n <ParallelSlotsContext.Provider value={parallelSlots ?? null}>\n <ChildrenContext.Provider value={children ?? null}>{element}</ChildrenContext.Provider>\n </ParallelSlotsContext.Provider>\n );\n}\n\nexport function Children() {\n return React.useContext(ChildrenContext);\n}\n\nexport function ParallelSlot({ name }: { name: string }) {\n const slots = React.useContext(ParallelSlotsContext);\n return slots?.[name] ?? null;\n}\n"],"mappings":";;;;;;AAMA,MAAM,iBAA8B,OAAO,OAAO,EAAE,CAAC;AACrD,MAAM,wCAAwB,IAAI,KAAa;;;;;;AAS/C,MAAa,kBAAkBA,QAAM,cAA2B,eAAe;AAE/E,MAAa,kBAAkBA,QAAM,cAA+B,KAAK;AAEzE,MAAa,uBAAuBA,QAAM,cAEhC,KAAK;AAEf,SAAgB,cACd,MACA,MACA,mBAAmB,OACN;CACb,MAAM,SAA0C;EAAE,GAAG;EAAM,GAAG;EAAM;AAIpE,MAAK,MAAM,OAAO,OAAO,KAAK,OAAO,CACnC,KAAI,IAAI,WAAW,QAAQ,IAAI,OAAO,SAAS,kBAAkB,OAAO,OAAO,MAAM,IAAI,CACvF,QAAO,OAAO,KAAK;AAQvB,KAAI;OACG,MAAM,OAAO,OAAO,KAAK,OAAO,CACnC,KAAI,IAAI,WAAW,QAAQ,IAAI,CAAC,OAAO,OAAO,MAAM,IAAI,CACtD,QAAO,OAAO;;AAIpB,QAAO;;AAGT,SAAgB,KAAK,EACnB,IACA,UACA,iBAKC;CACD,MAAM,WAAWA,QAAM,WAAW,gBAAgB;AAElD,KAAI,CAAC,OAAO,OAAO,UAAU,GAAG,EAAE;AAChC,MAAI,QAAQ,IAAI,aAAa,gBAAgB,CAAC,GAAG,WAAW,QAAQ;OAC9D,CAAC,sBAAsB,IAAI,GAAG,EAAE;AAClC,0BAAsB,IAAI,GAAG;AAC7B,YAAQ,KAAK,8DAA8D,GAAG;;;AAGlF,SAAO;;CAGT,MAAM,UAAU,SAAS;AACzB,KAAI,YAAY,eACd,WAAU;AAGZ,QACE,oBAAC,qBAAqB,UAAtB;EAA+B,OAAO,iBAAiB;YACrD,oBAAC,gBAAgB,UAAjB;GAA0B,OAAO,YAAY;aAAO;GAAmC,CAAA;EACzD,CAAA;;AAIpC,SAAgB,WAAW;AACzB,QAAOA,QAAM,WAAW,gBAAgB;;AAG1C,SAAgB,aAAa,EAAE,QAA0B;AAEvD,QADcA,QAAM,WAAW,qBAAqB,GACrC,SAAS"}
|
|
@@ -29,6 +29,7 @@ declare function createRequestContext(opts?: Partial<UnifiedRequestContext>): Un
|
|
|
29
29
|
* All shim modules will read/write their state from `ctx` for the
|
|
30
30
|
* duration of the call, including async continuations.
|
|
31
31
|
*/
|
|
32
|
+
declare function runWithRequestContext<T>(ctx: UnifiedRequestContext, fn: () => Promise<T>): Promise<T>;
|
|
32
33
|
declare function runWithRequestContext<T>(ctx: UnifiedRequestContext, fn: () => T | Promise<T>): T | Promise<T>;
|
|
33
34
|
/**
|
|
34
35
|
* Run `fn` in a nested unified scope derived from the current request context.
|
|
@@ -39,6 +40,7 @@ declare function runWithRequestContext<T>(ctx: UnifiedRequestContext, fn: () =>
|
|
|
39
40
|
*
|
|
40
41
|
* @internal
|
|
41
42
|
*/
|
|
43
|
+
declare function runWithUnifiedStateMutation<T>(mutate: (ctx: UnifiedRequestContext) => void, fn: () => Promise<T>): Promise<T>;
|
|
42
44
|
declare function runWithUnifiedStateMutation<T>(mutate: (ctx: UnifiedRequestContext) => void, fn: () => T | Promise<T>): T | Promise<T>;
|
|
43
45
|
/**
|
|
44
46
|
* Get the current unified request context.
|
|
@@ -44,23 +44,9 @@ function createRequestContext(opts) {
|
|
|
44
44
|
...opts
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
|
-
/**
|
|
48
|
-
* Run `fn` within a unified request context scope.
|
|
49
|
-
* All shim modules will read/write their state from `ctx` for the
|
|
50
|
-
* duration of the call, including async continuations.
|
|
51
|
-
*/
|
|
52
47
|
function runWithRequestContext(ctx, fn) {
|
|
53
48
|
return _als.run(ctx, fn);
|
|
54
49
|
}
|
|
55
|
-
/**
|
|
56
|
-
* Run `fn` in a nested unified scope derived from the current request context.
|
|
57
|
-
* Used by legacy runWith* wrappers to reset or override one sub-state while
|
|
58
|
-
* preserving proper async isolation for continuations created inside `fn`.
|
|
59
|
-
* The child scope is a shallow clone of the parent store, so untouched fields
|
|
60
|
-
* keep sharing their existing references while overridden slices can be reset.
|
|
61
|
-
*
|
|
62
|
-
* @internal
|
|
63
|
-
*/
|
|
64
50
|
function runWithUnifiedStateMutation(mutate, fn) {
|
|
65
51
|
const parentCtx = _als.getStore();
|
|
66
52
|
if (!parentCtx) return fn();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unified-request-context.js","names":[],"sources":["../../src/shims/unified-request-context.ts"],"sourcesContent":["/**\n * Unified per-request context backed by a single AsyncLocalStorage.\n *\n * Consolidates the 5–6 nested ALS scopes that previously wrapped every\n * App Router request (headers, navigation, cache-state, private-cache,\n * fetch-cache, execution-context) into one flat store.\n *\n * Each shim module checks `isInsideUnifiedScope()` and reads its sub-fields\n * from the unified store, falling back to its own standalone ALS when\n * outside (SSR environment, Pages Router, tests).\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type {\n CacheState,\n ExecutionContextLike,\n FetchCacheState,\n HeadState,\n I18nState,\n NavigationState,\n PrivateCacheState,\n RouterState,\n VinextHeadersShimState,\n} from \"./request-state-types.js\";\n\n// ---------------------------------------------------------------------------\n// Unified context shape\n// ---------------------------------------------------------------------------\n\n/**\n * Flat union of all per-request state previously spread across\n * VinextHeadersShimState, NavigationState, CacheState, PrivateCacheState,\n * FetchCacheState, and ExecutionContextLike.\n *\n * Each field group is documented with its source shim module.\n */\nexport type UnifiedRequestContext = {\n // ── request-context.ts ─────────────────────────────────────────────\n /** Cloudflare Workers ExecutionContext, or null on Node.js dev. */\n executionContext: ExecutionContextLike | null;\n\n // ── cache-for-request.ts ──────────────────────────────────────────\n /** Per-request cache for cacheForRequest(). Keyed by factory function reference. */\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n requestCache: WeakMap<(...args: any[]) => any, unknown>;\n} & VinextHeadersShimState &\n I18nState &\n NavigationState &\n CacheState &\n PrivateCacheState &\n FetchCacheState &\n RouterState &\n HeadState;\n\n// ---------------------------------------------------------------------------\n// ALS setup — stored on globalThis via Symbol.for so all Vite environments\n// (RSC/SSR/client) share the same instance.\n// ---------------------------------------------------------------------------\n\nconst _ALS_KEY = Symbol.for(\"vinext.unifiedRequestContext.als\");\nconst _REQUEST_CONTEXT_ALS_KEY = Symbol.for(\"vinext.requestContext.als\");\nconst _g = globalThis as unknown as Record<PropertyKey, unknown>;\nconst _als = (_g[_ALS_KEY] ??=\n new AsyncLocalStorage<UnifiedRequestContext>()) as AsyncLocalStorage<UnifiedRequestContext>;\n\nfunction _getInheritedExecutionContext(): ExecutionContextLike | null {\n const unifiedStore = _als.getStore();\n if (unifiedStore) return unifiedStore.executionContext;\n\n const executionContextAls = _g[_REQUEST_CONTEXT_ALS_KEY] as\n | AsyncLocalStorage<ExecutionContextLike | null>\n | undefined;\n return executionContextAls?.getStore() ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a fresh `UnifiedRequestContext` with defaults for all fields.\n * Pass partial overrides for the fields you need to pre-populate.\n */\nexport function createRequestContext(opts?: Partial<UnifiedRequestContext>): UnifiedRequestContext {\n return {\n headersContext: null,\n dynamicUsageDetected: false,\n pendingSetCookies: [],\n draftModeCookieHeader: null,\n phase: \"render\",\n i18nContext: null,\n serverContext: null,\n serverInsertedHTMLCallbacks: [],\n requestScopedCacheLife: null,\n _privateCache: null,\n currentRequestTags: [],\n executionContext: _getInheritedExecutionContext(), // inherits from standalone ALS if present\n requestCache: new WeakMap(),\n ssrContext: null,\n ssrHeadChildren: [],\n ...opts,\n };\n}\n\n/**\n * Run `fn` within a unified request context scope.\n * All shim modules will read/write their state from `ctx` for the\n * duration of the call, including async continuations.\n */\nexport function runWithRequestContext<T>(\n ctx: UnifiedRequestContext,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n return _als.run(ctx, fn);\n}\n\n/**\n * Run `fn` in a nested unified scope derived from the current request context.\n * Used by legacy runWith* wrappers to reset or override one sub-state while\n * preserving proper async isolation for continuations created inside `fn`.\n * The child scope is a shallow clone of the parent store, so untouched fields\n * keep sharing their existing references while overridden slices can be reset.\n *\n * @internal\n */\nexport function runWithUnifiedStateMutation<T>(\n mutate: (ctx: UnifiedRequestContext) => void,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n const parentCtx = _als.getStore();\n if (!parentCtx) return fn();\n\n const childCtx = { ...parentCtx };\n // NOTE: This is a shallow clone. Array fields (pendingSetCookies,\n // serverInsertedHTMLCallbacks, currentRequestTags, ssrHeadChildren), the\n // _privateCache Map, requestCache WeakMap, and object fields (headersContext,\n // i18nContext, serverContext, ssrContext, executionContext,\n // requestScopedCacheLife) still share references with the parent until\n // replaced. requestCache is intentionally shared — nested scopes within\n // the same request should see the same cached values. The mutate\n // callback must replace those reference-typed slices (for example\n // `ctx.currentRequestTags = []`) rather than mutating them in-place (for\n // example `ctx.currentRequestTags.push(...)`) or the parent scope will\n // observe those changes too. Keep this enumeration in sync with\n // UnifiedRequestContext: when adding a new reference-typed field, add it\n // here too and verify callers still follow the replace-not-mutate rule.\n mutate(childCtx);\n return _als.run(childCtx, fn);\n}\n\n/**\n * Get the current unified request context.\n * Returns the ALS store when inside a `runWithRequestContext()` scope,\n * or a fresh detached context otherwise. Unlike the legacy per-shim fallback\n * singletons, this detached value is ephemeral — mutations do not persist\n * across calls. This is intentional to prevent state leakage outside request\n * scopes.\n *\n * Only direct callers observe this detached fallback. Shim `_getState()`\n * helpers should continue to gate on `isInsideUnifiedScope()` and fall back\n * to their standalone ALS/fallback singletons outside the unified scope.\n * If called inside a standalone `runWithExecutionContext()` scope, the\n * detached context still reflects that inherited `executionContext`.\n */\nexport function getRequestContext(): UnifiedRequestContext {\n return _als.getStore() ?? createRequestContext();\n}\n\n/**\n * Check whether the current execution is inside a `runWithRequestContext()` scope.\n * Shim modules use this to decide whether to read from the unified store\n * or fall back to their own standalone ALS.\n */\nexport function isInsideUnifiedScope(): boolean {\n return _als.getStore() != null;\n}\n"],"mappings":";;;;;;;;;;;;;AA2DA,MAAM,WAAW,OAAO,IAAI,mCAAmC;AAC/D,MAAM,2BAA2B,OAAO,IAAI,4BAA4B;AACxE,MAAM,KAAK;AACX,MAAM,OAAQ,GAAG,cACf,IAAI,mBAA0C;AAEhD,SAAS,gCAA6D;CACpE,MAAM,eAAe,KAAK,UAAU;AACpC,KAAI,aAAc,QAAO,aAAa;AAKtC,QAH4B,GAAG,2BAGH,UAAU,IAAI;;;;;;AAW5C,SAAgB,qBAAqB,MAA8D;AACjG,QAAO;EACL,gBAAgB;EAChB,sBAAsB;EACtB,mBAAmB,EAAE;EACrB,uBAAuB;EACvB,OAAO;EACP,aAAa;EACb,eAAe;EACf,6BAA6B,EAAE;EAC/B,wBAAwB;EACxB,eAAe;EACf,oBAAoB,EAAE;EACtB,kBAAkB,+BAA+B;EACjD,8BAAc,IAAI,SAAS;EAC3B,YAAY;EACZ,iBAAiB,EAAE;EACnB,GAAG;EACJ
|
|
1
|
+
{"version":3,"file":"unified-request-context.js","names":[],"sources":["../../src/shims/unified-request-context.ts"],"sourcesContent":["/**\n * Unified per-request context backed by a single AsyncLocalStorage.\n *\n * Consolidates the 5–6 nested ALS scopes that previously wrapped every\n * App Router request (headers, navigation, cache-state, private-cache,\n * fetch-cache, execution-context) into one flat store.\n *\n * Each shim module checks `isInsideUnifiedScope()` and reads its sub-fields\n * from the unified store, falling back to its own standalone ALS when\n * outside (SSR environment, Pages Router, tests).\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type {\n CacheState,\n ExecutionContextLike,\n FetchCacheState,\n HeadState,\n I18nState,\n NavigationState,\n PrivateCacheState,\n RouterState,\n VinextHeadersShimState,\n} from \"./request-state-types.js\";\n\n// ---------------------------------------------------------------------------\n// Unified context shape\n// ---------------------------------------------------------------------------\n\n/**\n * Flat union of all per-request state previously spread across\n * VinextHeadersShimState, NavigationState, CacheState, PrivateCacheState,\n * FetchCacheState, and ExecutionContextLike.\n *\n * Each field group is documented with its source shim module.\n */\nexport type UnifiedRequestContext = {\n // ── request-context.ts ─────────────────────────────────────────────\n /** Cloudflare Workers ExecutionContext, or null on Node.js dev. */\n executionContext: ExecutionContextLike | null;\n\n // ── cache-for-request.ts ──────────────────────────────────────────\n /** Per-request cache for cacheForRequest(). Keyed by factory function reference. */\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n requestCache: WeakMap<(...args: any[]) => any, unknown>;\n} & VinextHeadersShimState &\n I18nState &\n NavigationState &\n CacheState &\n PrivateCacheState &\n FetchCacheState &\n RouterState &\n HeadState;\n\n// ---------------------------------------------------------------------------\n// ALS setup — stored on globalThis via Symbol.for so all Vite environments\n// (RSC/SSR/client) share the same instance.\n// ---------------------------------------------------------------------------\n\nconst _ALS_KEY = Symbol.for(\"vinext.unifiedRequestContext.als\");\nconst _REQUEST_CONTEXT_ALS_KEY = Symbol.for(\"vinext.requestContext.als\");\nconst _g = globalThis as unknown as Record<PropertyKey, unknown>;\nconst _als = (_g[_ALS_KEY] ??=\n new AsyncLocalStorage<UnifiedRequestContext>()) as AsyncLocalStorage<UnifiedRequestContext>;\n\nfunction _getInheritedExecutionContext(): ExecutionContextLike | null {\n const unifiedStore = _als.getStore();\n if (unifiedStore) return unifiedStore.executionContext;\n\n const executionContextAls = _g[_REQUEST_CONTEXT_ALS_KEY] as\n | AsyncLocalStorage<ExecutionContextLike | null>\n | undefined;\n return executionContextAls?.getStore() ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a fresh `UnifiedRequestContext` with defaults for all fields.\n * Pass partial overrides for the fields you need to pre-populate.\n */\nexport function createRequestContext(opts?: Partial<UnifiedRequestContext>): UnifiedRequestContext {\n return {\n headersContext: null,\n dynamicUsageDetected: false,\n pendingSetCookies: [],\n draftModeCookieHeader: null,\n phase: \"render\",\n i18nContext: null,\n serverContext: null,\n serverInsertedHTMLCallbacks: [],\n requestScopedCacheLife: null,\n _privateCache: null,\n currentRequestTags: [],\n executionContext: _getInheritedExecutionContext(), // inherits from standalone ALS if present\n requestCache: new WeakMap(),\n ssrContext: null,\n ssrHeadChildren: [],\n ...opts,\n };\n}\n\n/**\n * Run `fn` within a unified request context scope.\n * All shim modules will read/write their state from `ctx` for the\n * duration of the call, including async continuations.\n */\nexport function runWithRequestContext<T>(\n ctx: UnifiedRequestContext,\n fn: () => Promise<T>,\n): Promise<T>;\nexport function runWithRequestContext<T>(\n ctx: UnifiedRequestContext,\n fn: () => T | Promise<T>,\n): T | Promise<T>;\nexport function runWithRequestContext<T>(\n ctx: UnifiedRequestContext,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n return _als.run(ctx, fn);\n}\n\n/**\n * Run `fn` in a nested unified scope derived from the current request context.\n * Used by legacy runWith* wrappers to reset or override one sub-state while\n * preserving proper async isolation for continuations created inside `fn`.\n * The child scope is a shallow clone of the parent store, so untouched fields\n * keep sharing their existing references while overridden slices can be reset.\n *\n * @internal\n */\nexport function runWithUnifiedStateMutation<T>(\n mutate: (ctx: UnifiedRequestContext) => void,\n fn: () => Promise<T>,\n): Promise<T>;\nexport function runWithUnifiedStateMutation<T>(\n mutate: (ctx: UnifiedRequestContext) => void,\n fn: () => T | Promise<T>,\n): T | Promise<T>;\nexport function runWithUnifiedStateMutation<T>(\n mutate: (ctx: UnifiedRequestContext) => void,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n const parentCtx = _als.getStore();\n if (!parentCtx) return fn();\n\n const childCtx = { ...parentCtx };\n // NOTE: This is a shallow clone. Array fields (pendingSetCookies,\n // serverInsertedHTMLCallbacks, currentRequestTags, ssrHeadChildren), the\n // _privateCache Map, requestCache WeakMap, and object fields (headersContext,\n // i18nContext, serverContext, ssrContext, executionContext,\n // requestScopedCacheLife) still share references with the parent until\n // replaced. requestCache is intentionally shared — nested scopes within\n // the same request should see the same cached values. The mutate\n // callback must replace those reference-typed slices (for example\n // `ctx.currentRequestTags = []`) rather than mutating them in-place (for\n // example `ctx.currentRequestTags.push(...)`) or the parent scope will\n // observe those changes too. Keep this enumeration in sync with\n // UnifiedRequestContext: when adding a new reference-typed field, add it\n // here too and verify callers still follow the replace-not-mutate rule.\n mutate(childCtx);\n return _als.run(childCtx, fn);\n}\n\n/**\n * Get the current unified request context.\n * Returns the ALS store when inside a `runWithRequestContext()` scope,\n * or a fresh detached context otherwise. Unlike the legacy per-shim fallback\n * singletons, this detached value is ephemeral — mutations do not persist\n * across calls. This is intentional to prevent state leakage outside request\n * scopes.\n *\n * Only direct callers observe this detached fallback. Shim `_getState()`\n * helpers should continue to gate on `isInsideUnifiedScope()` and fall back\n * to their standalone ALS/fallback singletons outside the unified scope.\n * If called inside a standalone `runWithExecutionContext()` scope, the\n * detached context still reflects that inherited `executionContext`.\n */\nexport function getRequestContext(): UnifiedRequestContext {\n return _als.getStore() ?? createRequestContext();\n}\n\n/**\n * Check whether the current execution is inside a `runWithRequestContext()` scope.\n * Shim modules use this to decide whether to read from the unified store\n * or fall back to their own standalone ALS.\n */\nexport function isInsideUnifiedScope(): boolean {\n return _als.getStore() != null;\n}\n"],"mappings":";;;;;;;;;;;;;AA2DA,MAAM,WAAW,OAAO,IAAI,mCAAmC;AAC/D,MAAM,2BAA2B,OAAO,IAAI,4BAA4B;AACxE,MAAM,KAAK;AACX,MAAM,OAAQ,GAAG,cACf,IAAI,mBAA0C;AAEhD,SAAS,gCAA6D;CACpE,MAAM,eAAe,KAAK,UAAU;AACpC,KAAI,aAAc,QAAO,aAAa;AAKtC,QAH4B,GAAG,2BAGH,UAAU,IAAI;;;;;;AAW5C,SAAgB,qBAAqB,MAA8D;AACjG,QAAO;EACL,gBAAgB;EAChB,sBAAsB;EACtB,mBAAmB,EAAE;EACrB,uBAAuB;EACvB,OAAO;EACP,aAAa;EACb,eAAe;EACf,6BAA6B,EAAE;EAC/B,wBAAwB;EACxB,eAAe;EACf,oBAAoB,EAAE;EACtB,kBAAkB,+BAA+B;EACjD,8BAAc,IAAI,SAAS;EAC3B,YAAY;EACZ,iBAAiB,EAAE;EACnB,GAAG;EACJ;;AAgBH,SAAgB,sBACd,KACA,IACgB;AAChB,QAAO,KAAK,IAAI,KAAK,GAAG;;AAoB1B,SAAgB,4BACd,QACA,IACgB;CAChB,MAAM,YAAY,KAAK,UAAU;AACjC,KAAI,CAAC,UAAW,QAAO,IAAI;CAE3B,MAAM,WAAW,EAAE,GAAG,WAAW;AAcjC,QAAO,SAAS;AAChB,QAAO,KAAK,IAAI,UAAU,GAAG;;;;;;;;;;;;;;;;AAiB/B,SAAgB,oBAA2C;AACzD,QAAO,KAAK,UAAU,IAAI,sBAAsB;;;;;;;AAQlD,SAAgB,uBAAgC;AAC9C,QAAO,KAAK,UAAU,IAAI"}
|