@tanstack/redact 0.0.21 → 0.1.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/attributes.js +2 -1
- package/dist/core/attributes.js.map +2 -2
- package/dist/core/browser.d.ts +9 -0
- package/dist/core/browser.js +35 -0
- package/dist/core/browser.js.map +7 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +3 -3
- package/dist/core/internal.d.ts +31 -8
- package/dist/core/internal.js +3 -1
- package/dist/core/internal.js.map +2 -2
- package/dist/core/resource-hints.d.ts +7 -0
- package/dist/core/resource-hints.js +19 -0
- package/dist/core/resource-hints.js.map +7 -0
- package/dist/core/types.js +1 -1
- package/dist/dom/_all.d.ts +11 -16
- package/dist/dom/_all.js +9 -20
- package/dist/dom/_all.js.map +2 -2
- package/dist/dom/client.d.ts +4 -4
- package/dist/dom/client.js +4 -4
- package/dist/dom/commit.d.ts +23 -0
- package/dist/dom/commit.js +191 -0
- package/dist/dom/commit.js.map +7 -0
- package/dist/dom/dispatcher.d.ts +4 -22
- package/dist/dom/dispatcher.js +184 -126
- package/dist/dom/dispatcher.js.map +3 -3
- package/dist/dom/dom.d.ts +2 -0
- package/dist/dom/dom.js +72 -52
- package/dist/dom/dom.js.map +2 -2
- package/dist/dom/error-info.d.ts +2 -0
- package/dist/dom/error-info.js +16 -0
- package/dist/dom/error-info.js.map +7 -0
- package/dist/dom/event-replay.js +1 -1
- package/dist/dom/features/activity/full.d.ts +1 -0
- package/dist/dom/features/activity/full.js +162 -0
- package/dist/dom/features/activity/full.js.map +7 -0
- package/dist/dom/features/activity/index.d.ts +1 -0
- package/dist/dom/features/activity/index.js +3 -0
- package/dist/dom/features/activity/index.js.map +7 -0
- package/dist/dom/features/activity/stub.d.ts +1 -0
- package/dist/dom/features/activity/stub.js +12 -0
- package/dist/dom/features/activity/stub.js.map +7 -0
- package/dist/dom/features/class/full.js +87 -27
- package/dist/dom/features/class/full.js.map +2 -2
- package/dist/dom/features/class/index.d.ts +1 -1
- package/dist/dom/features/class/index.js +2 -2
- package/dist/dom/features/class/stub.js +3 -3
- package/dist/dom/features/context/full.d.ts +4 -1
- package/dist/dom/features/context/full.js +72 -15
- package/dist/dom/features/context/full.js.map +2 -2
- package/dist/dom/features/context/index.d.ts +1 -1
- package/dist/dom/features/context/index.js +2 -2
- package/dist/dom/features/context/stub.d.ts +4 -1
- package/dist/dom/features/context/stub.js +17 -8
- package/dist/dom/features/context/stub.js.map +2 -2
- package/dist/dom/features/forward-ref/full.js +12 -21
- package/dist/dom/features/forward-ref/full.js.map +2 -2
- package/dist/dom/features/forward-ref/index.d.ts +1 -1
- package/dist/dom/features/forward-ref/index.js +2 -2
- package/dist/dom/features/forward-ref/stub.js +4 -4
- package/dist/dom/features/fragment-refs/index.d.ts +1 -0
- package/dist/dom/features/fragment-refs/index.js +8 -0
- package/dist/dom/features/fragment-refs/index.js.map +7 -0
- package/dist/dom/features/fragment-refs/stub.d.ts +3 -0
- package/dist/dom/features/fragment-refs/stub.js +14 -0
- package/dist/dom/features/fragment-refs/stub.js.map +7 -0
- package/dist/dom/features/hydration/full.d.ts +11 -6
- package/dist/dom/features/hydration/full.js +76 -77
- package/dist/dom/features/hydration/full.js.map +2 -2
- package/dist/dom/features/hydration/index.d.ts +1 -1
- package/dist/dom/features/hydration/index.js +2 -2
- package/dist/dom/features/hydration/stub.d.ts +7 -2
- package/dist/dom/features/hydration/stub.js +1 -1
- package/dist/dom/features/hydration/stub.js.map +1 -1
- package/dist/dom/features/index.d.ts +8 -7
- package/dist/dom/features/index.js +9 -8
- package/dist/dom/features/index.js.map +2 -2
- package/dist/dom/features/lazy/full.js +4 -4
- package/dist/dom/features/lazy/index.d.ts +1 -1
- package/dist/dom/features/lazy/index.js +2 -2
- package/dist/dom/features/lazy/stub.js +4 -4
- package/dist/dom/features/memo/full.js +8 -6
- package/dist/dom/features/memo/full.js.map +2 -2
- package/dist/dom/features/memo/index.d.ts +1 -1
- package/dist/dom/features/memo/index.js +2 -2
- package/dist/dom/features/memo/stub.js +4 -4
- package/dist/dom/features/portal/full.js +4 -4
- package/dist/dom/features/portal/index.d.ts +1 -1
- package/dist/dom/features/portal/index.js +2 -2
- package/dist/dom/features/portal/stub.js +4 -4
- package/dist/dom/features/suspense/full.js +197 -52
- package/dist/dom/features/suspense/full.js.map +2 -2
- package/dist/dom/features/suspense/index.d.ts +1 -1
- package/dist/dom/features/suspense/index.js +2 -2
- package/dist/dom/features/suspense/stub.js +4 -4
- package/dist/dom/features/view-transition/full.d.ts +6 -0
- package/dist/dom/features/view-transition/full.js +280 -0
- package/dist/dom/features/view-transition/full.js.map +7 -0
- package/dist/dom/features/view-transition/index.d.ts +1 -0
- package/dist/dom/features/view-transition/index.js +3 -0
- package/dist/dom/features/view-transition/index.js.map +7 -0
- package/dist/dom/features/view-transition/resources.d.ts +11 -0
- package/dist/dom/features/view-transition/resources.js +108 -0
- package/dist/dom/features/view-transition/resources.js.map +7 -0
- package/dist/dom/features/view-transition/stub.d.ts +6 -0
- package/dist/dom/features/view-transition/stub.js +22 -0
- package/dist/dom/features/view-transition/stub.js.map +7 -0
- package/dist/dom/features/view-transition/visual.d.ts +14 -0
- package/dist/dom/features/view-transition/visual.js +356 -0
- package/dist/dom/features/view-transition/visual.js.map +7 -0
- package/dist/dom/fragment-instance.d.ts +40 -0
- package/dist/dom/fragment-instance.js +324 -0
- package/dist/dom/fragment-instance.js.map +7 -0
- package/dist/dom/index.d.ts +11 -11
- package/dist/dom/index.js +11 -18
- package/dist/dom/index.js.map +3 -3
- package/dist/dom/portal.d.ts +2 -2
- package/dist/dom/portal.js +2 -2
- package/dist/dom/portal.js.map +1 -1
- package/dist/dom/reconcile.d.ts +32 -3
- package/dist/dom/reconcile.js +689 -221
- package/dist/dom/reconcile.js.map +2 -2
- package/dist/dom/resource-hints.d.ts +6 -0
- package/dist/dom/resource-hints.js +115 -0
- package/dist/dom/resource-hints.js.map +7 -0
- package/dist/dom/resource-store.d.ts +13 -0
- package/dist/dom/resource-store.js +43 -0
- package/dist/dom/resource-store.js.map +7 -0
- package/dist/dom/resources.d.ts +1 -0
- package/dist/dom/resources.js +44 -0
- package/dist/dom/resources.js.map +7 -0
- package/dist/dom/retained-effects.d.ts +6 -0
- package/dist/dom/retained-effects.js +49 -0
- package/dist/dom/retained-effects.js.map +7 -0
- package/dist/dom/root-internal.d.ts +4 -4
- package/dist/dom/root-internal.js +2 -2
- package/dist/dom/root-internal.js.map +2 -2
- package/dist/dom/root.d.ts +5 -5
- package/dist/dom/root.js +11 -11
- package/dist/dom/root.js.map +2 -2
- package/dist/dom/test-utils.js +1 -1
- package/dist/react/activity.d.ts +7 -0
- package/dist/react/activity.js +8 -0
- package/dist/react/activity.js.map +7 -0
- package/dist/react/children.d.ts +1 -1
- package/dist/react/children.js +3 -3
- package/dist/react/children.js.map +1 -1
- package/dist/react/class.d.ts +1 -1
- package/dist/react/class.js +3 -3
- package/dist/react/class.js.map +1 -1
- package/dist/react/compiler-runtime.js +2 -2
- package/dist/react/context.d.ts +7 -2
- package/dist/react/context.js +3 -11
- package/dist/react/context.js.map +3 -3
- package/dist/react/element.d.ts +6 -3
- package/dist/react/element.js +7 -11
- package/dist/react/element.js.map +2 -2
- package/dist/react/hooks.d.ts +26 -7
- package/dist/react/hooks.js +13 -3
- package/dist/react/hooks.js.map +2 -2
- package/dist/react/index.d.ts +39 -24
- package/dist/react/index.js +39 -19
- package/dist/react/index.js.map +3 -3
- package/dist/react/jsx-runtime.d.ts +2 -2
- package/dist/react/jsx-runtime.js +3 -3
- package/dist/react/memo.d.ts +1 -1
- package/dist/react/memo.js +1 -1
- package/dist/react/portal.js +1 -1
- package/dist/react/shared-internals.d.ts +15 -5
- package/dist/react/shared-internals.js +2 -3
- package/dist/react/shared-internals.js.map +2 -2
- package/dist/react/suspense.js +1 -1
- package/dist/react/view-transition.d.ts +32 -0
- package/dist/react/view-transition.js +13 -0
- package/dist/react/view-transition.js.map +7 -0
- package/dist/scheduler/index.js +1 -1
- package/dist/server/bootstrap-script.d.ts +1 -23
- package/dist/server/bootstrap-script.js +7 -6
- package/dist/server/bootstrap-script.js.map +2 -2
- package/dist/server/dispatcher.d.ts +28 -6
- package/dist/server/dispatcher.js +33 -15
- package/dist/server/dispatcher.js.map +2 -2
- package/dist/server/escape.js +16 -15
- package/dist/server/escape.js.map +2 -2
- package/dist/server/index.d.ts +6 -6
- package/dist/server/index.js +7 -7
- package/dist/server/renderToString.d.ts +1 -1
- package/dist/server/renderToString.js +12 -8
- package/dist/server/renderToString.js.map +2 -2
- package/dist/server/resource-hints.d.ts +22 -0
- package/dist/server/resource-hints.js +148 -0
- package/dist/server/resource-hints.js.map +7 -0
- package/dist/server/stream.d.ts +15 -2
- package/dist/server/stream.js +155 -63
- package/dist/server/stream.js.map +2 -2
- package/dist/server/walk.d.ts +15 -2
- package/dist/server/walk.js +150 -110
- package/dist/server/walk.js.map +2 -2
- package/dist/vite/index.d.ts +6 -0
- package/dist/vite/index.js +22 -6
- package/dist/vite/index.js.map +2 -2
- package/package.json +1 -1
- package/src/core/attributes.ts +1 -0
- package/src/core/browser.ts +33 -0
- package/src/core/internal.ts +24 -6
- package/src/core/resource-hints.ts +36 -0
- package/src/dom/_all.ts +1 -7
- package/src/dom/commit.ts +186 -0
- package/src/dom/dispatcher.ts +190 -134
- package/src/dom/dom.ts +70 -54
- package/src/dom/error-info.ts +15 -0
- package/src/dom/features/activity/full.ts +166 -0
- package/src/dom/features/activity/index.ts +1 -0
- package/src/dom/features/activity/stub.ts +14 -0
- package/src/dom/features/class/full.ts +72 -28
- package/src/dom/features/context/full.ts +70 -13
- package/src/dom/features/context/stub.ts +10 -5
- package/src/dom/features/forward-ref/full.ts +9 -19
- package/src/dom/features/fragment-refs/index.ts +1 -0
- package/src/dom/features/fragment-refs/stub.ts +3 -0
- package/src/dom/features/hydration/full.ts +84 -85
- package/src/dom/features/hydration/stub.ts +1 -1
- package/src/dom/features/index.ts +1 -0
- package/src/dom/features/memo/full.ts +4 -3
- package/src/dom/features/suspense/full.ts +192 -55
- package/src/dom/features/view-transition/full.ts +288 -0
- package/src/dom/features/view-transition/index.ts +1 -0
- package/src/dom/features/view-transition/resources.ts +107 -0
- package/src/dom/features/view-transition/stub.ts +7 -0
- package/src/dom/features/view-transition/visual.ts +406 -0
- package/src/dom/fragment-instance.ts +337 -0
- package/src/dom/index.ts +6 -7
- package/src/dom/portal.ts +1 -1
- package/src/dom/reconcile.ts +695 -242
- package/src/dom/resource-hints.ts +115 -0
- package/src/dom/resource-store.ts +52 -0
- package/src/dom/resources.ts +39 -0
- package/src/dom/retained-effects.ts +38 -0
- package/src/dom/root-internal.ts +4 -4
- package/src/dom/root.ts +12 -14
- package/src/react/activity.ts +10 -0
- package/src/react/context.ts +4 -11
- package/src/react/element.ts +11 -12
- package/src/react/hooks.ts +12 -3
- package/src/react/index.ts +18 -0
- package/src/react/shared-internals.ts +3 -3
- package/src/react/view-transition.ts +41 -0
- package/src/server/bootstrap-script.ts +36 -5
- package/src/server/dispatcher.ts +35 -13
- package/src/server/escape.ts +15 -12
- package/src/server/renderToString.ts +7 -5
- package/src/server/resource-hints.ts +165 -0
- package/src/server/stream.ts +154 -62
- package/src/server/walk.ts +79 -26
- package/src/vite/index.ts +30 -13
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// src/server/resource-hints.ts
|
|
2
|
+
import { resourceKind, resourceURL } from "../core/resource-hints.js";
|
|
3
|
+
import { attrToHtml, escapeAttr } from "./escape.js";
|
|
4
|
+
import { attributeName } from "../core/attributes.js";
|
|
5
|
+
function styleText(props) {
|
|
6
|
+
const html = props.dangerouslySetInnerHTML;
|
|
7
|
+
if (html != null) {
|
|
8
|
+
if (typeof html !== "object" || !("__html" in html)) throw new Error("dangerouslySetInnerHTML must be an object with an __html field.");
|
|
9
|
+
if (props.children != null) throw new Error("Can only set one of children or dangerouslySetInnerHTML.");
|
|
10
|
+
return html.__html == null ? "" : "" + html.__html;
|
|
11
|
+
}
|
|
12
|
+
const child = Array.isArray(props.children) ? props.children.length < 2 ? props.children[0] : null : props.children;
|
|
13
|
+
return child == null || typeof child === "function" || typeof child === "symbol" ? "" : ("" + child).replace(/(<\/?)(s)(tyle)/gi, (_, prefix, s, suffix) => prefix + "\\" + s.charCodeAt(0).toString(16) + " " + suffix);
|
|
14
|
+
}
|
|
15
|
+
function markup(resource, late) {
|
|
16
|
+
const { kind, href, options } = resource;
|
|
17
|
+
const script = kind === "script" || kind === "module-script";
|
|
18
|
+
const style = kind === "stylesheet";
|
|
19
|
+
const props = script ? { src: href, ...kind === "module-script" ? { type: "module" } : {}, async: true, ...options } : style ? late ? { rel: "preload", as: "style", href, crossOrigin: options.crossOrigin, fetchPriority: options.fetchPriority, integrity: options.integrity, media: options.media, hrefLang: options.hrefLang, referrerPolicy: options.referrerPolicy } : { rel: "stylesheet", href, "data-precedence": options.precedence, ...options } : { rel: kind, ...options.as === "image" && options.imageSrcSet ? {} : { href }, ...options };
|
|
20
|
+
let output = script ? "<script" : "<link";
|
|
21
|
+
for (const name in props) {
|
|
22
|
+
if (name === "precedence" || late && name === "data-precedence") continue;
|
|
23
|
+
const value = name === "href" || name === "src" ? resourceURL(props[name]) : props[name];
|
|
24
|
+
output += attrToHtml(name, value).replace(/'/g, "'");
|
|
25
|
+
}
|
|
26
|
+
return output + (script ? "><\/script>" : "/>");
|
|
27
|
+
}
|
|
28
|
+
function createResourceHints(shellFlushed = false, styleNonce) {
|
|
29
|
+
const resources = /* @__PURE__ */ new Map();
|
|
30
|
+
const groups = [[], [], [], [], []];
|
|
31
|
+
const styles = /* @__PURE__ */ new Map();
|
|
32
|
+
const dependencies = /* @__PURE__ */ new Map();
|
|
33
|
+
const visibleInline = /* @__PURE__ */ new Set();
|
|
34
|
+
const collector = {
|
|
35
|
+
add(kind, href, options) {
|
|
36
|
+
let type = kind;
|
|
37
|
+
let source = href;
|
|
38
|
+
const init = kind === "style" || kind === "stylesheet" || kind === "script" || kind === "module-script";
|
|
39
|
+
if (kind === "preload") {
|
|
40
|
+
type = options.as;
|
|
41
|
+
if (type === "image" && options.imageSrcSet) source = options.imageSrcSet + "\n" + (options.imageSizes || "");
|
|
42
|
+
} else if (kind === "modulepreload") type = "module-" + (options.as || "script");
|
|
43
|
+
else if (kind === "stylesheet") type = "style";
|
|
44
|
+
else if (kind === "preconnect") type += ":" + (options.crossOrigin ?? "default");
|
|
45
|
+
const key = JSON.stringify([type, source]);
|
|
46
|
+
const prior = resources.get(key);
|
|
47
|
+
if (prior && (!init || prior.kind !== "preload" && prior.kind !== "modulepreload")) return prior;
|
|
48
|
+
const resource = { kind, href, options: { ...options } };
|
|
49
|
+
if (kind === "style" && (!styleNonce || options.nonce === styleNonce)) resource.css = styleText(options);
|
|
50
|
+
if (prior) {
|
|
51
|
+
prior.cancelled = true;
|
|
52
|
+
resource.preloaded = !!prior.sent;
|
|
53
|
+
for (const name of ["crossOrigin", "integrity"]) {
|
|
54
|
+
if (resource.options[name] == null && prior.options[name] != null) resource.options[name] = prior.options[name];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
resources.set(key, resource);
|
|
58
|
+
if (kind === "stylesheet" || kind === "style") {
|
|
59
|
+
const precedence = options.precedence;
|
|
60
|
+
let group = styles.get(precedence);
|
|
61
|
+
if (!group) styles.set(precedence, group = []);
|
|
62
|
+
group.push(resource);
|
|
63
|
+
} else {
|
|
64
|
+
const group = kind === "dns-prefetch" || kind === "preconnect" ? 0 : kind === "preload" && options.as === "font" ? 1 : kind === "preload" && options.as === "image" && options.fetchPriority === "high" ? 2 : init ? 3 : 4;
|
|
65
|
+
groups[group].push(resource);
|
|
66
|
+
}
|
|
67
|
+
return resource;
|
|
68
|
+
},
|
|
69
|
+
addHost(type, props, scope) {
|
|
70
|
+
const kind = resourceKind(type, props);
|
|
71
|
+
if (!kind) return false;
|
|
72
|
+
const resource = collector.add(kind === "script" && props.type === "module" ? "module-script" : kind, kind === "script" ? props.src : props.href, props);
|
|
73
|
+
if (shellFlushed && kind === "stylesheet") {
|
|
74
|
+
const descriptor = [resourceURL(resource.href), resource.options.precedence];
|
|
75
|
+
for (const name in resource.options) {
|
|
76
|
+
if (name === "href" || name === "rel" || name === "precedence" || name === "data-precedence" || name === "children" || name === "dangerouslySetInnerHTML" || name === "innerHTML" || name === "style" || name === "suppressHydrationWarning" || name === "suppressContentEditableWarning" || name === "ref" || name === "key" || /^on/i.test(name) || !/^[a-zA-Z_:][a-zA-Z0-9:_.-]*$/.test(name)) continue;
|
|
77
|
+
const value = resource.options[name];
|
|
78
|
+
if (value == null || typeof value === "function" || typeof value === "symbol" || name === "hidden" && value === false) continue;
|
|
79
|
+
descriptor.push(attributeName(name), name === "hidden" ? "" : name === "src" ? resourceURL("" + value) : "" + value);
|
|
80
|
+
}
|
|
81
|
+
;
|
|
82
|
+
(scope ? scope.stylesheets ||= /* @__PURE__ */ new Map() : dependencies).set(resource.href, descriptor);
|
|
83
|
+
} else if (shellFlushed && kind === "style") {
|
|
84
|
+
;
|
|
85
|
+
(scope ? scope.inline ||= /* @__PURE__ */ new Set() : visibleInline).add(resource.options.precedence);
|
|
86
|
+
}
|
|
87
|
+
return true;
|
|
88
|
+
},
|
|
89
|
+
mergeScope(scope, parent) {
|
|
90
|
+
if (scope.stylesheets) for (const [href, descriptor] of scope.stylesheets) {
|
|
91
|
+
;
|
|
92
|
+
(parent ? parent.stylesheets ||= /* @__PURE__ */ new Map() : dependencies).set(href, descriptor);
|
|
93
|
+
}
|
|
94
|
+
if (scope.inline) for (const precedence of scope.inline) {
|
|
95
|
+
;
|
|
96
|
+
(parent ? parent.inline ||= /* @__PURE__ */ new Set() : visibleInline).add(precedence);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
takeStylesheets() {
|
|
100
|
+
const result = Array.from(dependencies.values());
|
|
101
|
+
dependencies.clear();
|
|
102
|
+
return result;
|
|
103
|
+
},
|
|
104
|
+
drain() {
|
|
105
|
+
let output = "";
|
|
106
|
+
function flush(group, precedence) {
|
|
107
|
+
let remaining = 0;
|
|
108
|
+
let inline = false, hasStylesheets = false;
|
|
109
|
+
let hrefs = "", rules = "";
|
|
110
|
+
for (const resource of group) {
|
|
111
|
+
if (!resource.sent && !resource.cancelled) {
|
|
112
|
+
if (resource.kind === "style") {
|
|
113
|
+
if (shellFlushed && !visibleInline.has(precedence)) {
|
|
114
|
+
group[remaining++] = resource;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
inline = true;
|
|
118
|
+
if (resource.css !== void 0) {
|
|
119
|
+
hrefs += (hrefs ? " " : "") + resource.href;
|
|
120
|
+
rules += resource.css;
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
if (resource.kind === "stylesheet") hasStylesheets = true;
|
|
124
|
+
if (!(shellFlushed && resource.kind === "stylesheet" && resource.preloaded)) output += markup(resource, shellFlushed);
|
|
125
|
+
}
|
|
126
|
+
resource.sent = true;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
group.length = remaining;
|
|
130
|
+
if (hrefs || inline && !shellFlushed && !hasStylesheets) {
|
|
131
|
+
output += `<style${styleNonce !== void 0 ? ` nonce="${escapeAttr(styleNonce)}"` : ""}${shellFlushed ? ' media="not all"' : ""} data-precedence="${escapeAttr(precedence)}"${hrefs ? ` data-href="${escapeAttr(hrefs)}"` : ""}>${rules}</style>`;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
for (let index = 0; index < groups.length; index++) {
|
|
135
|
+
if (index === 3) for (const [precedence, group] of styles) flush(group, precedence);
|
|
136
|
+
flush(groups[index]);
|
|
137
|
+
}
|
|
138
|
+
shellFlushed = true;
|
|
139
|
+
visibleInline.clear();
|
|
140
|
+
return output;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
return collector;
|
|
144
|
+
}
|
|
145
|
+
export {
|
|
146
|
+
createResourceHints
|
|
147
|
+
};
|
|
148
|
+
//# sourceMappingURL=resource-hints.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/server/resource-hints.ts"],
|
|
4
|
+
"sourcesContent": ["import { resourceKind, resourceURL, type ResourceHintKind, type ResourceHintOptions } from '../core/resource-hints'\nimport { attrToHtml, escapeAttr } from './escape'\nimport { attributeName } from '../core/attributes'\n\ninterface Resource {\n kind: ResourceHintKind | 'style'\n href: string\n options: Record<string, any>\n sent?: boolean\n cancelled?: boolean\n preloaded?: boolean\n css?: string\n}\n\nexport interface ResourceScope {\n stylesheets?: Map<string, string[]>\n inline?: Set<string>\n}\n\nfunction styleText(props: any): string {\n const html = props.dangerouslySetInnerHTML\n if (html != null) {\n if (typeof html !== 'object' || !('__html' in html)) throw new Error('dangerouslySetInnerHTML must be an object with an __html field.')\n if (props.children != null) throw new Error('Can only set one of children or dangerouslySetInnerHTML.')\n return html.__html == null ? '' : '' + html.__html\n }\n const child = Array.isArray(props.children) ? props.children.length < 2 ? props.children[0] : null : props.children\n return child == null || typeof child === 'function' || typeof child === 'symbol' ? ''\n : ('' + child).replace(/(<\\/?)(s)(tyle)/gi, (_, prefix: string, s: string, suffix: string) => prefix + '\\\\' + s.charCodeAt(0).toString(16) + ' ' + suffix)\n}\n\nfunction markup(resource: Resource, late: boolean): string {\n const { kind, href, options } = resource\n const script = kind === 'script' || kind === 'module-script'\n const style = kind === 'stylesheet'\n const props: Record<string, any> = script\n ? { src: href, ...(kind === 'module-script' ? { type: 'module' } : {}), async: true, ...options }\n : style\n ? late\n ? { rel: 'preload', as: 'style', href, crossOrigin: options.crossOrigin, fetchPriority: options.fetchPriority, integrity: options.integrity, media: options.media, hrefLang: options.hrefLang, referrerPolicy: options.referrerPolicy }\n : { rel: 'stylesheet', href, 'data-precedence': options.precedence!, ...options }\n : { rel: kind, ...(options.as === 'image' && options.imageSrcSet ? {} : { href }), ...options }\n let output = script ? '<script' : '<link'\n for (const name in props) {\n if (name === 'precedence' || late && name === 'data-precedence') continue\n const value = name === 'href' || name === 'src' ? resourceURL(props[name]!) : props[name]!\n output += attrToHtml(name, value).replace(/'/g, ''')\n }\n return output + (script ? '></script>' : '/>')\n}\n\nexport function createResourceHints(shellFlushed = false, styleNonce?: string) {\n const resources = new Map<string, Resource>()\n const groups: Resource[][] = [[], [], [], [], []]\n const styles = new Map<string, Resource[]>()\n const dependencies = new Map<string, string[]>()\n const visibleInline = new Set<string>()\n const collector = {\n add(kind: ResourceHintKind | 'style', href: string, options: ResourceHintOptions): Resource {\n let type: string = kind\n let source = href\n const init = kind === 'style' || kind === 'stylesheet' || kind === 'script' || kind === 'module-script'\n if (kind === 'preload') {\n type = options.as!\n if (type === 'image' && options.imageSrcSet) source = options.imageSrcSet + '\\n' + (options.imageSizes || '')\n } else if (kind === 'modulepreload') type = 'module-' + (options.as || 'script')\n else if (kind === 'stylesheet') type = 'style'\n else if (kind === 'preconnect') type += ':' + (options.crossOrigin ?? 'default')\n const key = JSON.stringify([type, source])\n const prior = resources.get(key)\n if (prior && (!init || prior.kind !== 'preload' && prior.kind !== 'modulepreload')) return prior\n\n const resource: Resource = { kind, href, options: { ...options } }\n if (kind === 'style' && (!styleNonce || options.nonce === styleNonce)) resource.css = styleText(options)\n if (prior) {\n prior.cancelled = true\n resource.preloaded = !!prior.sent\n for (const name of ['crossOrigin', 'integrity']) {\n if (resource.options[name] == null && prior.options[name] != null) resource.options[name] = prior.options[name]!\n }\n }\n resources.set(key, resource)\n if (kind === 'stylesheet' || kind === 'style') {\n const precedence = options.precedence!\n let group = styles.get(precedence)\n if (!group) styles.set(precedence, group = [])\n group.push(resource)\n } else {\n const group = kind === 'dns-prefetch' || kind === 'preconnect' ? 0\n : kind === 'preload' && options.as === 'font' ? 1\n : kind === 'preload' && options.as === 'image' && options.fetchPriority === 'high' ? 2\n : init ? 3 : 4\n groups[group]!.push(resource)\n }\n return resource\n },\n addHost(type: string, props: any, scope?: ResourceScope): boolean {\n const kind = resourceKind(type, props)\n if (!kind) return false\n const resource = collector.add(kind === 'script' && props.type === 'module' ? 'module-script' : kind, kind === 'script' ? props.src : props.href, props)\n if (shellFlushed && kind === 'stylesheet') {\n const descriptor = [resourceURL(resource.href), resource.options.precedence]\n for (const name in resource.options) {\n if (name === 'href' || name === 'rel' || name === 'precedence' || name === 'data-precedence' || name === 'children' || name === 'dangerouslySetInnerHTML' || name === 'innerHTML' || name === 'style' || name === 'suppressHydrationWarning' || name === 'suppressContentEditableWarning' || name === 'ref' || name === 'key' || /^on/i.test(name) || !/^[a-zA-Z_:][a-zA-Z0-9:_.-]*$/.test(name)) continue\n const value = resource.options[name]\n if (value == null || typeof value === 'function' || typeof value === 'symbol' || name === 'hidden' && value === false) continue\n descriptor.push(attributeName(name), name === 'hidden' ? '' : name === 'src' ? resourceURL('' + value) : '' + value)\n }\n ;(scope ? scope.stylesheets ||= new Map() : dependencies).set(resource.href, descriptor)\n } else if (shellFlushed && kind === 'style') {\n ;(scope ? scope.inline ||= new Set() : visibleInline).add(resource.options.precedence)\n }\n return true\n },\n mergeScope(scope: ResourceScope, parent?: ResourceScope): void {\n if (scope.stylesheets) for (const [href, descriptor] of scope.stylesheets) {\n ;(parent ? parent.stylesheets ||= new Map() : dependencies).set(href, descriptor)\n }\n if (scope.inline) for (const precedence of scope.inline) {\n ;(parent ? parent.inline ||= new Set() : visibleInline).add(precedence)\n }\n },\n takeStylesheets(): string[][] {\n const result = Array.from(dependencies.values())\n dependencies.clear()\n return result\n },\n drain(): string {\n let output = ''\n function flush(group: Resource[], precedence?: string) {\n let remaining = 0\n let inline = false, hasStylesheets = false\n let hrefs = '', rules = ''\n for (const resource of group) {\n if (!resource.sent && !resource.cancelled) {\n if (resource.kind === 'style') {\n if (shellFlushed && !visibleInline.has(precedence!)) { group[remaining++] = resource; continue }\n inline = true\n if (resource.css !== undefined) {\n hrefs += (hrefs ? ' ' : '') + resource.href\n rules += resource.css\n }\n } else {\n if (resource.kind === 'stylesheet') hasStylesheets = true\n if (!(shellFlushed && resource.kind === 'stylesheet' && resource.preloaded)) output += markup(resource, shellFlushed)\n }\n resource.sent = true\n }\n }\n group.length = remaining\n if (hrefs || inline && !shellFlushed && !hasStylesheets) {\n output += `<style${styleNonce !== undefined ? ` nonce=\"${escapeAttr(styleNonce)}\"` : ''}${shellFlushed ? ' media=\"not all\"' : ''} data-precedence=\"${escapeAttr(precedence!)}\"${hrefs ? ` data-href=\"${escapeAttr(hrefs)}\"` : ''}>${rules}</style>`\n }\n }\n for (let index = 0; index < groups.length; index++) {\n if (index === 3) for (const [precedence, group] of styles) flush(group, precedence)\n flush(groups[index]!)\n }\n shellFlushed = true\n visibleInline.clear()\n return output\n },\n }\n return collector\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/server/stream.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import type { ReactNode } from
|
|
1
|
+
import type { ReactNode } from "../core/index.js";
|
|
2
|
+
import { type SSRFrame } from "./dispatcher.js";
|
|
3
|
+
import { type BrowserBailoutCallback } from "./walk.js";
|
|
2
4
|
export interface StreamOptions {
|
|
3
5
|
identifierPrefix?: string;
|
|
4
|
-
nonce?: string
|
|
6
|
+
nonce?: string | {
|
|
7
|
+
script?: string;
|
|
8
|
+
style?: string;
|
|
9
|
+
};
|
|
5
10
|
bootstrapScriptContent?: string | ReadonlyArray<string>;
|
|
6
11
|
bootstrapScripts?: ReadonlyArray<string | {
|
|
7
12
|
src: string;
|
|
@@ -13,6 +18,7 @@ export interface StreamOptions {
|
|
|
13
18
|
nonce?: string;
|
|
14
19
|
}>;
|
|
15
20
|
onError?: (error: unknown) => string | void;
|
|
21
|
+
onBrowserBailout?: BrowserBailoutCallback;
|
|
16
22
|
signal?: AbortSignal;
|
|
17
23
|
progressiveChunkSize?: number;
|
|
18
24
|
}
|
|
@@ -22,12 +28,19 @@ export interface ReadableStreamResult extends ReadableStream<Uint8Array> {
|
|
|
22
28
|
export interface PipeableWritable {
|
|
23
29
|
write(chunk: string): unknown;
|
|
24
30
|
end(): unknown;
|
|
31
|
+
destroy?(error?: unknown): unknown;
|
|
25
32
|
}
|
|
26
33
|
export interface OrchestratorState {
|
|
27
34
|
nextId: number;
|
|
28
35
|
pending: Set<Promise<void>>;
|
|
29
36
|
closed: boolean;
|
|
30
37
|
errored: unknown | null;
|
|
38
|
+
aborted: boolean;
|
|
39
|
+
reason: unknown;
|
|
40
|
+
abort: (reason?: unknown) => void;
|
|
41
|
+
cancelled: Promise<void>;
|
|
42
|
+
onShellReady?: () => void;
|
|
43
|
+
frame?: SSRFrame;
|
|
31
44
|
}
|
|
32
45
|
type Emit = (chunk: string) => void;
|
|
33
46
|
export declare function streamHtml(children: ReactNode, emit: Emit, options: StreamOptions, state: OrchestratorState): Promise<void>;
|
package/dist/server/stream.js
CHANGED
|
@@ -1,37 +1,70 @@
|
|
|
1
|
-
//
|
|
1
|
+
// src/server/stream.ts
|
|
2
2
|
import {
|
|
3
3
|
beginSSR,
|
|
4
4
|
endSSR,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "./
|
|
9
|
-
import {
|
|
10
|
-
import { BOUNDARY_REVEAL_RUNTIME, revealScript } from "./bootstrap-script";
|
|
11
|
-
import { escapeScript } from "./escape";
|
|
5
|
+
applyContextSnapshot,
|
|
6
|
+
currentSSRFrame
|
|
7
|
+
} from "./dispatcher.js";
|
|
8
|
+
import { walk } from "./walk.js";
|
|
9
|
+
import { browserError, isBrowserToken, isBrowserError } from "../core/browser.js";
|
|
10
|
+
import { BOUNDARY_REVEAL_RUNTIME, revealScript } from "./bootstrap-script.js";
|
|
11
|
+
import { escapeAttr, escapeScript } from "./escape.js";
|
|
12
|
+
import { resourceURL } from "../core/resource-hints.js";
|
|
13
|
+
function createState() {
|
|
14
|
+
let wake;
|
|
15
|
+
const state = {
|
|
16
|
+
nextId: 0,
|
|
17
|
+
pending: /* @__PURE__ */ new Set(),
|
|
18
|
+
closed: false,
|
|
19
|
+
errored: null,
|
|
20
|
+
aborted: false,
|
|
21
|
+
reason: void 0,
|
|
22
|
+
cancelled: new Promise((resolve) => {
|
|
23
|
+
wake = resolve;
|
|
24
|
+
}),
|
|
25
|
+
abort(reason) {
|
|
26
|
+
if (state.closed || state.aborted) return;
|
|
27
|
+
state.aborted = true;
|
|
28
|
+
state.reason = isBrowserToken(reason) ? browserError(reason) : reason ?? new Error("The render was aborted by the server without a reason.");
|
|
29
|
+
wake();
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
return state;
|
|
33
|
+
}
|
|
12
34
|
async function streamHtml(children, emit, options, state) {
|
|
13
|
-
|
|
14
|
-
beginSSR(options.identifierPrefix);
|
|
15
|
-
const nonce = options.nonce;
|
|
35
|
+
const nonce = scriptNonce(options);
|
|
16
36
|
try {
|
|
17
37
|
const boundaries = [];
|
|
18
38
|
const shellChunks = [];
|
|
39
|
+
let head = 0;
|
|
19
40
|
const bufferedEmit = (chunk) => {
|
|
20
41
|
shellChunks.push(chunk);
|
|
21
42
|
};
|
|
22
43
|
let shellRendered = false;
|
|
23
44
|
let rootRetries = 0;
|
|
45
|
+
let resources;
|
|
24
46
|
while (!shellRendered) {
|
|
25
47
|
const chunkCount = shellChunks.length;
|
|
26
48
|
const boundaryCount = boundaries.length;
|
|
27
49
|
const nextId = state.nextId;
|
|
50
|
+
head = 0;
|
|
51
|
+
const previous = beginSSR(options.identifierPrefix);
|
|
52
|
+
currentSSRFrame().styleNonce = typeof options.nonce === "object" ? options.nonce?.style : void 0;
|
|
53
|
+
if (resources) currentSSRFrame().resources = resources;
|
|
54
|
+
let suspended;
|
|
28
55
|
try {
|
|
56
|
+
if (state.aborted) throw state.reason;
|
|
29
57
|
walk(children, {
|
|
30
58
|
emit: bufferedEmit,
|
|
31
59
|
onSuspend: (b) => boundaries.push(b),
|
|
32
|
-
nextBoundaryId: () => state.nextId
|
|
60
|
+
nextBoundaryId: () => state.nextId++,
|
|
61
|
+
onBrowserBailout: options.onBrowserBailout,
|
|
62
|
+
onHead: () => {
|
|
63
|
+
head = shellChunks.length;
|
|
64
|
+
}
|
|
33
65
|
});
|
|
34
66
|
shellRendered = true;
|
|
67
|
+
state.frame = currentSSRFrame();
|
|
35
68
|
} catch (err) {
|
|
36
69
|
shellChunks.length = chunkCount;
|
|
37
70
|
boundaries.length = boundaryCount;
|
|
@@ -40,12 +73,19 @@ async function streamHtml(children, emit, options, state) {
|
|
|
40
73
|
if (++rootRetries > 50) {
|
|
41
74
|
throw new Error("renderToReadableStream exceeded 50 root suspension retries.");
|
|
42
75
|
}
|
|
43
|
-
|
|
76
|
+
suspended = err;
|
|
77
|
+
} finally {
|
|
78
|
+
resources = currentSSRFrame().resources;
|
|
79
|
+
endSSR(previous);
|
|
44
80
|
}
|
|
81
|
+
if (suspended) await Promise.race([suspended, state.cancelled]);
|
|
45
82
|
}
|
|
83
|
+
const hints = state.frame?.resources?.drain();
|
|
84
|
+
if (hints) shellChunks.splice(head, 0, hints);
|
|
85
|
+
if (state.frame) state.frame.shellFlushed = true;
|
|
46
86
|
const hasBootstrap = bootstrapScriptContentToArray(options.bootstrapScriptContent).length > 0 || (options.bootstrapScripts?.length ?? 0) > 0 || (options.bootstrapModules?.length ?? 0) > 0;
|
|
47
87
|
if (boundaries.length > 0 || hasBootstrap) {
|
|
48
|
-
shellChunks.push(`<script${nonce ? ` nonce="${nonce}"` : ""}>${BOUNDARY_REVEAL_RUNTIME}<\/script>`);
|
|
88
|
+
shellChunks.push(`<script${nonce ? ` nonce="${escapeAttr(nonce)}"` : ""}>${BOUNDARY_REVEAL_RUNTIME}<\/script>`);
|
|
49
89
|
for (const content of bootstrapScriptContentToArray(options.bootstrapScriptContent)) {
|
|
50
90
|
shellChunks.push(inlineBootstrapTag(content, nonce));
|
|
51
91
|
}
|
|
@@ -57,46 +97,74 @@ async function streamHtml(children, emit, options, state) {
|
|
|
57
97
|
}
|
|
58
98
|
}
|
|
59
99
|
if (shellChunks.length) emit(normalizeDocumentShell(shellChunks.join("")));
|
|
100
|
+
state.onShellReady?.();
|
|
60
101
|
for (const b of boundaries) streamBoundary(b, emit, options, state);
|
|
61
102
|
await drain(state);
|
|
62
103
|
} catch (err) {
|
|
104
|
+
if (isBrowserError(err)) {
|
|
105
|
+
err = new Error(
|
|
106
|
+
"The server render could not complete because client rendering was requested outside a Suspense boundary.",
|
|
107
|
+
Object.hasOwn(err, "cause") ? { cause: err.cause } : void 0
|
|
108
|
+
);
|
|
109
|
+
}
|
|
63
110
|
state.errored = err;
|
|
64
111
|
if (options.onError) options.onError(err);
|
|
65
112
|
throw err;
|
|
66
113
|
} finally {
|
|
67
|
-
endSSR();
|
|
68
|
-
uninstallSSRDispatcher();
|
|
69
114
|
state.closed = true;
|
|
70
115
|
}
|
|
71
116
|
}
|
|
72
117
|
function streamBoundary(b, emit, options, state) {
|
|
118
|
+
const nonce = scriptNonce(options);
|
|
73
119
|
const task = (async () => {
|
|
74
120
|
try {
|
|
75
|
-
await b.thenable;
|
|
76
|
-
} catch
|
|
77
|
-
if (options.onError) options.onError(err);
|
|
121
|
+
await Promise.race([b.thenable, state.cancelled]);
|
|
122
|
+
} catch {
|
|
78
123
|
}
|
|
79
124
|
if (state.closed) return;
|
|
125
|
+
const defer = (error) => {
|
|
126
|
+
if (isBrowserError(error)) options.onBrowserBailout?.(error, { componentStack: error.componentStack || b.componentStack });
|
|
127
|
+
else options.onError?.(error);
|
|
128
|
+
emit(`<script${nonce ? ` nonce="${escapeAttr(nonce)}"` : ""}>$RB(${b.id}${isBrowserError(error) ? "" : ",1"})<\/script>`);
|
|
129
|
+
};
|
|
130
|
+
if (state.aborted) {
|
|
131
|
+
defer(state.reason);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
80
134
|
const parts = [];
|
|
81
135
|
const sub = [];
|
|
136
|
+
const resourceScope = {};
|
|
137
|
+
let styles;
|
|
138
|
+
const previous = beginSSR(options.identifierPrefix, state.frame);
|
|
139
|
+
state.frame?.resources?.takeStylesheets();
|
|
82
140
|
const restore = applyContextSnapshot(b.contextSnapshot);
|
|
83
141
|
try {
|
|
84
142
|
walk(b.children, {
|
|
85
143
|
emit: (s) => parts.push(s),
|
|
86
144
|
onSuspend: (n) => sub.push(n),
|
|
87
|
-
nextBoundaryId: () => state.nextId
|
|
145
|
+
nextBoundaryId: () => state.nextId++,
|
|
146
|
+
onBrowserBailout: options.onBrowserBailout,
|
|
147
|
+
componentStack: b.componentStack,
|
|
148
|
+
resourceScope
|
|
88
149
|
});
|
|
150
|
+
state.frame?.resources?.mergeScope(resourceScope);
|
|
89
151
|
} catch (err) {
|
|
90
|
-
if (
|
|
91
|
-
|
|
152
|
+
if (isThenable(err)) {
|
|
153
|
+
streamBoundary({ ...b, thenable: err }, emit, options, state);
|
|
154
|
+
} else defer(err);
|
|
92
155
|
return;
|
|
156
|
+
} finally {
|
|
157
|
+
restore();
|
|
158
|
+
endSSR(previous);
|
|
159
|
+
const hints = state.frame?.resources?.drain();
|
|
160
|
+
styles = state.frame?.resources?.takeStylesheets();
|
|
161
|
+
if (hints) emit(hints);
|
|
93
162
|
}
|
|
94
|
-
|
|
95
|
-
emit(`<div hidden id="S:${b.id}">${parts.join("")}</div>${revealScript(b.id, options.nonce)}`);
|
|
163
|
+
emit(`<div hidden id="S:${b.id}">${parts.join("")}</div>${revealScript(b.id, nonce, styles)}`);
|
|
96
164
|
for (const s of sub) streamBoundary(s, emit, options, state);
|
|
97
165
|
})();
|
|
98
166
|
state.pending.add(task);
|
|
99
|
-
task.
|
|
167
|
+
task.then(() => state.pending.delete(task), () => state.pending.delete(task));
|
|
100
168
|
}
|
|
101
169
|
async function drain(state) {
|
|
102
170
|
while (state.pending.size > 0) {
|
|
@@ -106,12 +174,15 @@ async function drain(state) {
|
|
|
106
174
|
function isThenable(value) {
|
|
107
175
|
return !!value && typeof value.then === "function";
|
|
108
176
|
}
|
|
177
|
+
function scriptNonce(options) {
|
|
178
|
+
return typeof options.nonce === "string" ? options.nonce : options.nonce?.script;
|
|
179
|
+
}
|
|
109
180
|
function bootstrapScriptContentToArray(content) {
|
|
110
181
|
if (content === void 0) return [];
|
|
111
182
|
return typeof content === "string" ? [content] : [...content];
|
|
112
183
|
}
|
|
113
184
|
function inlineBootstrapTag(content, defaultNonce) {
|
|
114
|
-
const nAttr = defaultNonce ? ` nonce="${defaultNonce}"` : "";
|
|
185
|
+
const nAttr = defaultNonce ? ` nonce="${escapeAttr(defaultNonce)}"` : "";
|
|
115
186
|
return `<script${nAttr}>${escapeScript(content)}<\/script>`;
|
|
116
187
|
}
|
|
117
188
|
function normalizeDocumentShell(html) {
|
|
@@ -146,26 +217,37 @@ function stripLeadingHeadTags(value) {
|
|
|
146
217
|
return rest;
|
|
147
218
|
}
|
|
148
219
|
function bootstrapTag(entry, kind, defaultNonce) {
|
|
149
|
-
const src = typeof entry === "string" ? entry : entry.src;
|
|
220
|
+
const src = escapeAttr(resourceURL(typeof entry === "string" ? entry : entry.src));
|
|
150
221
|
const nonce = typeof entry === "string" ? defaultNonce : entry.nonce ?? defaultNonce;
|
|
151
|
-
const nAttr = nonce ? ` nonce="${nonce}"` : "";
|
|
222
|
+
const nAttr = nonce ? ` nonce="${escapeAttr(nonce)}"` : "";
|
|
152
223
|
if (kind === "module") return `<script type="module"${nAttr} src="${src}"><\/script>`;
|
|
153
224
|
return `<script async${nAttr} src="${src}"><\/script>`;
|
|
154
225
|
}
|
|
155
226
|
function renderToReadableStream(children, options = {}) {
|
|
156
|
-
const state =
|
|
157
|
-
nextId: 0,
|
|
158
|
-
pending: /* @__PURE__ */ new Set(),
|
|
159
|
-
closed: false,
|
|
160
|
-
errored: null
|
|
161
|
-
};
|
|
227
|
+
const state = createState();
|
|
162
228
|
const encoder = new TextEncoder();
|
|
229
|
+
let abortListener;
|
|
230
|
+
const detachAbortListener = () => {
|
|
231
|
+
if (abortListener) {
|
|
232
|
+
options.signal?.removeEventListener("abort", abortListener);
|
|
233
|
+
abortListener = void 0;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
163
236
|
let allReadyResolve;
|
|
164
237
|
let allReadyReject;
|
|
165
238
|
const allReady = new Promise((r, rej) => {
|
|
166
239
|
allReadyResolve = r;
|
|
167
240
|
allReadyReject = rej;
|
|
168
241
|
});
|
|
242
|
+
allReady.catch(() => {
|
|
243
|
+
});
|
|
244
|
+
let shellResolve;
|
|
245
|
+
let shellReject;
|
|
246
|
+
const shell = new Promise((resolve, reject) => {
|
|
247
|
+
shellResolve = resolve;
|
|
248
|
+
shellReject = reject;
|
|
249
|
+
});
|
|
250
|
+
state.onShellReady = () => queueMicrotask(() => shellResolve(Object.assign(stream, { allReady })));
|
|
169
251
|
const stream = new ReadableStream({
|
|
170
252
|
start(controller) {
|
|
171
253
|
const emit = (chunk) => {
|
|
@@ -174,8 +256,17 @@ function renderToReadableStream(children, options = {}) {
|
|
|
174
256
|
} catch {
|
|
175
257
|
}
|
|
176
258
|
};
|
|
259
|
+
if (options.signal) {
|
|
260
|
+
abortListener = () => {
|
|
261
|
+
detachAbortListener();
|
|
262
|
+
state.abort(options.signal.reason);
|
|
263
|
+
};
|
|
264
|
+
options.signal.addEventListener("abort", abortListener);
|
|
265
|
+
if (options.signal.aborted) abortListener();
|
|
266
|
+
}
|
|
177
267
|
streamHtml(children, emit, options, state).then(
|
|
178
268
|
() => {
|
|
269
|
+
detachAbortListener();
|
|
179
270
|
try {
|
|
180
271
|
controller.close();
|
|
181
272
|
} catch {
|
|
@@ -183,46 +274,51 @@ function renderToReadableStream(children, options = {}) {
|
|
|
183
274
|
allReadyResolve();
|
|
184
275
|
},
|
|
185
276
|
(err) => {
|
|
277
|
+
detachAbortListener();
|
|
186
278
|
try {
|
|
187
279
|
controller.error(err);
|
|
188
280
|
} catch {
|
|
189
281
|
}
|
|
190
282
|
allReadyReject(err);
|
|
283
|
+
shellReject(err);
|
|
191
284
|
}
|
|
192
285
|
);
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
} catch {
|
|
198
|
-
}
|
|
199
|
-
});
|
|
286
|
+
},
|
|
287
|
+
cancel(reason) {
|
|
288
|
+
state.abort(reason);
|
|
289
|
+
detachAbortListener();
|
|
200
290
|
}
|
|
201
291
|
});
|
|
202
|
-
return
|
|
292
|
+
return shell;
|
|
203
293
|
}
|
|
204
294
|
function renderToPipeableStream(children, options = {}) {
|
|
205
|
-
const state =
|
|
206
|
-
nextId: 0,
|
|
207
|
-
pending: /* @__PURE__ */ new Set(),
|
|
208
|
-
closed: false,
|
|
209
|
-
errored: null
|
|
210
|
-
};
|
|
295
|
+
const state = createState();
|
|
211
296
|
const buffers = [];
|
|
212
297
|
let dest = null;
|
|
213
298
|
let shellReady = false;
|
|
299
|
+
let shellFailed = false;
|
|
214
300
|
let finished = false;
|
|
215
|
-
let
|
|
301
|
+
let failed = false;
|
|
302
|
+
let failure;
|
|
303
|
+
const finishDestination = (target) => {
|
|
304
|
+
if (failed && target.destroy) target.destroy(failure);
|
|
305
|
+
else target.end();
|
|
306
|
+
};
|
|
216
307
|
const flushTo = (w) => {
|
|
217
308
|
if (!buffers.length) return;
|
|
218
309
|
for (const b of buffers) w.write(b);
|
|
219
310
|
buffers.length = 0;
|
|
220
311
|
};
|
|
221
312
|
const emit = (chunk) => {
|
|
222
|
-
if (
|
|
313
|
+
if (finished) return;
|
|
223
314
|
if (dest) dest.write(chunk);
|
|
224
315
|
else buffers.push(chunk);
|
|
225
316
|
};
|
|
317
|
+
state.onShellReady = () => queueMicrotask(() => {
|
|
318
|
+
if (shellFailed) return;
|
|
319
|
+
shellReady = true;
|
|
320
|
+
options.onShellReady?.();
|
|
321
|
+
});
|
|
226
322
|
streamHtml(children, emit, options, state).then(
|
|
227
323
|
() => {
|
|
228
324
|
finished = true;
|
|
@@ -230,30 +326,26 @@ function renderToPipeableStream(children, options = {}) {
|
|
|
230
326
|
options.onAllReady?.();
|
|
231
327
|
},
|
|
232
328
|
(err) => {
|
|
329
|
+
finished = true;
|
|
330
|
+
failed = true;
|
|
331
|
+
failure = err;
|
|
233
332
|
if (!shellReady) {
|
|
333
|
+
shellFailed = true;
|
|
234
334
|
options.onShellError?.(err);
|
|
235
335
|
} else {
|
|
236
|
-
|
|
237
|
-
if (dest) dest.end();
|
|
336
|
+
if (dest) finishDestination(dest);
|
|
238
337
|
}
|
|
239
338
|
}
|
|
240
339
|
);
|
|
241
|
-
queueMicrotask(() => {
|
|
242
|
-
if (aborted || finished) return;
|
|
243
|
-
shellReady = true;
|
|
244
|
-
options.onShellReady?.();
|
|
245
|
-
});
|
|
246
340
|
return {
|
|
247
341
|
pipe(target) {
|
|
248
342
|
dest = target;
|
|
249
|
-
flushTo(target);
|
|
250
|
-
if (finished) target
|
|
343
|
+
if (!failed) flushTo(target);
|
|
344
|
+
if (finished) finishDestination(target);
|
|
251
345
|
return target;
|
|
252
346
|
},
|
|
253
|
-
abort(
|
|
254
|
-
|
|
255
|
-
state.closed = true;
|
|
256
|
-
if (dest) dest.end();
|
|
347
|
+
abort(reason) {
|
|
348
|
+
state.abort(reason);
|
|
257
349
|
}
|
|
258
350
|
};
|
|
259
351
|
}
|