@tanstack/redact 0.0.21 → 0.1.0
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 +69 -9
- 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 +15 -4
- 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 +1 -1
- package/dist/react/context.js +3 -3
- package/dist/react/context.js.map +1 -1
- package/dist/react/element.d.ts +6 -3
- package/dist/react/element.js +2 -2
- 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 +143 -96
- 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 +66 -4
- package/src/dom/features/context/stub.ts +6 -0
- 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/element.ts +6 -2
- 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 +72 -11
- package/src/vite/index.ts +30 -13
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
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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'\nimport { escapeScript } from './escape'\n\nexport interface StreamOptions {\n identifierPrefix?: string\n nonce?: string\n bootstrapScriptContent?: string | ReadonlyArray<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 PipeableWritable {\n write(chunk: string): unknown\n end(): unknown\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. A root-level `use(promise)` has no Suspense\n // boundary to capture it, but App Router SSR commonly suspends at this\n // level while resolving the RSC stream. Wait and retry without leaking\n // partial shell chunks or boundary ids from the aborted attempt.\n let shellRendered = false\n let rootRetries = 0\n while (!shellRendered) {\n const chunkCount = shellChunks.length\n const boundaryCount = boundaries.length\n const nextId = state.nextId\n try {\n walk(children, {\n emit: bufferedEmit,\n onSuspend: (b) => boundaries.push(b),\n nextBoundaryId: () => state.nextId++,\n })\n shellRendered = true\n } catch (err) {\n shellChunks.length = chunkCount\n boundaries.length = boundaryCount\n state.nextId = nextId\n if (!isThenable(err)) throw err\n if (++rootRetries > 50) {\n throw new Error('renderToReadableStream exceeded 50 root suspension retries.')\n }\n await err\n }\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 bootstrapScriptContentToArray(options.bootstrapScriptContent).length > 0 ||\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 content of bootstrapScriptContentToArray(options.bootstrapScriptContent)) {\n shellChunks.push(inlineBootstrapTag(content, nonce))\n }\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(normalizeDocumentShell(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 isThenable(value: unknown): value is Promise<unknown> {\n return !!value && typeof (value as { then?: unknown }).then === 'function'\n}\n\nfunction bootstrapScriptContentToArray(\n content: StreamOptions['bootstrapScriptContent'],\n): string[] {\n if (content === undefined) return []\n return typeof content === 'string' ? [content] : [...content]\n}\n\nfunction inlineBootstrapTag(content: string, defaultNonce: string | undefined): string {\n const nAttr = defaultNonce ? ` nonce=\"${defaultNonce}\"` : ''\n return `<script${nAttr}>${escapeScript(content)}</script>`\n}\n\nfunction normalizeDocumentShell(html: string): string {\n const doctypeIndex = html.indexOf('<!DOCTYPE html><html')\n if (doctypeIndex <= 0) return html\n\n const headPrefix = html.slice(0, doctypeIndex)\n if (!isHeadPrefix(headPrefix)) return html\n\n const documentHtml = html.slice(doctypeIndex)\n const headOpen = documentHtml.match(/<head(?:\\s[^>]*)?>/)\n if (!headOpen || headOpen.index === undefined) return html\n\n const insertAt = headOpen.index + headOpen[0].length\n return documentHtml.slice(0, insertAt) + headPrefix + documentHtml.slice(insertAt)\n}\n\nfunction isHeadPrefix(value: string): boolean {\n if (!value) return false\n return stripLeadingHeadTags(value).trim() === ''\n}\n\nfunction stripLeadingHeadTags(value: string): string {\n let rest = value\n let changed = true\n while (changed) {\n changed = false\n const next = rest.replace(\n /^\\s*(?:<meta\\b[^>]*>|<link\\b[^>]*>|<base\\b[^>]*>|<title\\b[^>]*>[\\s\\S]*?<\\/title>|<style\\b[^>]*>[\\s\\S]*?<\\/style>|<script\\b[^>]*>[\\s\\S]*?<\\/script>)/i,\n '',\n )\n if (next !== rest) {\n rest = next\n changed = true\n }\n }\n return rest\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 PipeableWritable>(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: PipeableWritable | null = null\n let shellReady = false\n let finished = false\n let aborted = false\n\n const flushTo = (w: PipeableWritable) => {\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 PipeableWritable>(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": ";AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,
|
|
4
|
+
"sourcesContent": ["import type { ReactNode } from '../core'\nimport {\n beginSSR,\n endSSR,\n applyContextSnapshot,\n currentSSRFrame,\n type SSRFrame,\n} from './dispatcher'\nimport { walk, type SuspendedBoundary, type BrowserBailoutCallback } from './walk'\nimport { browserError, isBrowserToken, isBrowserError } from '../core/browser'\nimport { BOUNDARY_REVEAL_RUNTIME, revealScript } from './bootstrap-script'\nimport { escapeAttr, escapeScript } from './escape'\nimport { resourceURL } from '../core/resource-hints'\nimport type { ResourceScope } from './resource-hints'\n\nexport interface StreamOptions {\n identifierPrefix?: string\n nonce?: string | { script?: string; style?: string }\n bootstrapScriptContent?: string | ReadonlyArray<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 onBrowserBailout?: BrowserBailoutCallback\n signal?: AbortSignal\n progressiveChunkSize?: number\n}\n\nexport interface ReadableStreamResult extends ReadableStream<Uint8Array> {\n allReady: Promise<void>\n}\n\nexport interface PipeableWritable {\n write(chunk: string): unknown\n end(): unknown\n destroy?(error?: unknown): unknown\n}\n\nexport interface OrchestratorState {\n nextId: number\n pending: Set<Promise<void>>\n closed: boolean\n errored: unknown | null\n aborted: boolean\n reason: unknown\n abort: (reason?: unknown) => void\n cancelled: Promise<void>\n onShellReady?: () => void\n frame?: SSRFrame\n}\n\nfunction createState(): OrchestratorState {\n let wake!: () => void\n const state: OrchestratorState = {\n nextId: 0, pending: new Set(), closed: false, errored: null,\n aborted: false, reason: undefined,\n cancelled: new Promise<void>((resolve) => { wake = resolve }),\n abort(reason) {\n if (state.closed || state.aborted) return\n state.aborted = true\n state.reason = isBrowserToken(reason) ? browserError(reason) : reason ?? new Error('The render was aborted by the server without a reason.')\n wake()\n },\n }\n return state\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 const nonce = scriptNonce(options)\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 let head = 0\n const bufferedEmit: Emit = (chunk) => {\n shellChunks.push(chunk)\n }\n\n // 1. Render the shell. A root-level `use(promise)` has no Suspense\n // boundary to capture it, but App Router SSR commonly suspends at this\n // level while resolving the RSC stream. Wait and retry without leaking\n // partial shell chunks or boundary ids from the aborted attempt.\n let shellRendered = false\n let rootRetries = 0\n let resources: SSRFrame['resources']\n while (!shellRendered) {\n const chunkCount = shellChunks.length\n const boundaryCount = boundaries.length\n const nextId = state.nextId\n head = 0\n const previous = beginSSR(options.identifierPrefix)\n currentSSRFrame().styleNonce = typeof options.nonce === 'object' ? options.nonce?.style : undefined\n if (resources) currentSSRFrame().resources = resources\n let suspended: Promise<unknown> | undefined\n try {\n if (state.aborted) throw state.reason\n walk(children, {\n emit: bufferedEmit,\n onSuspend: (b) => boundaries.push(b),\n nextBoundaryId: () => state.nextId++,\n onBrowserBailout: options.onBrowserBailout,\n onHead: () => { head = shellChunks.length },\n })\n shellRendered = true\n state.frame = currentSSRFrame()\n } catch (err) {\n shellChunks.length = chunkCount\n boundaries.length = boundaryCount\n state.nextId = nextId\n if (!isThenable(err)) throw err\n if (++rootRetries > 50) {\n throw new Error('renderToReadableStream exceeded 50 root suspension retries.')\n }\n suspended = err\n } finally {\n resources = currentSSRFrame().resources\n endSSR(previous)\n }\n if (suspended) await Promise.race([suspended, state.cancelled])\n }\n\n const hints = state.frame?.resources?.drain()\n if (hints) shellChunks.splice(head, 0, hints)\n if (state.frame) state.frame.shellFlushed = true\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 bootstrapScriptContentToArray(options.bootstrapScriptContent).length > 0 ||\n (options.bootstrapScripts?.length ?? 0) > 0 ||\n (options.bootstrapModules?.length ?? 0) > 0\n if (boundaries.length > 0 || hasBootstrap) {\n shellChunks.push(`<script${nonce ? ` nonce=\"${escapeAttr(nonce)}\"` : ''}>${BOUNDARY_REVEAL_RUNTIME}</script>`)\n for (const content of bootstrapScriptContentToArray(options.bootstrapScriptContent)) {\n shellChunks.push(inlineBootstrapTag(content, nonce))\n }\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(normalizeDocumentShell(shellChunks.join('')))\n state.onShellReady?.()\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 if (isBrowserError(err)) {\n err = new Error('The server render could not complete because client rendering was requested outside a Suspense boundary.',\n Object.hasOwn(err, 'cause') ? { cause: err.cause } : undefined)\n }\n state.errored = err\n if (options.onError) options.onError(err)\n throw err\n } finally {\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 nonce = scriptNonce(options)\n const task = (async () => {\n try {\n await Promise.race([b.thenable, state.cancelled])\n } catch {}\n if (state.closed) return\n\n const defer = (error: unknown) => {\n if (isBrowserError(error)) options.onBrowserBailout?.(error, { componentStack: (error as any).componentStack || b.componentStack })\n else options.onError?.(error)\n emit(`<script${nonce ? ` nonce=\"${escapeAttr(nonce)}\"` : ''}>$RB(${b.id}${isBrowserError(error) ? '' : ',1'})</script>`)\n }\n if (state.aborted) { defer(state.reason); 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 resourceScope: ResourceScope = {}\n let styles: string[][] | undefined\n const previous = beginSSR(options.identifierPrefix, state.frame)\n state.frame?.resources?.takeStylesheets()\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 onBrowserBailout: options.onBrowserBailout,\n componentStack: b.componentStack,\n resourceScope,\n })\n state.frame?.resources?.mergeScope(resourceScope)\n } catch (err) {\n if (isThenable(err)) {\n streamBoundary({ ...b, thenable: err }, emit, options, state)\n } else defer(err)\n return\n } finally {\n restore()\n endSSR(previous)\n const hints = state.frame?.resources?.drain()\n styles = state.frame?.resources?.takeStylesheets()\n if (hints) emit(hints)\n }\n\n emit(`<div hidden id=\"S:${b.id}\">${parts.join('')}</div>${revealScript(b.id, nonce, styles)}`)\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.then(() => state.pending.delete(task), () => 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 isThenable(value: unknown): value is Promise<unknown> {\n return !!value && typeof (value as { then?: unknown }).then === 'function'\n}\n\nfunction scriptNonce(options: StreamOptions): string | undefined {\n return typeof options.nonce === 'string' ? options.nonce : options.nonce?.script\n}\n\nfunction bootstrapScriptContentToArray(\n content: StreamOptions['bootstrapScriptContent'],\n): string[] {\n if (content === undefined) return []\n return typeof content === 'string' ? [content] : [...content]\n}\n\nfunction inlineBootstrapTag(content: string, defaultNonce: string | undefined): string {\n const nAttr = defaultNonce ? ` nonce=\"${escapeAttr(defaultNonce)}\"` : ''\n return `<script${nAttr}>${escapeScript(content)}</script>`\n}\n\nfunction normalizeDocumentShell(html: string): string {\n const doctypeIndex = html.indexOf('<!DOCTYPE html><html')\n if (doctypeIndex <= 0) return html\n\n const headPrefix = html.slice(0, doctypeIndex)\n if (!isHeadPrefix(headPrefix)) return html\n\n const documentHtml = html.slice(doctypeIndex)\n const headOpen = documentHtml.match(/<head(?:\\s[^>]*)?>/)\n if (!headOpen || headOpen.index === undefined) return html\n\n const insertAt = headOpen.index + headOpen[0].length\n return documentHtml.slice(0, insertAt) + headPrefix + documentHtml.slice(insertAt)\n}\n\nfunction isHeadPrefix(value: string): boolean {\n if (!value) return false\n return stripLeadingHeadTags(value).trim() === ''\n}\n\nfunction stripLeadingHeadTags(value: string): string {\n let rest = value\n let changed = true\n while (changed) {\n changed = false\n const next = rest.replace(\n /^\\s*(?:<meta\\b[^>]*>|<link\\b[^>]*>|<base\\b[^>]*>|<title\\b[^>]*>[\\s\\S]*?<\\/title>|<style\\b[^>]*>[\\s\\S]*?<\\/style>|<script\\b[^>]*>[\\s\\S]*?<\\/script>)/i,\n '',\n )\n if (next !== rest) {\n rest = next\n changed = true\n }\n }\n return rest\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 = escapeAttr(resourceURL(typeof entry === 'string' ? entry : entry.src))\n const nonce = typeof entry === 'string' ? defaultNonce : entry.nonce ?? defaultNonce\n const nAttr = nonce ? ` nonce=\"${escapeAttr(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 = createState()\n const encoder = new TextEncoder()\n let abortListener: (() => void) | undefined\n const detachAbortListener = () => {\n if (abortListener) {\n options.signal?.removeEventListener('abort', abortListener)\n abortListener = undefined\n }\n }\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 // Shell failures reject the outer promise before callers receive allReady.\n allReady.catch(() => {})\n let shellResolve!: (stream: ReadableStreamResult) => void\n let shellReject!: (error: unknown) => void\n const shell = new Promise<ReadableStreamResult>((resolve, reject) => {\n shellResolve = resolve\n shellReject = reject\n })\n state.onShellReady = () => queueMicrotask(() => shellResolve(Object.assign(stream, { allReady })))\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 if (options.signal) {\n abortListener = () => {\n detachAbortListener()\n state.abort(options.signal!.reason)\n }\n options.signal.addEventListener('abort', abortListener)\n if (options.signal.aborted) abortListener()\n }\n\n streamHtml(children, emit, options, state).then(\n () => {\n detachAbortListener()\n try {\n controller.close()\n } catch {}\n allReadyResolve()\n },\n (err) => {\n detachAbortListener()\n try {\n controller.error(err)\n } catch {}\n allReadyReject(err)\n shellReject(err)\n },\n )\n\n },\n cancel(reason) {\n state.abort(reason)\n detachAbortListener()\n },\n })\n\n return shell\n}\n\n// ---------------------------------------------------------------------------\n// Node Streams: renderToPipeableStream\n// ---------------------------------------------------------------------------\n\nexport interface PipeableHandle {\n pipe<T extends PipeableWritable>(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 = createState()\n\n const buffers: string[] = []\n let dest: PipeableWritable | null = null\n let shellReady = false\n let shellFailed = false\n let finished = false\n let failed = false\n let failure: unknown\n\n const finishDestination = (target: PipeableWritable) => {\n if (failed && target.destroy) target.destroy(failure)\n else target.end()\n }\n\n const flushTo = (w: PipeableWritable) => {\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 (finished) return\n if (dest) dest.write(chunk)\n else buffers.push(chunk)\n }\n\n state.onShellReady = () => queueMicrotask(() => {\n if (shellFailed) return\n shellReady = true\n options.onShellReady?.()\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 finished = true\n failed = true\n failure = err\n if (!shellReady) {\n shellFailed = true\n options.onShellError?.(err)\n } else {\n if (dest) finishDestination(dest)\n }\n },\n )\n\n return {\n pipe<T extends PipeableWritable>(target: T): T {\n dest = target\n if (!failed) flushTo(target)\n if (finished) finishDestination(target)\n return target\n },\n abort(reason?: unknown) {\n state.abort(reason)\n },\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/server/walk.d.ts
CHANGED
|
@@ -1,19 +1,32 @@
|
|
|
1
|
-
import { type ReactNode } from
|
|
2
|
-
import { type ContextSnapshot } from
|
|
1
|
+
import { type ReactNode } from "../core/index.js";
|
|
2
|
+
import { type ContextSnapshot } from "./dispatcher.js";
|
|
3
|
+
import type { ResourceScope } from "./resource-hints.js";
|
|
4
|
+
export interface ServerErrorInfo {
|
|
5
|
+
componentStack: string;
|
|
6
|
+
}
|
|
7
|
+
export type BrowserBailoutCallback = (error: Error, errorInfo: ServerErrorInfo) => void;
|
|
3
8
|
export interface SuspendedBoundary {
|
|
4
9
|
id: number;
|
|
5
10
|
fallbackHTML: string;
|
|
6
11
|
children: ReactNode;
|
|
7
12
|
thenable: Promise<any>;
|
|
8
13
|
contextSnapshot: ContextSnapshot;
|
|
14
|
+
componentStack: string;
|
|
9
15
|
}
|
|
10
16
|
export interface WalkOptions {
|
|
11
17
|
emit: (chunk: string) => void;
|
|
18
|
+
onHead?: () => void;
|
|
12
19
|
onSuspend?: ((boundary: SuspendedBoundary) => void) | undefined;
|
|
20
|
+
onBrowserBailout?: BrowserBailoutCallback | undefined;
|
|
21
|
+
componentStack?: string | undefined;
|
|
22
|
+
thrownInfo?: {
|
|
23
|
+
componentStack?: string | undefined;
|
|
24
|
+
};
|
|
13
25
|
nextBoundaryId: () => number;
|
|
14
26
|
bootstrapped?: boolean | undefined;
|
|
15
27
|
isBoundaryResolution?: boolean | undefined;
|
|
16
28
|
isSvg?: boolean | undefined;
|
|
29
|
+
resourceScope?: ResourceScope | undefined;
|
|
17
30
|
/**
|
|
18
31
|
* Tracks whether the most recent emission within the *current text flow*
|
|
19
32
|
* ended with a text node. When the next emission is also text, we emit a
|