vinext 0.0.29 → 0.0.30
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/dist/check.d.ts.map +1 -1
- package/dist/check.js +11 -7
- package/dist/check.js.map +1 -1
- package/dist/cloudflare/kv-cache-handler.d.ts.map +1 -1
- package/dist/cloudflare/kv-cache-handler.js +44 -30
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +1 -1
- package/dist/entries/app-rsc-entry.d.ts.map +1 -1
- package/dist/entries/app-rsc-entry.js +208 -164
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.d.ts.map +1 -1
- package/dist/entries/pages-server-entry.js +151 -100
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/routing/app-router.d.ts.map +1 -1
- package/dist/routing/app-router.js +43 -29
- package/dist/routing/app-router.js.map +1 -1
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/dev-server.d.ts +2 -1
- package/dist/server/dev-server.d.ts.map +1 -1
- package/dist/server/dev-server.js +163 -163
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/image-optimization.d.ts.map +1 -1
- package/dist/server/image-optimization.js +23 -11
- package/dist/server/image-optimization.js.map +1 -1
- package/dist/server/isr-cache.d.ts.map +1 -1
- package/dist/server/isr-cache.js +8 -3
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/metadata-routes.d.ts.map +1 -1
- package/dist/server/metadata-routes.js +56 -18
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-codegen.d.ts.map +1 -1
- package/dist/server/middleware-codegen.js +37 -4
- package/dist/server/middleware-codegen.js.map +1 -1
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +50 -6
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/pages-i18n.d.ts +50 -0
- package/dist/server/pages-i18n.d.ts.map +1 -0
- package/dist/server/pages-i18n.js +152 -0
- package/dist/server/pages-i18n.js.map +1 -0
- package/dist/shims/cache-runtime.d.ts +3 -0
- package/dist/shims/cache-runtime.d.ts.map +1 -1
- package/dist/shims/cache-runtime.js +22 -5
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +3 -0
- package/dist/shims/cache.d.ts.map +1 -1
- package/dist/shims/cache.js +21 -12
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/constants.d.ts.map +1 -1
- package/dist/shims/constants.js +0 -1
- package/dist/shims/constants.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts +14 -0
- package/dist/shims/fetch-cache.d.ts.map +1 -1
- package/dist/shims/fetch-cache.js +102 -37
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/head-state.d.ts +4 -0
- package/dist/shims/head-state.d.ts.map +1 -1
- package/dist/shims/head-state.js +14 -11
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/head.d.ts +4 -2
- package/dist/shims/head.d.ts.map +1 -1
- package/dist/shims/head.js +162 -52
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/headers.d.ts +8 -1
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/headers.js +21 -29
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/i18n-context.d.ts +27 -0
- package/dist/shims/i18n-context.d.ts.map +1 -0
- package/dist/shims/i18n-context.js +57 -0
- package/dist/shims/i18n-context.js.map +1 -0
- package/dist/shims/i18n-state.d.ts +20 -0
- package/dist/shims/i18n-state.d.ts.map +1 -0
- package/dist/shims/i18n-state.js +53 -0
- package/dist/shims/i18n-state.js.map +1 -0
- package/dist/shims/image.d.ts +2 -0
- package/dist/shims/image.d.ts.map +1 -1
- package/dist/shims/image.js +14 -6
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/utils.d.ts +1 -0
- package/dist/shims/internal/utils.d.ts.map +1 -1
- package/dist/shims/internal/utils.js.map +1 -1
- package/dist/shims/link.d.ts.map +1 -1
- package/dist/shims/link.js +27 -11
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +22 -22
- package/dist/shims/metadata.d.ts.map +1 -1
- package/dist/shims/metadata.js +34 -32
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation-state.d.ts +14 -0
- package/dist/shims/navigation-state.d.ts.map +1 -1
- package/dist/shims/navigation-state.js +33 -15
- package/dist/shims/navigation-state.js.map +1 -1
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/shims/navigation.js +39 -22
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/request-context.d.ts.map +1 -1
- package/dist/shims/request-context.js +9 -0
- package/dist/shims/request-context.js.map +1 -1
- package/dist/shims/request-state-types.d.ts +11 -0
- package/dist/shims/request-state-types.d.ts.map +1 -0
- package/dist/shims/request-state-types.js +2 -0
- package/dist/shims/request-state-types.js.map +1 -0
- package/dist/shims/router-state.d.ts +11 -0
- package/dist/shims/router-state.d.ts.map +1 -1
- package/dist/shims/router-state.js +10 -8
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/router.d.ts +4 -0
- package/dist/shims/router.d.ts.map +1 -1
- package/dist/shims/router.js +117 -21
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/server.d.ts +8 -1
- package/dist/shims/server.d.ts.map +1 -1
- package/dist/shims/server.js +52 -6
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/unified-request-context.d.ts +66 -0
- package/dist/shims/unified-request-context.d.ts.map +1 -0
- package/dist/shims/unified-request-context.js +116 -0
- package/dist/shims/unified-request-context.js.map +1 -0
- package/dist/utils/domain-locale.d.ts +18 -0
- package/dist/utils/domain-locale.d.ts.map +1 -0
- package/dist/utils/domain-locale.js +64 -0
- package/dist/utils/domain-locale.js.map +1 -0
- package/package.json +2 -2
package/dist/shims/head.js
CHANGED
|
@@ -4,23 +4,25 @@
|
|
|
4
4
|
* In the Pages Router, <Head> manages document <head> elements.
|
|
5
5
|
* - On the server: collects elements into a module-level array that the
|
|
6
6
|
* dev-server reads after render and injects into the HTML <head>.
|
|
7
|
-
* - On the client:
|
|
7
|
+
* - On the client: reduces all mounted <Head> instances into one deduped
|
|
8
|
+
* document.head projection and applies it with DOM manipulation.
|
|
8
9
|
*/
|
|
9
|
-
import { useEffect, Children, isValidElement } from "react";
|
|
10
|
+
import React, { useEffect, useRef, Children, isValidElement } from "react";
|
|
10
11
|
// --- SSR head collection ---
|
|
11
12
|
// State uses a registration pattern so this module can be bundled for the
|
|
12
13
|
// browser. The ALS-backed implementation lives in head-state.ts (server-only).
|
|
13
|
-
let
|
|
14
|
-
|
|
14
|
+
let _ssrHeadChildren = [];
|
|
15
|
+
const _clientHeadChildren = new Map();
|
|
16
|
+
let _getSSRHeadChildren = () => _ssrHeadChildren;
|
|
15
17
|
let _resetSSRHeadImpl = () => {
|
|
16
|
-
|
|
18
|
+
_ssrHeadChildren = [];
|
|
17
19
|
};
|
|
18
20
|
/**
|
|
19
21
|
* Register ALS-backed state accessors. Called by head-state.ts on import.
|
|
20
22
|
* @internal
|
|
21
23
|
*/
|
|
22
24
|
export function _registerHeadStateAccessors(accessors) {
|
|
23
|
-
|
|
25
|
+
_getSSRHeadChildren = accessors.getSSRHeadChildren;
|
|
24
26
|
_resetSSRHeadImpl = accessors.resetSSRHead;
|
|
25
27
|
}
|
|
26
28
|
/** Reset the SSR head collector. Call before render. */
|
|
@@ -29,13 +31,126 @@ export function resetSSRHead() {
|
|
|
29
31
|
}
|
|
30
32
|
/** Get collected head HTML. Call after render. */
|
|
31
33
|
export function getSSRHeadHTML() {
|
|
32
|
-
return
|
|
34
|
+
return reduceHeadChildren(_getSSRHeadChildren())
|
|
35
|
+
.map(reactElementToHTML)
|
|
36
|
+
.filter(Boolean)
|
|
37
|
+
.join("\n ");
|
|
33
38
|
}
|
|
34
39
|
/**
|
|
35
40
|
* Tags allowed inside <head>. Anything else is silently dropped.
|
|
36
41
|
* This prevents injection of dangerous elements like <iframe>, <object>, etc.
|
|
37
42
|
*/
|
|
38
43
|
const ALLOWED_HEAD_TAGS = new Set(["title", "meta", "link", "style", "script", "base", "noscript"]);
|
|
44
|
+
const META_TYPES = ["name", "httpEquiv", "charSet", "itemProp"];
|
|
45
|
+
function warnDisallowedHeadTag(tag) {
|
|
46
|
+
if (process.env.NODE_ENV !== "production") {
|
|
47
|
+
console.warn(`[vinext] <Head> ignoring disallowed tag <${tag}>. ` +
|
|
48
|
+
`Only ${[...ALLOWED_HEAD_TAGS].join(", ")} are allowed.`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function collectHeadElements(list, child) {
|
|
52
|
+
if (child == null ||
|
|
53
|
+
typeof child === "boolean" ||
|
|
54
|
+
typeof child === "string" ||
|
|
55
|
+
typeof child === "number") {
|
|
56
|
+
return list;
|
|
57
|
+
}
|
|
58
|
+
if (!isValidElement(child)) {
|
|
59
|
+
return list;
|
|
60
|
+
}
|
|
61
|
+
if (child.type === React.Fragment) {
|
|
62
|
+
return Children.toArray(child.props.children).reduce(collectHeadElements, list);
|
|
63
|
+
}
|
|
64
|
+
if (typeof child.type !== "string") {
|
|
65
|
+
return list;
|
|
66
|
+
}
|
|
67
|
+
if (!ALLOWED_HEAD_TAGS.has(child.type)) {
|
|
68
|
+
warnDisallowedHeadTag(child.type);
|
|
69
|
+
return list;
|
|
70
|
+
}
|
|
71
|
+
return list.concat(child);
|
|
72
|
+
}
|
|
73
|
+
function normalizeHeadKey(key) {
|
|
74
|
+
if (key == null || typeof key === "number")
|
|
75
|
+
return null;
|
|
76
|
+
const normalizedKey = String(key);
|
|
77
|
+
const separatorIndex = normalizedKey.indexOf("$");
|
|
78
|
+
return separatorIndex > 0 ? normalizedKey.slice(separatorIndex + 1) : null;
|
|
79
|
+
}
|
|
80
|
+
function createUniqueHeadFilter() {
|
|
81
|
+
const keys = new Set();
|
|
82
|
+
const tags = new Set();
|
|
83
|
+
const metaTypes = new Set();
|
|
84
|
+
const metaCategories = new Map();
|
|
85
|
+
return (child) => {
|
|
86
|
+
let isUnique = true;
|
|
87
|
+
const normalizedKey = normalizeHeadKey(child.key);
|
|
88
|
+
const hasKey = normalizedKey !== null;
|
|
89
|
+
if (normalizedKey) {
|
|
90
|
+
if (keys.has(normalizedKey)) {
|
|
91
|
+
isUnique = false;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
keys.add(normalizedKey);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
switch (child.type) {
|
|
98
|
+
case "title":
|
|
99
|
+
case "base":
|
|
100
|
+
if (tags.has(child.type)) {
|
|
101
|
+
isUnique = false;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
tags.add(child.type);
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
case "meta": {
|
|
108
|
+
const props = child.props;
|
|
109
|
+
for (const metaType of META_TYPES) {
|
|
110
|
+
if (!Object.prototype.hasOwnProperty.call(props, metaType))
|
|
111
|
+
continue;
|
|
112
|
+
if (metaType === "charSet") {
|
|
113
|
+
if (metaTypes.has(metaType)) {
|
|
114
|
+
isUnique = false;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
metaTypes.add(metaType);
|
|
118
|
+
}
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const category = props[metaType];
|
|
122
|
+
if (typeof category !== "string")
|
|
123
|
+
continue;
|
|
124
|
+
let categories = metaCategories.get(metaType);
|
|
125
|
+
if (!categories) {
|
|
126
|
+
categories = new Set();
|
|
127
|
+
metaCategories.set(metaType, categories);
|
|
128
|
+
}
|
|
129
|
+
if ((metaType !== "name" || !hasKey) && categories.has(category)) {
|
|
130
|
+
isUnique = false;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
categories.add(category);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
default:
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
return isUnique;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
export function reduceHeadChildren(headChildren) {
|
|
145
|
+
return headChildren
|
|
146
|
+
.reduce((flattenedChildren, child) => {
|
|
147
|
+
return flattenedChildren.concat(Children.toArray(child));
|
|
148
|
+
}, [])
|
|
149
|
+
.reduce(collectHeadElements, [])
|
|
150
|
+
.reverse()
|
|
151
|
+
.filter(createUniqueHeadFilter())
|
|
152
|
+
.reverse();
|
|
153
|
+
}
|
|
39
154
|
/**
|
|
40
155
|
* Convert a React element to an HTML string for SSR head injection.
|
|
41
156
|
* Returns an empty string for disallowed tag types.
|
|
@@ -43,10 +158,7 @@ const ALLOWED_HEAD_TAGS = new Set(["title", "meta", "link", "style", "script", "
|
|
|
43
158
|
function reactElementToHTML(child) {
|
|
44
159
|
const tag = child.type;
|
|
45
160
|
if (!ALLOWED_HEAD_TAGS.has(tag)) {
|
|
46
|
-
|
|
47
|
-
console.warn(`[vinext] <Head> ignoring disallowed tag <${tag}>. ` +
|
|
48
|
-
`Only ${[...ALLOWED_HEAD_TAGS].join(", ")} are allowed.`);
|
|
49
|
-
}
|
|
161
|
+
warnDisallowedHeadTag(tag);
|
|
50
162
|
return "";
|
|
51
163
|
}
|
|
52
164
|
const props = child.props;
|
|
@@ -116,56 +228,54 @@ export function escapeInlineContent(content, tag) {
|
|
|
116
228
|
const pattern = new RegExp(`<\\/(${tag})`, "gi");
|
|
117
229
|
return content.replace(pattern, "<\\/$1");
|
|
118
230
|
}
|
|
231
|
+
function syncClientHead() {
|
|
232
|
+
document.querySelectorAll("[data-vinext-head]").forEach((el) => el.remove());
|
|
233
|
+
for (const child of reduceHeadChildren([..._clientHeadChildren.values()])) {
|
|
234
|
+
if (typeof child.type !== "string")
|
|
235
|
+
continue;
|
|
236
|
+
const domEl = document.createElement(child.type);
|
|
237
|
+
const props = child.props;
|
|
238
|
+
for (const [key, value] of Object.entries(props)) {
|
|
239
|
+
if (key === "children" && typeof value === "string") {
|
|
240
|
+
domEl.textContent = value;
|
|
241
|
+
}
|
|
242
|
+
else if (key === "dangerouslySetInnerHTML") {
|
|
243
|
+
// skip for safety
|
|
244
|
+
}
|
|
245
|
+
else if (key === "className") {
|
|
246
|
+
domEl.setAttribute("class", String(value));
|
|
247
|
+
}
|
|
248
|
+
else if (typeof value === "boolean" && value) {
|
|
249
|
+
domEl.setAttribute(key, "");
|
|
250
|
+
}
|
|
251
|
+
else if (key !== "children" && typeof value === "string") {
|
|
252
|
+
domEl.setAttribute(key, value);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
domEl.setAttribute("data-vinext-head", "true");
|
|
256
|
+
document.head.appendChild(domEl);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
119
259
|
// --- Component ---
|
|
120
260
|
function Head({ children }) {
|
|
261
|
+
const headInstanceIdRef = useRef(null);
|
|
262
|
+
if (headInstanceIdRef.current === null) {
|
|
263
|
+
headInstanceIdRef.current = Symbol("vinext-head");
|
|
264
|
+
}
|
|
121
265
|
// SSR path: collect elements for later injection
|
|
122
266
|
if (typeof window === "undefined") {
|
|
123
|
-
|
|
124
|
-
if (!isValidElement(child))
|
|
125
|
-
return;
|
|
126
|
-
if (typeof child.type !== "string")
|
|
127
|
-
return;
|
|
128
|
-
const html = reactElementToHTML(child);
|
|
129
|
-
if (html)
|
|
130
|
-
_getSSRHeadElements().push(html);
|
|
131
|
-
});
|
|
267
|
+
_getSSRHeadChildren().push(children);
|
|
132
268
|
return null;
|
|
133
269
|
}
|
|
134
|
-
// Client path:
|
|
270
|
+
// Client path: update the shared head projection after hydration.
|
|
135
271
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
136
272
|
useEffect(() => {
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
Children.forEach(children, (child) => {
|
|
141
|
-
if (!isValidElement(child))
|
|
142
|
-
return;
|
|
143
|
-
if (typeof child.type !== "string")
|
|
144
|
-
return;
|
|
145
|
-
if (!ALLOWED_HEAD_TAGS.has(child.type))
|
|
146
|
-
return;
|
|
147
|
-
const domEl = document.createElement(child.type);
|
|
148
|
-
const props = child.props;
|
|
149
|
-
for (const [key, value] of Object.entries(props)) {
|
|
150
|
-
if (key === "children" && typeof value === "string") {
|
|
151
|
-
domEl.textContent = value;
|
|
152
|
-
}
|
|
153
|
-
else if (key === "dangerouslySetInnerHTML") {
|
|
154
|
-
// skip for safety
|
|
155
|
-
}
|
|
156
|
-
else if (key === "className") {
|
|
157
|
-
domEl.setAttribute("class", String(value));
|
|
158
|
-
}
|
|
159
|
-
else if (key !== "children" && typeof value === "string") {
|
|
160
|
-
domEl.setAttribute(key, value);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
domEl.setAttribute("data-vinext-head", "true");
|
|
164
|
-
document.head.appendChild(domEl);
|
|
165
|
-
elements.push(domEl);
|
|
166
|
-
});
|
|
273
|
+
const instanceId = headInstanceIdRef.current;
|
|
274
|
+
_clientHeadChildren.set(instanceId, children);
|
|
275
|
+
syncClientHead();
|
|
167
276
|
return () => {
|
|
168
|
-
|
|
277
|
+
_clientHeadChildren.delete(instanceId);
|
|
278
|
+
syncClientHead();
|
|
169
279
|
};
|
|
170
280
|
}, [children]);
|
|
171
281
|
return null;
|
package/dist/shims/head.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"head.js","sourceRoot":"","sources":["../../src/shims/head.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * next/head shim\n *\n * In the Pages Router, <Head> manages document <head> elements.\n * - On the server: collects elements into a module-level array that the\n * dev-server reads after render and injects into the HTML <head>.\n * - On the client: uses useEffect + DOM manipulation.\n */\nimport React, { useEffect, Children, isValidElement } from \"react\";\n\ninterface HeadProps {\n children?: React.ReactNode;\n}\n\n// --- SSR head collection ---\n// State uses a registration pattern so this module can be bundled for the\n// browser. The ALS-backed implementation lives in head-state.ts (server-only).\n\nlet _ssrHeadElements: string[] = [];\n\nlet _getSSRHeadElements = (): string[] => _ssrHeadElements;\nlet _resetSSRHeadImpl = (): void => {\n _ssrHeadElements = [];\n};\n\n/**\n * Register ALS-backed state accessors. Called by head-state.ts on import.\n * @internal\n */\nexport function _registerHeadStateAccessors(accessors: {\n getSSRHeadElements: () => string[];\n resetSSRHead: () => void;\n}): void {\n _getSSRHeadElements = accessors.getSSRHeadElements;\n _resetSSRHeadImpl = accessors.resetSSRHead;\n}\n\n/** Reset the SSR head collector. Call before render. */\nexport function resetSSRHead(): void {\n _resetSSRHeadImpl();\n}\n\n/** Get collected head HTML. Call after render. */\nexport function getSSRHeadHTML(): string {\n return _getSSRHeadElements().join(\"\\n \");\n}\n\n/**\n * Tags allowed inside <head>. Anything else is silently dropped.\n * This prevents injection of dangerous elements like <iframe>, <object>, etc.\n */\nconst ALLOWED_HEAD_TAGS = new Set([\"title\", \"meta\", \"link\", \"style\", \"script\", \"base\", \"noscript\"]);\n\n/**\n * Convert a React element to an HTML string for SSR head injection.\n * Returns an empty string for disallowed tag types.\n */\nfunction reactElementToHTML(child: React.ReactElement): string {\n const tag = child.type as string;\n\n if (!ALLOWED_HEAD_TAGS.has(tag)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `[vinext] <Head> ignoring disallowed tag <${tag}>. ` +\n `Only ${[...ALLOWED_HEAD_TAGS].join(\", \")} are allowed.`,\n );\n }\n return \"\";\n }\n\n const props = child.props as Record<string, unknown>;\n const attrs: string[] = [];\n let innerHTML = \"\";\n\n for (const [key, value] of Object.entries(props)) {\n if (key === \"children\") {\n if (typeof value === \"string\") {\n innerHTML = escapeHTML(value);\n }\n } else if (key === \"dangerouslySetInnerHTML\") {\n // Intentionally raw — developer explicitly opted in.\n // SECURITY NOTE: This injects raw HTML during SSR. The client-side\n // path (line ~148) skips dangerouslySetInnerHTML for safety. Developers\n // must never pass unsanitized user input here — it is a stored XSS vector.\n const html = value as { __html: string };\n if (html?.__html) innerHTML = html.__html;\n } else if (key === \"className\") {\n attrs.push(`class=\"${escapeAttr(String(value))}\"`);\n } else if (typeof value === \"string\") {\n attrs.push(`${key}=\"${escapeAttr(value)}\"`);\n } else if (typeof value === \"boolean\" && value) {\n attrs.push(key);\n }\n }\n\n const attrStr = attrs.length ? \" \" + attrs.join(\" \") : \"\";\n\n // Self-closing tags\n const selfClosing = [\"meta\", \"link\", \"base\"];\n if (selfClosing.includes(tag)) {\n return `<${tag}${attrStr} data-vinext-head=\"true\" />`;\n }\n\n // For raw-content tags (script, style), escape closing-tag sequences so the\n // HTML parser doesn't prematurely terminate the element.\n const rawContentTags = [\"script\", \"style\"];\n if (rawContentTags.includes(tag) && innerHTML) {\n innerHTML = escapeInlineContent(innerHTML, tag);\n }\n\n return `<${tag}${attrStr} data-vinext-head=\"true\">${innerHTML}</${tag}>`;\n}\n\nfunction escapeHTML(s: string): string {\n return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n\nexport function escapeAttr(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/\"/g, \""\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n}\n\n/**\n * Escape content that will be placed inside a raw <script> or <style> tag\n * during SSR. The HTML parser treats `</script>` (or `</style>`) as the end\n * of the block regardless of JavaScript string context, so any occurrence\n * of `</` followed by the tag name must be escaped.\n *\n * We replace `</script` and `</style` (case-insensitive) with `<\\/script`\n * and `<\\/style` respectively. The `<\\/` form is harmless in JS/CSS string\n * context but prevents the HTML parser from seeing a closing tag.\n */\nexport function escapeInlineContent(content: string, tag: string): string {\n // Build a pattern like `<\\/script` or `<\\/style`, case-insensitive\n const pattern = new RegExp(`<\\\\/(${tag})`, \"gi\");\n return content.replace(pattern, \"<\\\\/$1\");\n}\n\n// --- Component ---\n\nfunction Head({ children }: HeadProps): null {\n // SSR path: collect elements for later injection\n if (typeof window === \"undefined\") {\n Children.forEach(children, (child) => {\n if (!isValidElement(child)) return;\n if (typeof child.type !== \"string\") return;\n const html = reactElementToHTML(child);\n if (html) _getSSRHeadElements().push(html);\n });\n return null;\n }\n\n // Client path: useEffect DOM manipulation (runs after hydration)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useEffect(() => {\n const elements: Element[] = [];\n\n // Remove previous vinext-managed head elements\n document.querySelectorAll(\"[data-vinext-head]\").forEach((el) => el.remove());\n\n Children.forEach(children, (child) => {\n if (!isValidElement(child)) return;\n if (typeof child.type !== \"string\") return;\n if (!ALLOWED_HEAD_TAGS.has(child.type)) return;\n\n const domEl = document.createElement(child.type);\n const props = child.props as Record<string, unknown>;\n\n for (const [key, value] of Object.entries(props)) {\n if (key === \"children\" && typeof value === \"string\") {\n domEl.textContent = value;\n } else if (key === \"dangerouslySetInnerHTML\") {\n // skip for safety\n } else if (key === \"className\") {\n domEl.setAttribute(\"class\", String(value));\n } else if (key !== \"children\" && typeof value === \"string\") {\n domEl.setAttribute(key, value);\n }\n }\n\n domEl.setAttribute(\"data-vinext-head\", \"true\");\n document.head.appendChild(domEl);\n elements.push(domEl);\n });\n\n return () => {\n elements.forEach((el) => el.remove());\n };\n }, [children]);\n\n return null;\n}\n\nexport default Head;\n"]}
|
|
1
|
+
{"version":3,"file":"head.js","sourceRoot":"","sources":["../../src/shims/head.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * next/head shim\n *\n * In the Pages Router, <Head> manages document <head> elements.\n * - On the server: collects elements into a module-level array that the\n * dev-server reads after render and injects into the HTML <head>.\n * - On the client: reduces all mounted <Head> instances into one deduped\n * document.head projection and applies it with DOM manipulation.\n */\nimport React, { useEffect, useRef, Children, isValidElement } from \"react\";\n\ninterface HeadProps {\n children?: React.ReactNode;\n}\n\n// --- SSR head collection ---\n// State uses a registration pattern so this module can be bundled for the\n// browser. The ALS-backed implementation lives in head-state.ts (server-only).\n\nlet _ssrHeadChildren: React.ReactNode[] = [];\nconst _clientHeadChildren = new Map<symbol, React.ReactNode>();\n\nlet _getSSRHeadChildren = (): React.ReactNode[] => _ssrHeadChildren;\nlet _resetSSRHeadImpl = (): void => {\n _ssrHeadChildren = [];\n};\n\n/**\n * Register ALS-backed state accessors. Called by head-state.ts on import.\n * @internal\n */\nexport function _registerHeadStateAccessors(accessors: {\n getSSRHeadChildren: () => React.ReactNode[];\n resetSSRHead: () => void;\n}): void {\n _getSSRHeadChildren = accessors.getSSRHeadChildren;\n _resetSSRHeadImpl = accessors.resetSSRHead;\n}\n\n/** Reset the SSR head collector. Call before render. */\nexport function resetSSRHead(): void {\n _resetSSRHeadImpl();\n}\n\n/** Get collected head HTML. Call after render. */\nexport function getSSRHeadHTML(): string {\n return reduceHeadChildren(_getSSRHeadChildren())\n .map(reactElementToHTML)\n .filter(Boolean)\n .join(\"\\n \");\n}\n\n/**\n * Tags allowed inside <head>. Anything else is silently dropped.\n * This prevents injection of dangerous elements like <iframe>, <object>, etc.\n */\nconst ALLOWED_HEAD_TAGS = new Set([\"title\", \"meta\", \"link\", \"style\", \"script\", \"base\", \"noscript\"]);\nconst META_TYPES = [\"name\", \"httpEquiv\", \"charSet\", \"itemProp\"] as const;\n\nfunction warnDisallowedHeadTag(tag: string): void {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `[vinext] <Head> ignoring disallowed tag <${tag}>. ` +\n `Only ${[...ALLOWED_HEAD_TAGS].join(\", \")} are allowed.`,\n );\n }\n}\n\nfunction collectHeadElements(\n list: React.ReactElement[],\n child: React.ReactNode,\n): React.ReactElement[] {\n if (\n child == null ||\n typeof child === \"boolean\" ||\n typeof child === \"string\" ||\n typeof child === \"number\"\n ) {\n return list;\n }\n if (!isValidElement(child)) {\n return list;\n }\n if (child.type === React.Fragment) {\n return Children.toArray((child.props as { children?: React.ReactNode }).children).reduce(\n collectHeadElements,\n list,\n );\n }\n if (typeof child.type !== \"string\") {\n return list;\n }\n if (!ALLOWED_HEAD_TAGS.has(child.type)) {\n warnDisallowedHeadTag(child.type);\n return list;\n }\n return list.concat(child);\n}\n\nfunction normalizeHeadKey(key: React.Key | null): string | null {\n if (key == null || typeof key === \"number\") return null;\n const normalizedKey = String(key);\n const separatorIndex = normalizedKey.indexOf(\"$\");\n return separatorIndex > 0 ? normalizedKey.slice(separatorIndex + 1) : null;\n}\n\nfunction createUniqueHeadFilter(): (child: React.ReactElement) => boolean {\n const keys = new Set<string>();\n const tags = new Set<string>();\n const metaTypes = new Set<string>();\n const metaCategories = new Map<string, Set<string>>();\n\n return (child) => {\n let isUnique = true;\n const normalizedKey = normalizeHeadKey(child.key);\n const hasKey = normalizedKey !== null;\n if (normalizedKey) {\n if (keys.has(normalizedKey)) {\n isUnique = false;\n } else {\n keys.add(normalizedKey);\n }\n }\n\n switch (child.type) {\n case \"title\":\n case \"base\":\n if (tags.has(child.type)) {\n isUnique = false;\n } else {\n tags.add(child.type);\n }\n break;\n case \"meta\": {\n const props = child.props as Record<string, unknown>;\n for (const metaType of META_TYPES) {\n if (!Object.prototype.hasOwnProperty.call(props, metaType)) continue;\n if (metaType === \"charSet\") {\n if (metaTypes.has(metaType)) {\n isUnique = false;\n } else {\n metaTypes.add(metaType);\n }\n continue;\n }\n\n const category = props[metaType];\n if (typeof category !== \"string\") continue;\n\n let categories = metaCategories.get(metaType);\n if (!categories) {\n categories = new Set<string>();\n metaCategories.set(metaType, categories);\n }\n\n if ((metaType !== \"name\" || !hasKey) && categories.has(category)) {\n isUnique = false;\n } else {\n categories.add(category);\n }\n }\n break;\n }\n default:\n break;\n }\n\n return isUnique;\n };\n}\n\nexport function reduceHeadChildren(headChildren: React.ReactNode[]): React.ReactElement[] {\n return headChildren\n .reduce<React.ReactNode[]>((flattenedChildren, child) => {\n return flattenedChildren.concat(Children.toArray(child));\n }, [])\n .reduce(collectHeadElements, [])\n .reverse()\n .filter(createUniqueHeadFilter())\n .reverse();\n}\n\n/**\n * Convert a React element to an HTML string for SSR head injection.\n * Returns an empty string for disallowed tag types.\n */\nfunction reactElementToHTML(child: React.ReactElement): string {\n const tag = child.type as string;\n\n if (!ALLOWED_HEAD_TAGS.has(tag)) {\n warnDisallowedHeadTag(tag);\n return \"\";\n }\n\n const props = child.props as Record<string, unknown>;\n const attrs: string[] = [];\n let innerHTML = \"\";\n\n for (const [key, value] of Object.entries(props)) {\n if (key === \"children\") {\n if (typeof value === \"string\") {\n innerHTML = escapeHTML(value);\n }\n } else if (key === \"dangerouslySetInnerHTML\") {\n // Intentionally raw — developer explicitly opted in.\n // SECURITY NOTE: This injects raw HTML during SSR. The client-side\n // path (line ~148) skips dangerouslySetInnerHTML for safety. Developers\n // must never pass unsanitized user input here — it is a stored XSS vector.\n const html = value as { __html: string };\n if (html?.__html) innerHTML = html.__html;\n } else if (key === \"className\") {\n attrs.push(`class=\"${escapeAttr(String(value))}\"`);\n } else if (typeof value === \"string\") {\n attrs.push(`${key}=\"${escapeAttr(value)}\"`);\n } else if (typeof value === \"boolean\" && value) {\n attrs.push(key);\n }\n }\n\n const attrStr = attrs.length ? \" \" + attrs.join(\" \") : \"\";\n\n // Self-closing tags\n const selfClosing = [\"meta\", \"link\", \"base\"];\n if (selfClosing.includes(tag)) {\n return `<${tag}${attrStr} data-vinext-head=\"true\" />`;\n }\n\n // For raw-content tags (script, style), escape closing-tag sequences so the\n // HTML parser doesn't prematurely terminate the element.\n const rawContentTags = [\"script\", \"style\"];\n if (rawContentTags.includes(tag) && innerHTML) {\n innerHTML = escapeInlineContent(innerHTML, tag);\n }\n\n return `<${tag}${attrStr} data-vinext-head=\"true\">${innerHTML}</${tag}>`;\n}\n\nfunction escapeHTML(s: string): string {\n return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n\nexport function escapeAttr(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/\"/g, \""\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n}\n\n/**\n * Escape content that will be placed inside a raw <script> or <style> tag\n * during SSR. The HTML parser treats `</script>` (or `</style>`) as the end\n * of the block regardless of JavaScript string context, so any occurrence\n * of `</` followed by the tag name must be escaped.\n *\n * We replace `</script` and `</style` (case-insensitive) with `<\\/script`\n * and `<\\/style` respectively. The `<\\/` form is harmless in JS/CSS string\n * context but prevents the HTML parser from seeing a closing tag.\n */\nexport function escapeInlineContent(content: string, tag: string): string {\n // Build a pattern like `<\\/script` or `<\\/style`, case-insensitive\n const pattern = new RegExp(`<\\\\/(${tag})`, \"gi\");\n return content.replace(pattern, \"<\\\\/$1\");\n}\n\nfunction syncClientHead(): void {\n document.querySelectorAll(\"[data-vinext-head]\").forEach((el) => el.remove());\n\n for (const child of reduceHeadChildren([..._clientHeadChildren.values()])) {\n if (typeof child.type !== \"string\") continue;\n\n const domEl = document.createElement(child.type);\n const props = child.props as Record<string, unknown>;\n\n for (const [key, value] of Object.entries(props)) {\n if (key === \"children\" && typeof value === \"string\") {\n domEl.textContent = value;\n } else if (key === \"dangerouslySetInnerHTML\") {\n // skip for safety\n } else if (key === \"className\") {\n domEl.setAttribute(\"class\", String(value));\n } else if (typeof value === \"boolean\" && value) {\n domEl.setAttribute(key, \"\");\n } else if (key !== \"children\" && typeof value === \"string\") {\n domEl.setAttribute(key, value);\n }\n }\n\n domEl.setAttribute(\"data-vinext-head\", \"true\");\n document.head.appendChild(domEl);\n }\n}\n\n// --- Component ---\n\nfunction Head({ children }: HeadProps): null {\n const headInstanceIdRef = useRef<symbol | null>(null);\n if (headInstanceIdRef.current === null) {\n headInstanceIdRef.current = Symbol(\"vinext-head\");\n }\n\n // SSR path: collect elements for later injection\n if (typeof window === \"undefined\") {\n _getSSRHeadChildren().push(children);\n return null;\n }\n\n // Client path: update the shared head projection after hydration.\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useEffect(() => {\n const instanceId = headInstanceIdRef.current!;\n _clientHeadChildren.set(instanceId, children);\n syncClientHead();\n\n return () => {\n _clientHeadChildren.delete(instanceId);\n syncClientHead();\n };\n }, [children]);\n\n return null;\n}\n\nexport default Head;\n"]}
|
package/dist/shims/headers.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* In Next.js 15+, cookies() and headers() return Promises (async).
|
|
8
8
|
* We support both the sync (legacy) and async patterns.
|
|
9
9
|
*/
|
|
10
|
-
interface HeadersContext {
|
|
10
|
+
export interface HeadersContext {
|
|
11
11
|
headers: Headers;
|
|
12
12
|
cookies: Map<string, string>;
|
|
13
13
|
accessError?: Error;
|
|
@@ -16,6 +16,13 @@ interface HeadersContext {
|
|
|
16
16
|
readonlyHeaders?: Headers;
|
|
17
17
|
}
|
|
18
18
|
export type HeadersAccessPhase = "render" | "action" | "route-handler";
|
|
19
|
+
export type VinextHeadersShimState = {
|
|
20
|
+
headersContext: HeadersContext | null;
|
|
21
|
+
dynamicUsageDetected: boolean;
|
|
22
|
+
pendingSetCookies: string[];
|
|
23
|
+
draftModeCookieHeader: string | null;
|
|
24
|
+
phase: HeadersAccessPhase;
|
|
25
|
+
};
|
|
19
26
|
/**
|
|
20
27
|
* Dynamic usage flag — set when a component calls connection(), cookies(),
|
|
21
28
|
* headers(), or noStore() during rendering. When true, ISR caching is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../src/shims/headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../src/shims/headers.ts"],"names":[],"mappings":"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"}
|
package/dist/shims/headers.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
11
11
|
import { buildRequestHeadersFromMiddlewareResponse } from "../server/middleware-request-headers.js";
|
|
12
12
|
import { parseCookieHeader } from "./internal/parse-cookie-header.js";
|
|
13
|
+
import { isInsideUnifiedScope, getRequestContext, runWithUnifiedStateMutation, } from "./unified-request-context.js";
|
|
13
14
|
// NOTE:
|
|
14
15
|
// - This shim can be loaded under multiple module specifiers in Vite's
|
|
15
16
|
// multi-environment setup (RSC/SSR). Store the AsyncLocalStorage on
|
|
@@ -30,8 +31,10 @@ const _fallbackState = (_g[_FALLBACK_KEY] ??= {
|
|
|
30
31
|
phase: "render",
|
|
31
32
|
});
|
|
32
33
|
function _getState() {
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
if (isInsideUnifiedScope()) {
|
|
35
|
+
return getRequestContext();
|
|
36
|
+
}
|
|
37
|
+
return _als.getStore() ?? _fallbackState;
|
|
35
38
|
}
|
|
36
39
|
/**
|
|
37
40
|
* Dynamic usage flag — set when a component calls connection(), cookies(),
|
|
@@ -124,37 +127,17 @@ export function getHeadersContext() {
|
|
|
124
127
|
return _getState().headersContext;
|
|
125
128
|
}
|
|
126
129
|
export function setHeadersContext(ctx) {
|
|
130
|
+
const state = _getState();
|
|
127
131
|
if (ctx !== null) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (existing) {
|
|
133
|
-
existing.headersContext = ctx;
|
|
134
|
-
existing.dynamicUsageDetected = false;
|
|
135
|
-
existing.pendingSetCookies = [];
|
|
136
|
-
existing.draftModeCookieHeader = null;
|
|
137
|
-
existing.phase = "render";
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
_fallbackState.headersContext = ctx;
|
|
141
|
-
_fallbackState.dynamicUsageDetected = false;
|
|
142
|
-
_fallbackState.pendingSetCookies = [];
|
|
143
|
-
_fallbackState.draftModeCookieHeader = null;
|
|
144
|
-
_fallbackState.phase = "render";
|
|
145
|
-
}
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
// End of request cleanup: keep the store (so consumeDynamicUsage and
|
|
149
|
-
// cookie flushing can still run), but clear the request headers/cookies.
|
|
150
|
-
const state = _als.getStore();
|
|
151
|
-
if (state) {
|
|
152
|
-
state.headersContext = null;
|
|
132
|
+
state.headersContext = ctx;
|
|
133
|
+
state.dynamicUsageDetected = false;
|
|
134
|
+
state.pendingSetCookies = [];
|
|
135
|
+
state.draftModeCookieHeader = null;
|
|
153
136
|
state.phase = "render";
|
|
154
137
|
}
|
|
155
138
|
else {
|
|
156
|
-
|
|
157
|
-
|
|
139
|
+
state.headersContext = null;
|
|
140
|
+
state.phase = "render";
|
|
158
141
|
}
|
|
159
142
|
}
|
|
160
143
|
/**
|
|
@@ -168,6 +151,15 @@ export function setHeadersContext(ctx) {
|
|
|
168
151
|
* stream is consumed still see the correct request's context.
|
|
169
152
|
*/
|
|
170
153
|
export function runWithHeadersContext(ctx, fn) {
|
|
154
|
+
if (isInsideUnifiedScope()) {
|
|
155
|
+
return runWithUnifiedStateMutation((uCtx) => {
|
|
156
|
+
uCtx.headersContext = ctx;
|
|
157
|
+
uCtx.dynamicUsageDetected = false;
|
|
158
|
+
uCtx.pendingSetCookies = [];
|
|
159
|
+
uCtx.draftModeCookieHeader = null;
|
|
160
|
+
uCtx.phase = "render";
|
|
161
|
+
}, fn);
|
|
162
|
+
}
|
|
171
163
|
const state = {
|
|
172
164
|
headersContext: ctx,
|
|
173
165
|
dynamicUsageDetected: false,
|