@tanstack/redact 0.0.1
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/core/index.d.ts +2 -0
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +7 -0
- package/dist/core/internal.d.ts +76 -0
- package/dist/core/internal.js +59 -0
- package/dist/core/internal.js.map +7 -0
- package/dist/core/types.d.ts +21 -0
- package/dist/core/types.js +10 -0
- package/dist/core/types.js.map +7 -0
- package/dist/dom/_all.d.ts +17 -0
- package/dist/dom/_all.js +51 -0
- package/dist/dom/_all.js.map +7 -0
- package/dist/dom/client.d.ts +3 -0
- package/dist/dom/client.js +8 -0
- package/dist/dom/client.js.map +7 -0
- package/dist/dom/dispatcher.d.ts +20 -0
- package/dist/dom/dispatcher.js +267 -0
- package/dist/dom/dispatcher.js.map +7 -0
- package/dist/dom/dom.d.ts +10 -0
- package/dist/dom/dom.js +262 -0
- package/dist/dom/dom.js.map +7 -0
- package/dist/dom/event-replay.d.ts +13 -0
- package/dist/dom/event-replay.js +46 -0
- package/dist/dom/event-replay.js.map +7 -0
- package/dist/dom/features/class/full.d.ts +1 -0
- package/dist/dom/features/class/full.js +91 -0
- package/dist/dom/features/class/full.js.map +7 -0
- package/dist/dom/features/class/index.d.ts +1 -0
- package/dist/dom/features/class/index.js +3 -0
- package/dist/dom/features/class/index.js.map +7 -0
- package/dist/dom/features/class/stub.d.ts +1 -0
- package/dist/dom/features/class/stub.js +50 -0
- package/dist/dom/features/class/stub.js.map +7 -0
- package/dist/dom/features/context/full.d.ts +1 -0
- package/dist/dom/features/context/full.js +49 -0
- package/dist/dom/features/context/full.js.map +7 -0
- package/dist/dom/features/context/index.d.ts +1 -0
- package/dist/dom/features/context/index.js +3 -0
- package/dist/dom/features/context/index.js.map +7 -0
- package/dist/dom/features/context/stub.d.ts +1 -0
- package/dist/dom/features/context/stub.js +22 -0
- package/dist/dom/features/context/stub.js.map +7 -0
- package/dist/dom/features/forward-ref/full.d.ts +1 -0
- package/dist/dom/features/forward-ref/full.js +51 -0
- package/dist/dom/features/forward-ref/full.js.map +7 -0
- package/dist/dom/features/forward-ref/index.d.ts +1 -0
- package/dist/dom/features/forward-ref/index.js +3 -0
- package/dist/dom/features/forward-ref/index.js.map +7 -0
- package/dist/dom/features/forward-ref/stub.d.ts +1 -0
- package/dist/dom/features/forward-ref/stub.js +22 -0
- package/dist/dom/features/forward-ref/stub.js.map +7 -0
- package/dist/dom/features/hydration/full.d.ts +61 -0
- package/dist/dom/features/hydration/full.js +264 -0
- package/dist/dom/features/hydration/full.js.map +7 -0
- package/dist/dom/features/hydration/index.d.ts +1 -0
- package/dist/dom/features/hydration/index.js +3 -0
- package/dist/dom/features/hydration/index.js.map +7 -0
- package/dist/dom/features/hydration/stub.d.ts +28 -0
- package/dist/dom/features/hydration/stub.js +66 -0
- package/dist/dom/features/hydration/stub.js.map +7 -0
- package/dist/dom/features/index.d.ts +7 -0
- package/dist/dom/features/index.js +9 -0
- package/dist/dom/features/index.js.map +7 -0
- package/dist/dom/features/lazy/full.d.ts +1 -0
- package/dist/dom/features/lazy/full.js +78 -0
- package/dist/dom/features/lazy/full.js.map +7 -0
- package/dist/dom/features/lazy/index.d.ts +1 -0
- package/dist/dom/features/lazy/index.js +3 -0
- package/dist/dom/features/lazy/index.js.map +7 -0
- package/dist/dom/features/lazy/stub.d.ts +1 -0
- package/dist/dom/features/lazy/stub.js +36 -0
- package/dist/dom/features/lazy/stub.js.map +7 -0
- package/dist/dom/features/memo/full.d.ts +1 -0
- package/dist/dom/features/memo/full.js +59 -0
- package/dist/dom/features/memo/full.js.map +7 -0
- package/dist/dom/features/memo/index.d.ts +1 -0
- package/dist/dom/features/memo/index.js +3 -0
- package/dist/dom/features/memo/index.js.map +7 -0
- package/dist/dom/features/memo/stub.d.ts +1 -0
- package/dist/dom/features/memo/stub.js +36 -0
- package/dist/dom/features/memo/stub.js.map +7 -0
- package/dist/dom/features/portal/full.d.ts +1 -0
- package/dist/dom/features/portal/full.js +19 -0
- package/dist/dom/features/portal/full.js.map +7 -0
- package/dist/dom/features/portal/index.d.ts +1 -0
- package/dist/dom/features/portal/index.js +3 -0
- package/dist/dom/features/portal/index.js.map +7 -0
- package/dist/dom/features/portal/stub.d.ts +1 -0
- package/dist/dom/features/portal/stub.js +7 -0
- package/dist/dom/features/portal/stub.js.map +7 -0
- package/dist/dom/features/suspense/full.d.ts +1 -0
- package/dist/dom/features/suspense/full.js +146 -0
- package/dist/dom/features/suspense/full.js.map +7 -0
- package/dist/dom/features/suspense/index.d.ts +1 -0
- package/dist/dom/features/suspense/index.js +3 -0
- package/dist/dom/features/suspense/index.js.map +7 -0
- package/dist/dom/features/suspense/stub.d.ts +1 -0
- package/dist/dom/features/suspense/stub.js +6 -0
- package/dist/dom/features/suspense/stub.js.map +7 -0
- package/dist/dom/index.d.ts +25 -0
- package/dist/dom/index.js +45 -0
- package/dist/dom/index.js.map +7 -0
- package/dist/dom/portal.d.ts +2 -0
- package/dist/dom/portal.js +15 -0
- package/dist/dom/portal.js.map +7 -0
- package/dist/dom/reconcile.d.ts +40 -0
- package/dist/dom/reconcile.js +795 -0
- package/dist/dom/reconcile.js.map +7 -0
- package/dist/dom/root.d.ts +15 -0
- package/dist/dom/root.js +85 -0
- package/dist/dom/root.js.map +7 -0
- package/dist/dom/test-utils.d.ts +1 -0
- package/dist/dom/test-utils.js +10 -0
- package/dist/dom/test-utils.js.map +7 -0
- package/dist/react/children.d.ts +8 -0
- package/dist/react/children.js +75 -0
- package/dist/react/children.js.map +7 -0
- package/dist/react/class.d.ts +31 -0
- package/dist/react/class.js +40 -0
- package/dist/react/class.js.map +7 -0
- package/dist/react/context.d.ts +27 -0
- package/dist/react/context.js +31 -0
- package/dist/react/context.js.map +7 -0
- package/dist/react/element.d.ts +10 -0
- package/dist/react/element.js +64 -0
- package/dist/react/element.js.map +7 -0
- package/dist/react/hooks.d.ts +37 -0
- package/dist/react/hooks.js +146 -0
- package/dist/react/hooks.js.map +7 -0
- package/dist/react/index.d.ts +76 -0
- package/dist/react/index.js +187 -0
- package/dist/react/index.js.map +7 -0
- package/dist/react/jsx-runtime.d.ts +5 -0
- package/dist/react/jsx-runtime.js +21 -0
- package/dist/react/jsx-runtime.js.map +7 -0
- package/dist/react/memo.d.ts +29 -0
- package/dist/react/memo.js +47 -0
- package/dist/react/memo.js.map +7 -0
- package/dist/react/portal.d.ts +1 -0
- package/dist/react/portal.js +6 -0
- package/dist/react/portal.js.map +7 -0
- package/dist/react/shared-internals.d.ts +33 -0
- package/dist/react/shared-internals.js +29 -0
- package/dist/react/shared-internals.js.map +7 -0
- package/dist/react/suspense.d.ts +15 -0
- package/dist/react/suspense.js +16 -0
- package/dist/react/suspense.js.map +7 -0
- package/dist/scheduler/index.d.ts +44 -0
- package/dist/scheduler/index.js +109 -0
- package/dist/scheduler/index.js.map +7 -0
- package/dist/server/bootstrap-script.d.ts +22 -0
- package/dist/server/bootstrap-script.js +16 -0
- package/dist/server/bootstrap-script.js.map +7 -0
- package/dist/server/dispatcher.d.ts +37 -0
- package/dist/server/dispatcher.js +140 -0
- package/dist/server/dispatcher.js.map +7 -0
- package/dist/server/escape.d.ts +7 -0
- package/dist/server/escape.js +159 -0
- package/dist/server/escape.js.map +7 -0
- package/dist/server/index.d.ts +16 -0
- package/dist/server/index.js +26 -0
- package/dist/server/index.js.map +7 -0
- package/dist/server/renderToString.d.ts +7 -0
- package/dist/server/renderToString.js +29 -0
- package/dist/server/renderToString.js.map +7 -0
- package/dist/server/stream.d.ts +40 -0
- package/dist/server/stream.js +200 -0
- package/dist/server/stream.js.map +7 -0
- package/dist/server/walk.d.ts +33 -0
- package/dist/server/walk.js +298 -0
- package/dist/server/walk.js.map +7 -0
- package/dist/vite/index.d.ts +96 -0
- package/dist/vite/index.js +217 -0
- package/dist/vite/index.js.map +7 -0
- package/package.json +83 -0
- package/src/core/index.ts +2 -0
- package/src/core/internal.ts +107 -0
- package/src/core/types.ts +36 -0
- package/src/dom/_all.ts +54 -0
- package/src/dom/client.ts +4 -0
- package/src/dom/dispatcher.ts +318 -0
- package/src/dom/dom.ts +316 -0
- package/src/dom/event-replay.ts +55 -0
- package/src/dom/features/class/full.ts +104 -0
- package/src/dom/features/class/index.ts +1 -0
- package/src/dom/features/class/stub.ts +65 -0
- package/src/dom/features/context/full.ts +57 -0
- package/src/dom/features/context/index.ts +1 -0
- package/src/dom/features/context/stub.ts +32 -0
- package/src/dom/features/forward-ref/full.ts +54 -0
- package/src/dom/features/forward-ref/index.ts +1 -0
- package/src/dom/features/forward-ref/stub.ts +28 -0
- package/src/dom/features/hydration/full.ts +345 -0
- package/src/dom/features/hydration/index.ts +1 -0
- package/src/dom/features/hydration/stub.ts +72 -0
- package/src/dom/features/index.ts +11 -0
- package/src/dom/features/lazy/full.ts +98 -0
- package/src/dom/features/lazy/index.ts +1 -0
- package/src/dom/features/lazy/stub.ts +45 -0
- package/src/dom/features/memo/full.ts +74 -0
- package/src/dom/features/memo/index.ts +1 -0
- package/src/dom/features/memo/stub.ts +42 -0
- package/src/dom/features/portal/full.ts +22 -0
- package/src/dom/features/portal/index.ts +1 -0
- package/src/dom/features/portal/stub.ts +11 -0
- package/src/dom/features/suspense/full.ts +191 -0
- package/src/dom/features/suspense/index.ts +1 -0
- package/src/dom/features/suspense/stub.ts +12 -0
- package/src/dom/index.ts +33 -0
- package/src/dom/portal.ts +16 -0
- package/src/dom/reconcile.ts +1169 -0
- package/src/dom/root.ts +107 -0
- package/src/dom/test-utils.ts +6 -0
- package/src/react/children.ts +85 -0
- package/src/react/class.ts +56 -0
- package/src/react/context.ts +50 -0
- package/src/react/element.ts +80 -0
- package/src/react/hooks.ts +190 -0
- package/src/react/index.ts +132 -0
- package/src/react/jsx-runtime.ts +16 -0
- package/src/react/memo.ts +45 -0
- package/src/react/portal.ts +1 -0
- package/src/react/shared-internals.ts +79 -0
- package/src/react/suspense.ts +18 -0
- package/src/scheduler/index.ts +124 -0
- package/src/server/bootstrap-script.ts +52 -0
- package/src/server/dispatcher.ts +158 -0
- package/src/server/escape.ts +187 -0
- package/src/server/index.ts +26 -0
- package/src/server/renderToString.ts +33 -0
- package/src/server/stream.ts +302 -0
- package/src/server/walk.ts +448 -0
- package/src/vite/index.ts +401 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// packages/redact/src/server/escape.ts
|
|
2
|
+
var ATTR_MAP = {
|
|
3
|
+
"&": "&",
|
|
4
|
+
'"': """,
|
|
5
|
+
"<": "<",
|
|
6
|
+
">": ">"
|
|
7
|
+
};
|
|
8
|
+
var TEXT_MAP = {
|
|
9
|
+
"&": "&",
|
|
10
|
+
"<": "<",
|
|
11
|
+
">": ">"
|
|
12
|
+
};
|
|
13
|
+
function escapeAttr(value) {
|
|
14
|
+
return value.replace(/[&"<>]/g, (c) => ATTR_MAP[c]);
|
|
15
|
+
}
|
|
16
|
+
function escapeText(value) {
|
|
17
|
+
return value.replace(/[&<>]/g, (c) => TEXT_MAP[c]);
|
|
18
|
+
}
|
|
19
|
+
function escapeScript(value) {
|
|
20
|
+
return value.replace(/<\/(script|style)/gi, "<\\/$1").replace(/<!--/g, "<\\!--");
|
|
21
|
+
}
|
|
22
|
+
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
23
|
+
"area",
|
|
24
|
+
"base",
|
|
25
|
+
"br",
|
|
26
|
+
"col",
|
|
27
|
+
"embed",
|
|
28
|
+
"hr",
|
|
29
|
+
"img",
|
|
30
|
+
"input",
|
|
31
|
+
"link",
|
|
32
|
+
"meta",
|
|
33
|
+
"param",
|
|
34
|
+
"source",
|
|
35
|
+
"track",
|
|
36
|
+
"wbr"
|
|
37
|
+
]);
|
|
38
|
+
var RAW_TEXT_ELEMENTS = /* @__PURE__ */ new Set(["script", "style"]);
|
|
39
|
+
var ATTR_ALIASES = {
|
|
40
|
+
className: "class",
|
|
41
|
+
htmlFor: "for",
|
|
42
|
+
httpEquiv: "http-equiv",
|
|
43
|
+
acceptCharset: "accept-charset",
|
|
44
|
+
crossOrigin: "crossorigin",
|
|
45
|
+
viewBox: "viewBox",
|
|
46
|
+
// SVG keeps camelCase
|
|
47
|
+
noModule: "nomodule"
|
|
48
|
+
};
|
|
49
|
+
var BOOLEAN_ATTRS = /* @__PURE__ */ new Set([
|
|
50
|
+
"allowfullscreen",
|
|
51
|
+
"async",
|
|
52
|
+
"autofocus",
|
|
53
|
+
"autoplay",
|
|
54
|
+
"checked",
|
|
55
|
+
"controls",
|
|
56
|
+
"default",
|
|
57
|
+
"defer",
|
|
58
|
+
"disabled",
|
|
59
|
+
"formnovalidate",
|
|
60
|
+
"hidden",
|
|
61
|
+
"inert",
|
|
62
|
+
"ismap",
|
|
63
|
+
"itemscope",
|
|
64
|
+
"loop",
|
|
65
|
+
"multiple",
|
|
66
|
+
"muted",
|
|
67
|
+
"nomodule",
|
|
68
|
+
"novalidate",
|
|
69
|
+
"open",
|
|
70
|
+
"playsinline",
|
|
71
|
+
"readonly",
|
|
72
|
+
"required",
|
|
73
|
+
"reversed",
|
|
74
|
+
"selected"
|
|
75
|
+
]);
|
|
76
|
+
function attrToHtml(name, value) {
|
|
77
|
+
if (name === "children" || name === "key" || name === "ref" || name === "dangerouslySetInnerHTML" || name === "defaultValue" || name === "defaultChecked" || name === "suppressHydrationWarning" || name === "suppressContentEditableWarning") {
|
|
78
|
+
return "";
|
|
79
|
+
}
|
|
80
|
+
if (name[0] === "o" && name[1] === "n" && typeof value === "function") return "";
|
|
81
|
+
if (value == null) return "";
|
|
82
|
+
const htmlName = ATTR_ALIASES[name] ?? name.toLowerCase();
|
|
83
|
+
if (name.startsWith("aria-") || name.startsWith("data-")) {
|
|
84
|
+
return ` ${htmlName}="${escapeAttr(String(value))}"`;
|
|
85
|
+
}
|
|
86
|
+
if (value === false) return "";
|
|
87
|
+
if (value === true || BOOLEAN_ATTRS.has(htmlName)) {
|
|
88
|
+
return value ? ` ${htmlName}=""` : "";
|
|
89
|
+
}
|
|
90
|
+
if (name === "style" && typeof value === "object" && value !== null) {
|
|
91
|
+
return ` style="${escapeAttr(styleToString(value))}"`;
|
|
92
|
+
}
|
|
93
|
+
return ` ${htmlName}="${escapeAttr(String(value))}"`;
|
|
94
|
+
}
|
|
95
|
+
var UNITLESS_STYLE = /* @__PURE__ */ new Set([
|
|
96
|
+
"animationIterationCount",
|
|
97
|
+
"borderImageOutset",
|
|
98
|
+
"borderImageSlice",
|
|
99
|
+
"borderImageWidth",
|
|
100
|
+
"boxFlex",
|
|
101
|
+
"boxFlexGroup",
|
|
102
|
+
"boxOrdinalGroup",
|
|
103
|
+
"columnCount",
|
|
104
|
+
"columns",
|
|
105
|
+
"flex",
|
|
106
|
+
"flexGrow",
|
|
107
|
+
"flexPositive",
|
|
108
|
+
"flexShrink",
|
|
109
|
+
"flexNegative",
|
|
110
|
+
"flexOrder",
|
|
111
|
+
"gridArea",
|
|
112
|
+
"gridRow",
|
|
113
|
+
"gridRowEnd",
|
|
114
|
+
"gridRowSpan",
|
|
115
|
+
"gridRowStart",
|
|
116
|
+
"gridColumn",
|
|
117
|
+
"gridColumnEnd",
|
|
118
|
+
"gridColumnSpan",
|
|
119
|
+
"gridColumnStart",
|
|
120
|
+
"fontWeight",
|
|
121
|
+
"lineClamp",
|
|
122
|
+
"lineHeight",
|
|
123
|
+
"opacity",
|
|
124
|
+
"order",
|
|
125
|
+
"orphans",
|
|
126
|
+
"tabSize",
|
|
127
|
+
"widows",
|
|
128
|
+
"zIndex",
|
|
129
|
+
"zoom",
|
|
130
|
+
"fillOpacity",
|
|
131
|
+
"floodOpacity",
|
|
132
|
+
"stopOpacity",
|
|
133
|
+
"strokeDasharray",
|
|
134
|
+
"strokeDashoffset",
|
|
135
|
+
"strokeMiterlimit",
|
|
136
|
+
"strokeOpacity",
|
|
137
|
+
"strokeWidth"
|
|
138
|
+
]);
|
|
139
|
+
function styleToString(style) {
|
|
140
|
+
let out = "";
|
|
141
|
+
for (const key in style) {
|
|
142
|
+
const v = style[key];
|
|
143
|
+
if (v == null || v === false) continue;
|
|
144
|
+
const kebab = key.startsWith("--") ? key : key.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
|
|
145
|
+
const value = typeof v === "number" && !UNITLESS_STYLE.has(key) && v !== 0 ? v + "px" : v;
|
|
146
|
+
out += `${kebab}:${value};`;
|
|
147
|
+
}
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
150
|
+
export {
|
|
151
|
+
ATTR_ALIASES,
|
|
152
|
+
RAW_TEXT_ELEMENTS,
|
|
153
|
+
VOID_ELEMENTS,
|
|
154
|
+
attrToHtml,
|
|
155
|
+
escapeAttr,
|
|
156
|
+
escapeScript,
|
|
157
|
+
escapeText
|
|
158
|
+
};
|
|
159
|
+
//# sourceMappingURL=escape.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/server/escape.ts"],
|
|
4
|
+
"sourcesContent": ["const ATTR_MAP: Record<string, string> = {\n '&': '&',\n '\"': '"',\n '<': '<',\n '>': '>',\n}\nconst TEXT_MAP: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n}\n\nexport function escapeAttr(value: string): string {\n return value.replace(/[&\"<>]/g, (c) => ATTR_MAP[c]!)\n}\n\nexport function escapeText(value: string): string {\n return value.replace(/[&<>]/g, (c) => TEXT_MAP[c]!)\n}\n\n// Raw-text element body escaping: prevent any closing tag for the raw-text\n// elements (<script>, <style>) from terminating the element early, plus\n// `<!--` (which would start an HTML comment that survives even inside\n// raw-text bodies and can be exploited to alter following script content).\n// React's serializer follows the same approach.\nexport function escapeScript(value: string): string {\n return value\n .replace(/<\\/(script|style)/gi, '<\\\\/$1')\n .replace(/<!--/g, '<\\\\!--')\n}\n\nexport const VOID_ELEMENTS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'param',\n 'source',\n 'track',\n 'wbr',\n])\n\nexport const RAW_TEXT_ELEMENTS = new Set(['script', 'style'])\n\n// Map JSX prop names to HTML attribute names where they differ\nexport const ATTR_ALIASES: Record<string, string> = {\n className: 'class',\n htmlFor: 'for',\n httpEquiv: 'http-equiv',\n acceptCharset: 'accept-charset',\n crossOrigin: 'crossorigin',\n viewBox: 'viewBox', // SVG keeps camelCase\n noModule: 'nomodule',\n}\n\nconst BOOLEAN_ATTRS = new Set([\n 'allowfullscreen',\n 'async',\n 'autofocus',\n 'autoplay',\n 'checked',\n 'controls',\n 'default',\n 'defer',\n 'disabled',\n 'formnovalidate',\n 'hidden',\n 'inert',\n 'ismap',\n 'itemscope',\n 'loop',\n 'multiple',\n 'muted',\n 'nomodule',\n 'novalidate',\n 'open',\n 'playsinline',\n 'readonly',\n 'required',\n 'reversed',\n 'selected',\n])\n\nexport function attrToHtml(name: string, value: unknown): string {\n if (\n name === 'children' ||\n name === 'key' ||\n name === 'ref' ||\n name === 'dangerouslySetInnerHTML' ||\n name === 'defaultValue' ||\n name === 'defaultChecked' ||\n name === 'suppressHydrationWarning' ||\n name === 'suppressContentEditableWarning'\n ) {\n return ''\n }\n if (name[0] === 'o' && name[1] === 'n' && typeof value === 'function') return ''\n if (value == null) return ''\n\n const htmlName = ATTR_ALIASES[name] ?? name.toLowerCase()\n\n // aria-* and data-* stringify booleans to `\"true\"`/`\"false\"` rather than\n // using boolean-attribute presence semantics \u2014 matches React and the ARIA\n // spec. Must branch before the general `value === false` / BOOLEAN_ATTRS\n // path, which would drop them.\n if (name.startsWith('aria-') || name.startsWith('data-')) {\n return ` ${htmlName}=\"${escapeAttr(String(value))}\"`\n }\n\n if (value === false) return ''\n\n if (value === true || BOOLEAN_ATTRS.has(htmlName)) {\n return value ? ` ${htmlName}=\"\"` : ''\n }\n\n if (name === 'style' && typeof value === 'object' && value !== null) {\n return ` style=\"${escapeAttr(styleToString(value as Record<string, unknown>))}\"`\n }\n\n return ` ${htmlName}=\"${escapeAttr(String(value))}\"`\n}\n\nconst UNITLESS_STYLE = new Set([\n 'animationIterationCount',\n 'borderImageOutset',\n 'borderImageSlice',\n 'borderImageWidth',\n 'boxFlex',\n 'boxFlexGroup',\n 'boxOrdinalGroup',\n 'columnCount',\n 'columns',\n 'flex',\n 'flexGrow',\n 'flexPositive',\n 'flexShrink',\n 'flexNegative',\n 'flexOrder',\n 'gridArea',\n 'gridRow',\n 'gridRowEnd',\n 'gridRowSpan',\n 'gridRowStart',\n 'gridColumn',\n 'gridColumnEnd',\n 'gridColumnSpan',\n 'gridColumnStart',\n 'fontWeight',\n 'lineClamp',\n 'lineHeight',\n 'opacity',\n 'order',\n 'orphans',\n 'tabSize',\n 'widows',\n 'zIndex',\n 'zoom',\n 'fillOpacity',\n 'floodOpacity',\n 'stopOpacity',\n 'strokeDasharray',\n 'strokeDashoffset',\n 'strokeMiterlimit',\n 'strokeOpacity',\n 'strokeWidth',\n])\n\nfunction styleToString(style: Record<string, unknown>): string {\n let out = ''\n for (const key in style) {\n const v = style[key]\n if (v == null || v === false) continue\n const kebab = key.startsWith('--')\n ? key\n : key.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase())\n const value =\n typeof v === 'number' && !UNITLESS_STYLE.has(key) && v !== 0 ? v + 'px' : v\n out += `${kebab}:${value};`\n }\n return out\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { renderToString, renderToStaticMarkup } from './renderToString';
|
|
2
|
+
export { renderToReadableStream, renderToPipeableStream } from './stream';
|
|
3
|
+
export type { StreamOptions, PipeableOptions, PipeableHandle, ReadableStreamResult, } from './stream';
|
|
4
|
+
export { BOUNDARY_REVEAL_RUNTIME } from './bootstrap-script';
|
|
5
|
+
export declare const version = "19.2.3";
|
|
6
|
+
import { renderToString, renderToStaticMarkup } from './renderToString';
|
|
7
|
+
import { renderToReadableStream, renderToPipeableStream } from './stream';
|
|
8
|
+
declare const _default: {
|
|
9
|
+
renderToString: typeof renderToString;
|
|
10
|
+
renderToStaticMarkup: typeof renderToStaticMarkup;
|
|
11
|
+
renderToReadableStream: typeof renderToReadableStream;
|
|
12
|
+
renderToPipeableStream: typeof renderToPipeableStream;
|
|
13
|
+
BOUNDARY_REVEAL_RUNTIME: string;
|
|
14
|
+
version: string;
|
|
15
|
+
};
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// packages/redact/src/server/index.ts
|
|
2
|
+
import { renderToString, renderToStaticMarkup } from "./renderToString";
|
|
3
|
+
import { renderToReadableStream, renderToPipeableStream } from "./stream";
|
|
4
|
+
import { BOUNDARY_REVEAL_RUNTIME } from "./bootstrap-script";
|
|
5
|
+
import { renderToString as renderToString2, renderToStaticMarkup as renderToStaticMarkup2 } from "./renderToString";
|
|
6
|
+
import { renderToReadableStream as renderToReadableStream2, renderToPipeableStream as renderToPipeableStream2 } from "./stream";
|
|
7
|
+
import { BOUNDARY_REVEAL_RUNTIME as BOUNDARY_REVEAL_RUNTIME2 } from "./bootstrap-script";
|
|
8
|
+
var version = "19.2.3";
|
|
9
|
+
var server_default = {
|
|
10
|
+
renderToString: renderToString2,
|
|
11
|
+
renderToStaticMarkup: renderToStaticMarkup2,
|
|
12
|
+
renderToReadableStream: renderToReadableStream2,
|
|
13
|
+
renderToPipeableStream: renderToPipeableStream2,
|
|
14
|
+
BOUNDARY_REVEAL_RUNTIME: BOUNDARY_REVEAL_RUNTIME2,
|
|
15
|
+
version: "19.2.3"
|
|
16
|
+
};
|
|
17
|
+
export {
|
|
18
|
+
BOUNDARY_REVEAL_RUNTIME,
|
|
19
|
+
server_default as default,
|
|
20
|
+
renderToPipeableStream,
|
|
21
|
+
renderToReadableStream,
|
|
22
|
+
renderToStaticMarkup,
|
|
23
|
+
renderToString,
|
|
24
|
+
version
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/server/index.ts"],
|
|
4
|
+
"sourcesContent": ["export { renderToString, renderToStaticMarkup } from './renderToString'\nexport { renderToReadableStream, renderToPipeableStream } from './stream'\nexport type {\n StreamOptions,\n PipeableOptions,\n PipeableHandle,\n ReadableStreamResult,\n} from './stream'\nexport { BOUNDARY_REVEAL_RUNTIME } from './bootstrap-script'\n\nexport const version = '19.2.3'\n\n// Default export \u2014 React's real `react-dom/server` ships one, and TanStack\n// Router's SSR code does `import ReactDOMServer from 'react-dom/server'` and\n// reads `.renderToReadableStream` off the default.\nimport { renderToString, renderToStaticMarkup } from './renderToString'\nimport { renderToReadableStream, renderToPipeableStream } from './stream'\nimport { BOUNDARY_REVEAL_RUNTIME } from './bootstrap-script'\nexport default {\n renderToString,\n renderToStaticMarkup,\n renderToReadableStream,\n renderToPipeableStream,\n BOUNDARY_REVEAL_RUNTIME,\n version: '19.2.3',\n}\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,gBAAgB,4BAA4B;AACrD,SAAS,wBAAwB,8BAA8B;AAO/D,SAAS,+BAA+B;AAOxC,SAAS,kBAAAA,iBAAgB,wBAAAC,6BAA4B;AACrD,SAAS,0BAAAC,yBAAwB,0BAAAC,+BAA8B;AAC/D,SAAS,2BAAAC,gCAA+B;AAPjC,IAAM,UAAU;AAQvB,IAAO,iBAAQ;AAAA,EACb,gBAAAJ;AAAA,EACA,sBAAAC;AAAA,EACA,wBAAAC;AAAA,EACA,wBAAAC;AAAA,EACA,yBAAAC;AAAA,EACA,SAAS;AACX;",
|
|
6
|
+
"names": ["renderToString", "renderToStaticMarkup", "renderToReadableStream", "renderToPipeableStream", "BOUNDARY_REVEAL_RUNTIME"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ReactNode } from '../core';
|
|
2
|
+
export declare function renderToString(children: ReactNode, options?: {
|
|
3
|
+
identifierPrefix?: string;
|
|
4
|
+
}): string;
|
|
5
|
+
export declare function renderToStaticMarkup(children: ReactNode, options?: {
|
|
6
|
+
identifierPrefix?: string;
|
|
7
|
+
}): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// packages/redact/src/server/renderToString.ts
|
|
2
|
+
import { beginSSR, endSSR, installSSRDispatcher, uninstallSSRDispatcher } from "./dispatcher";
|
|
3
|
+
import { walk } from "./walk";
|
|
4
|
+
function renderToString(children, options = {}) {
|
|
5
|
+
installSSRDispatcher();
|
|
6
|
+
beginSSR(options.identifierPrefix);
|
|
7
|
+
let output = "";
|
|
8
|
+
let id = 0;
|
|
9
|
+
try {
|
|
10
|
+
walk(children, {
|
|
11
|
+
emit: (s) => {
|
|
12
|
+
output += s;
|
|
13
|
+
},
|
|
14
|
+
nextBoundaryId: () => id++
|
|
15
|
+
});
|
|
16
|
+
} finally {
|
|
17
|
+
endSSR();
|
|
18
|
+
uninstallSSRDispatcher();
|
|
19
|
+
}
|
|
20
|
+
return output;
|
|
21
|
+
}
|
|
22
|
+
function renderToStaticMarkup(children, options = {}) {
|
|
23
|
+
return renderToString(children, options).replace(/<!--[^>]*-->/g, "");
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
renderToStaticMarkup,
|
|
27
|
+
renderToString
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=renderToString.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/server/renderToString.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ReactNode } from '../core'\nimport { beginSSR, endSSR, installSSRDispatcher, uninstallSSRDispatcher } from './dispatcher'\nimport { walk } from './walk'\n\nexport function renderToString(\n children: ReactNode,\n options: { identifierPrefix?: string } = {},\n): string {\n installSSRDispatcher()\n beginSSR(options.identifierPrefix)\n let output = ''\n let id = 0\n try {\n walk(children, {\n emit: (s) => {\n output += s\n },\n nextBoundaryId: () => id++,\n })\n } finally {\n endSSR()\n uninstallSSRDispatcher()\n }\n return output\n}\n\nexport function renderToStaticMarkup(\n children: ReactNode,\n options: { identifierPrefix?: string } = {},\n): string {\n // For our purposes identical to renderToString (no hydration markers in static output)\n return renderToString(children, options).replace(/<!--[^>]*-->/g, '')\n}\n"],
|
|
5
|
+
"mappings": ";AACA,SAAS,UAAU,QAAQ,sBAAsB,8BAA8B;AAC/E,SAAS,YAAY;AAEd,SAAS,eACd,UACA,UAAyC,CAAC,GAClC;AACR,uBAAqB;AACrB,WAAS,QAAQ,gBAAgB;AACjC,MAAI,SAAS;AACb,MAAI,KAAK;AACT,MAAI;AACF,SAAK,UAAU;AAAA,MACb,MAAM,CAAC,MAAM;AACX,kBAAU;AAAA,MACZ;AAAA,MACA,gBAAgB,MAAM;AAAA,IACxB,CAAC;AAAA,EACH,UAAE;AACA,WAAO;AACP,2BAAuB;AAAA,EACzB;AACA,SAAO;AACT;AAEO,SAAS,qBACd,UACA,UAAyC,CAAC,GAClC;AAER,SAAO,eAAe,UAAU,OAAO,EAAE,QAAQ,iBAAiB,EAAE;AACtE;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ReactNode } from '../core';
|
|
2
|
+
export interface StreamOptions {
|
|
3
|
+
identifierPrefix?: string;
|
|
4
|
+
nonce?: string;
|
|
5
|
+
bootstrapScripts?: ReadonlyArray<string | {
|
|
6
|
+
src: string;
|
|
7
|
+
async?: boolean;
|
|
8
|
+
nonce?: string;
|
|
9
|
+
}>;
|
|
10
|
+
bootstrapModules?: ReadonlyArray<string | {
|
|
11
|
+
src: string;
|
|
12
|
+
nonce?: string;
|
|
13
|
+
}>;
|
|
14
|
+
onError?: (error: unknown) => string | void;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
progressiveChunkSize?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ReadableStreamResult extends ReadableStream<Uint8Array> {
|
|
19
|
+
allReady: Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export interface OrchestratorState {
|
|
22
|
+
nextId: number;
|
|
23
|
+
pending: Set<Promise<void>>;
|
|
24
|
+
closed: boolean;
|
|
25
|
+
errored: unknown | null;
|
|
26
|
+
}
|
|
27
|
+
type Emit = (chunk: string) => void;
|
|
28
|
+
export declare function streamHtml(children: ReactNode, emit: Emit, options: StreamOptions, state: OrchestratorState): Promise<void>;
|
|
29
|
+
export declare function renderToReadableStream(children: ReactNode, options?: StreamOptions): Promise<ReadableStreamResult>;
|
|
30
|
+
export interface PipeableHandle {
|
|
31
|
+
pipe<T extends NodeJS.WritableStream>(dest: T): T;
|
|
32
|
+
abort(reason?: unknown): void;
|
|
33
|
+
}
|
|
34
|
+
export interface PipeableOptions extends StreamOptions {
|
|
35
|
+
onShellReady?: () => void;
|
|
36
|
+
onShellError?: (err: unknown) => void;
|
|
37
|
+
onAllReady?: () => void;
|
|
38
|
+
}
|
|
39
|
+
export declare function renderToPipeableStream(children: ReactNode, options?: PipeableOptions): PipeableHandle;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// packages/redact/src/server/stream.ts
|
|
2
|
+
import {
|
|
3
|
+
beginSSR,
|
|
4
|
+
endSSR,
|
|
5
|
+
installSSRDispatcher,
|
|
6
|
+
uninstallSSRDispatcher,
|
|
7
|
+
applyContextSnapshot
|
|
8
|
+
} from "./dispatcher";
|
|
9
|
+
import { walk } from "./walk";
|
|
10
|
+
import { BOUNDARY_REVEAL_RUNTIME, revealScript } from "./bootstrap-script";
|
|
11
|
+
async function streamHtml(children, emit, options, state) {
|
|
12
|
+
installSSRDispatcher();
|
|
13
|
+
beginSSR(options.identifierPrefix);
|
|
14
|
+
const nonce = options.nonce;
|
|
15
|
+
try {
|
|
16
|
+
const boundaries = [];
|
|
17
|
+
const shellChunks = [];
|
|
18
|
+
const bufferedEmit = (chunk) => {
|
|
19
|
+
shellChunks.push(chunk);
|
|
20
|
+
};
|
|
21
|
+
walk(children, {
|
|
22
|
+
emit: bufferedEmit,
|
|
23
|
+
onSuspend: (b) => boundaries.push(b),
|
|
24
|
+
nextBoundaryId: () => state.nextId++
|
|
25
|
+
});
|
|
26
|
+
const hasBootstrap = (options.bootstrapScripts?.length ?? 0) > 0 || (options.bootstrapModules?.length ?? 0) > 0;
|
|
27
|
+
if (boundaries.length > 0 || hasBootstrap) {
|
|
28
|
+
shellChunks.push(`<script${nonce ? ` nonce="${nonce}"` : ""}>${BOUNDARY_REVEAL_RUNTIME}<\/script>`);
|
|
29
|
+
for (const s of options.bootstrapScripts ?? []) {
|
|
30
|
+
shellChunks.push(bootstrapTag(s, "script", nonce));
|
|
31
|
+
}
|
|
32
|
+
for (const m of options.bootstrapModules ?? []) {
|
|
33
|
+
shellChunks.push(bootstrapTag(m, "module", nonce));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (shellChunks.length) emit(shellChunks.join(""));
|
|
37
|
+
for (const b of boundaries) streamBoundary(b, emit, options, state);
|
|
38
|
+
await drain(state);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
state.errored = err;
|
|
41
|
+
if (options.onError) options.onError(err);
|
|
42
|
+
throw err;
|
|
43
|
+
} finally {
|
|
44
|
+
endSSR();
|
|
45
|
+
uninstallSSRDispatcher();
|
|
46
|
+
state.closed = true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function streamBoundary(b, emit, options, state) {
|
|
50
|
+
const task = (async () => {
|
|
51
|
+
try {
|
|
52
|
+
await b.thenable;
|
|
53
|
+
} catch (err) {
|
|
54
|
+
if (options.onError) options.onError(err);
|
|
55
|
+
}
|
|
56
|
+
if (state.closed) return;
|
|
57
|
+
const parts = [];
|
|
58
|
+
const sub = [];
|
|
59
|
+
const restore = applyContextSnapshot(b.contextSnapshot);
|
|
60
|
+
try {
|
|
61
|
+
walk(b.children, {
|
|
62
|
+
emit: (s) => parts.push(s),
|
|
63
|
+
onSuspend: (n) => sub.push(n),
|
|
64
|
+
nextBoundaryId: () => state.nextId++
|
|
65
|
+
});
|
|
66
|
+
} catch (err) {
|
|
67
|
+
if (options.onError) options.onError(err);
|
|
68
|
+
restore();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
restore();
|
|
72
|
+
emit(`<div hidden id="S:${b.id}">${parts.join("")}</div>${revealScript(b.id, options.nonce)}`);
|
|
73
|
+
for (const s of sub) streamBoundary(s, emit, options, state);
|
|
74
|
+
})();
|
|
75
|
+
state.pending.add(task);
|
|
76
|
+
task.finally(() => state.pending.delete(task));
|
|
77
|
+
}
|
|
78
|
+
async function drain(state) {
|
|
79
|
+
while (state.pending.size > 0) {
|
|
80
|
+
await Promise.race(state.pending);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function bootstrapTag(entry, kind, defaultNonce) {
|
|
84
|
+
const src = typeof entry === "string" ? entry : entry.src;
|
|
85
|
+
const nonce = typeof entry === "string" ? defaultNonce : entry.nonce ?? defaultNonce;
|
|
86
|
+
const nAttr = nonce ? ` nonce="${nonce}"` : "";
|
|
87
|
+
if (kind === "module") return `<script type="module"${nAttr} src="${src}"><\/script>`;
|
|
88
|
+
return `<script async${nAttr} src="${src}"><\/script>`;
|
|
89
|
+
}
|
|
90
|
+
function renderToReadableStream(children, options = {}) {
|
|
91
|
+
const state = {
|
|
92
|
+
nextId: 0,
|
|
93
|
+
pending: /* @__PURE__ */ new Set(),
|
|
94
|
+
closed: false,
|
|
95
|
+
errored: null
|
|
96
|
+
};
|
|
97
|
+
const encoder = new TextEncoder();
|
|
98
|
+
let allReadyResolve;
|
|
99
|
+
let allReadyReject;
|
|
100
|
+
const allReady = new Promise((r, rej) => {
|
|
101
|
+
allReadyResolve = r;
|
|
102
|
+
allReadyReject = rej;
|
|
103
|
+
});
|
|
104
|
+
const stream = new ReadableStream({
|
|
105
|
+
start(controller) {
|
|
106
|
+
const emit = (chunk) => {
|
|
107
|
+
try {
|
|
108
|
+
controller.enqueue(encoder.encode(chunk));
|
|
109
|
+
} catch {
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
streamHtml(children, emit, options, state).then(
|
|
113
|
+
() => {
|
|
114
|
+
try {
|
|
115
|
+
controller.close();
|
|
116
|
+
} catch {
|
|
117
|
+
}
|
|
118
|
+
allReadyResolve();
|
|
119
|
+
},
|
|
120
|
+
(err) => {
|
|
121
|
+
try {
|
|
122
|
+
controller.error(err);
|
|
123
|
+
} catch {
|
|
124
|
+
}
|
|
125
|
+
allReadyReject(err);
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
options.signal?.addEventListener("abort", () => {
|
|
129
|
+
state.closed = true;
|
|
130
|
+
try {
|
|
131
|
+
controller.close();
|
|
132
|
+
} catch {
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
return Promise.resolve(Object.assign(stream, { allReady }));
|
|
138
|
+
}
|
|
139
|
+
function renderToPipeableStream(children, options = {}) {
|
|
140
|
+
const state = {
|
|
141
|
+
nextId: 0,
|
|
142
|
+
pending: /* @__PURE__ */ new Set(),
|
|
143
|
+
closed: false,
|
|
144
|
+
errored: null
|
|
145
|
+
};
|
|
146
|
+
const buffers = [];
|
|
147
|
+
let dest = null;
|
|
148
|
+
let shellReady = false;
|
|
149
|
+
let finished = false;
|
|
150
|
+
let aborted = false;
|
|
151
|
+
const flushTo = (w) => {
|
|
152
|
+
if (!buffers.length) return;
|
|
153
|
+
for (const b of buffers) w.write(b);
|
|
154
|
+
buffers.length = 0;
|
|
155
|
+
};
|
|
156
|
+
const emit = (chunk) => {
|
|
157
|
+
if (aborted || finished) return;
|
|
158
|
+
if (dest) dest.write(chunk);
|
|
159
|
+
else buffers.push(chunk);
|
|
160
|
+
};
|
|
161
|
+
streamHtml(children, emit, options, state).then(
|
|
162
|
+
() => {
|
|
163
|
+
finished = true;
|
|
164
|
+
if (dest) dest.end();
|
|
165
|
+
options.onAllReady?.();
|
|
166
|
+
},
|
|
167
|
+
(err) => {
|
|
168
|
+
if (!shellReady) {
|
|
169
|
+
options.onShellError?.(err);
|
|
170
|
+
} else {
|
|
171
|
+
options.onError?.(err);
|
|
172
|
+
if (dest) dest.end();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
queueMicrotask(() => {
|
|
177
|
+
if (aborted || finished) return;
|
|
178
|
+
shellReady = true;
|
|
179
|
+
options.onShellReady?.();
|
|
180
|
+
});
|
|
181
|
+
return {
|
|
182
|
+
pipe(target) {
|
|
183
|
+
dest = target;
|
|
184
|
+
flushTo(target);
|
|
185
|
+
if (finished) target.end();
|
|
186
|
+
return target;
|
|
187
|
+
},
|
|
188
|
+
abort(_reason) {
|
|
189
|
+
aborted = true;
|
|
190
|
+
state.closed = true;
|
|
191
|
+
if (dest) dest.end();
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
export {
|
|
196
|
+
renderToPipeableStream,
|
|
197
|
+
renderToReadableStream,
|
|
198
|
+
streamHtml
|
|
199
|
+
};
|
|
200
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/server/stream.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ReactNode } from '../core'\nimport {\n beginSSR,\n endSSR,\n installSSRDispatcher,\n uninstallSSRDispatcher,\n applyContextSnapshot,\n} from './dispatcher'\nimport { walk, type SuspendedBoundary } from './walk'\nimport { BOUNDARY_REVEAL_RUNTIME, revealScript } from './bootstrap-script'\n\nexport interface StreamOptions {\n identifierPrefix?: string\n nonce?: string\n bootstrapScripts?: ReadonlyArray<string | { src: string; async?: boolean; nonce?: string }>\n bootstrapModules?: ReadonlyArray<string | { src: string; nonce?: string }>\n onError?: (error: unknown) => string | void\n signal?: AbortSignal\n progressiveChunkSize?: number\n}\n\nexport interface ReadableStreamResult extends ReadableStream<Uint8Array> {\n allReady: Promise<void>\n}\n\nexport interface OrchestratorState {\n nextId: number\n pending: Set<Promise<void>>\n closed: boolean\n errored: unknown | null\n}\n\ntype Emit = (chunk: string) => void\n\nexport async function streamHtml(\n children: ReactNode,\n emit: Emit,\n options: StreamOptions,\n state: OrchestratorState,\n): Promise<void> {\n installSSRDispatcher()\n beginSSR(options.identifierPrefix)\n const nonce = options.nonce\n\n try {\n const boundaries: SuspendedBoundary[] = []\n\n // Buffer shell + bootstrap into a string[] and flush as a single emit.\n // Per-emit overhead in renderToReadableStream is TextEncoder.encode +\n // controller.enqueue \u2014 each walkHost normally fires 3+ emits (opening\n // tag, per-attribute, closing bracket), which for a ~30-component tree\n // is ~100 stream-controller round-trips. Batching collapses those into\n // one encode and one enqueue per shell \u2014 measured ~2-4% of total SSR\n // time on CPU profiles.\n const shellChunks: string[] = []\n const bufferedEmit: Emit = (chunk) => {\n shellChunks.push(chunk)\n }\n\n // 1. Render the shell\n walk(children, {\n emit: bufferedEmit,\n onSuspend: (b) => boundaries.push(b),\n nextBoundaryId: () => state.nextId++,\n })\n\n // 2. Inject runtime + bootstrap scripts (once, after shell). Skip the\n // reveal/event-replay runtime when nothing needs it \u2014 no suspensions to\n // reveal and no bootstrap scripts to guard against early user input. That\n // keeps fully-static SSR responses byte-equivalent to a plain walk and\n // matches React's behavior where `renderToReadableStream` of a static\n // tree emits only the markup.\n const hasBootstrap =\n (options.bootstrapScripts?.length ?? 0) > 0 ||\n (options.bootstrapModules?.length ?? 0) > 0\n if (boundaries.length > 0 || hasBootstrap) {\n shellChunks.push(`<script${nonce ? ` nonce=\"${nonce}\"` : ''}>${BOUNDARY_REVEAL_RUNTIME}</script>`)\n for (const s of options.bootstrapScripts ?? []) {\n shellChunks.push(bootstrapTag(s, 'script', nonce))\n }\n for (const m of options.bootstrapModules ?? []) {\n shellChunks.push(bootstrapTag(m, 'module', nonce))\n }\n }\n\n if (shellChunks.length) emit(shellChunks.join(''))\n\n // 3. Stream suspended boundaries as they resolve\n for (const b of boundaries) streamBoundary(b, emit, options, state)\n await drain(state)\n } catch (err) {\n state.errored = err\n if (options.onError) options.onError(err)\n throw err\n } finally {\n endSSR()\n uninstallSSRDispatcher()\n state.closed = true\n }\n}\n\nfunction streamBoundary(\n b: SuspendedBoundary,\n emit: Emit,\n options: StreamOptions,\n state: OrchestratorState,\n): void {\n const task = (async () => {\n try {\n await b.thenable\n } catch (err) {\n if (options.onError) options.onError(err)\n }\n if (state.closed) return\n\n // Re-render the boundary's children into a string, restoring the\n // provider stack from when the boundary first suspended.\n const parts: string[] = []\n const sub: SuspendedBoundary[] = []\n const restore = applyContextSnapshot(b.contextSnapshot)\n try {\n walk(b.children, {\n emit: (s) => parts.push(s),\n onSuspend: (n) => sub.push(n),\n nextBoundaryId: () => state.nextId++,\n })\n } catch (err) {\n if (options.onError) options.onError(err)\n restore()\n return\n }\n restore()\n\n emit(`<div hidden id=\"S:${b.id}\">${parts.join('')}</div>${revealScript(b.id, options.nonce)}`)\n\n // Recurse: any nested suspensions inside the now-revealed content\n for (const s of sub) streamBoundary(s, emit, options, state)\n })()\n state.pending.add(task)\n task.finally(() => state.pending.delete(task))\n}\n\nasync function drain(state: OrchestratorState): Promise<void> {\n while (state.pending.size > 0) {\n await Promise.race(state.pending)\n }\n}\n\nfunction bootstrapTag(\n entry: string | { src: string; async?: boolean; nonce?: string },\n kind: 'script' | 'module',\n defaultNonce: string | undefined,\n): string {\n const src = typeof entry === 'string' ? entry : entry.src\n const nonce = typeof entry === 'string' ? defaultNonce : entry.nonce ?? defaultNonce\n const nAttr = nonce ? ` nonce=\"${nonce}\"` : ''\n if (kind === 'module') return `<script type=\"module\"${nAttr} src=\"${src}\"></script>`\n return `<script async${nAttr} src=\"${src}\"></script>`\n}\n\n// ---------------------------------------------------------------------------\n// Web Streams: renderToReadableStream\n// ---------------------------------------------------------------------------\n\nexport function renderToReadableStream(\n children: ReactNode,\n options: StreamOptions = {},\n): Promise<ReadableStreamResult> {\n const state: OrchestratorState = {\n nextId: 0,\n pending: new Set(),\n closed: false,\n errored: null,\n }\n const encoder = new TextEncoder()\n\n let allReadyResolve!: () => void\n let allReadyReject!: (e: unknown) => void\n const allReady = new Promise<void>((r, rej) => {\n allReadyResolve = r\n allReadyReject = rej\n })\n\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n const emit = (chunk: string) => {\n try {\n controller.enqueue(encoder.encode(chunk))\n } catch {}\n }\n\n streamHtml(children, emit, options, state).then(\n () => {\n try {\n controller.close()\n } catch {}\n allReadyResolve()\n },\n (err) => {\n try {\n controller.error(err)\n } catch {}\n allReadyReject(err)\n },\n )\n\n options.signal?.addEventListener('abort', () => {\n state.closed = true\n try {\n controller.close()\n } catch {}\n })\n },\n })\n\n return Promise.resolve(Object.assign(stream, { allReady }))\n}\n\n// ---------------------------------------------------------------------------\n// Node Streams: renderToPipeableStream\n// ---------------------------------------------------------------------------\n\nexport interface PipeableHandle {\n pipe<T extends NodeJS.WritableStream>(dest: T): T\n abort(reason?: unknown): void\n}\n\nexport interface PipeableOptions extends StreamOptions {\n onShellReady?: () => void\n onShellError?: (err: unknown) => void\n onAllReady?: () => void\n}\n\nexport function renderToPipeableStream(\n children: ReactNode,\n options: PipeableOptions = {},\n): PipeableHandle {\n const state: OrchestratorState = {\n nextId: 0,\n pending: new Set(),\n closed: false,\n errored: null,\n }\n\n const buffers: string[] = []\n let dest: NodeJS.WritableStream | null = null\n let shellReady = false\n let finished = false\n let aborted = false\n\n const flushTo = (w: NodeJS.WritableStream) => {\n if (!buffers.length) return\n for (const b of buffers) w.write(b)\n buffers.length = 0\n }\n\n const emit: Emit = (chunk) => {\n if (aborted || finished) return\n if (dest) dest.write(chunk)\n else buffers.push(chunk)\n }\n\n // Kick off rendering\n streamHtml(children, emit, options, state).then(\n () => {\n finished = true\n if (dest) dest.end()\n options.onAllReady?.()\n },\n (err) => {\n if (!shellReady) {\n options.onShellError?.(err)\n } else {\n options.onError?.(err)\n if (dest) dest.end()\n }\n },\n )\n\n // We call onShellReady once the first synchronous emit has landed.\n // streamHtml above runs the shell synchronously before the first await in drain(),\n // so we can schedule onShellReady right after the first microtask.\n queueMicrotask(() => {\n if (aborted || finished) return\n shellReady = true\n options.onShellReady?.()\n })\n\n return {\n pipe<T extends NodeJS.WritableStream>(target: T): T {\n dest = target\n flushTo(target)\n if (finished) target.end()\n return target\n },\n abort(_reason?: unknown) {\n aborted = true\n state.closed = true\n if (dest) dest.end()\n },\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ReactNode } from '../core';
|
|
2
|
+
import { type ContextSnapshot } from './dispatcher';
|
|
3
|
+
export interface SuspendedBoundary {
|
|
4
|
+
id: number;
|
|
5
|
+
fallbackHTML: string;
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
thenable: Promise<any>;
|
|
8
|
+
contextSnapshot: ContextSnapshot;
|
|
9
|
+
}
|
|
10
|
+
export interface WalkOptions {
|
|
11
|
+
emit: (chunk: string) => void;
|
|
12
|
+
onSuspend?: (boundary: SuspendedBoundary) => void;
|
|
13
|
+
nextBoundaryId: () => number;
|
|
14
|
+
bootstrapped?: boolean;
|
|
15
|
+
isBoundaryResolution?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Tracks whether the most recent emission within the *current text flow*
|
|
18
|
+
* ended with a text node. When the next emission is also text, we emit a
|
|
19
|
+
* `<!-- -->` separator so the browser's HTML parser doesn't merge them
|
|
20
|
+
* into a single text node — required for hydration to line up text
|
|
21
|
+
* boundaries with the React tree. Reset to `false` whenever we enter a
|
|
22
|
+
* new host element (`<tag>` opens a fresh text flow).
|
|
23
|
+
*/
|
|
24
|
+
textState?: {
|
|
25
|
+
lastWasText: boolean;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Synchronously walk a React node and emit HTML string pieces to `opts.emit`.
|
|
30
|
+
* Suspended boundaries are emitted as fallbacks with marker IDs; if `opts.onSuspend`
|
|
31
|
+
* is provided, the suspension is recorded for later streaming.
|
|
32
|
+
*/
|
|
33
|
+
export declare function walk(node: ReactNode, opts: WalkOptions): void;
|