@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.
Files changed (253) hide show
  1. package/dist/core/attributes.js +2 -1
  2. package/dist/core/attributes.js.map +2 -2
  3. package/dist/core/browser.d.ts +9 -0
  4. package/dist/core/browser.js +35 -0
  5. package/dist/core/browser.js.map +7 -0
  6. package/dist/core/index.d.ts +2 -2
  7. package/dist/core/index.js +3 -3
  8. package/dist/core/internal.d.ts +31 -8
  9. package/dist/core/internal.js +3 -1
  10. package/dist/core/internal.js.map +2 -2
  11. package/dist/core/resource-hints.d.ts +7 -0
  12. package/dist/core/resource-hints.js +19 -0
  13. package/dist/core/resource-hints.js.map +7 -0
  14. package/dist/core/types.js +1 -1
  15. package/dist/dom/_all.d.ts +11 -16
  16. package/dist/dom/_all.js +9 -20
  17. package/dist/dom/_all.js.map +2 -2
  18. package/dist/dom/client.d.ts +4 -4
  19. package/dist/dom/client.js +4 -4
  20. package/dist/dom/commit.d.ts +23 -0
  21. package/dist/dom/commit.js +191 -0
  22. package/dist/dom/commit.js.map +7 -0
  23. package/dist/dom/dispatcher.d.ts +4 -22
  24. package/dist/dom/dispatcher.js +184 -126
  25. package/dist/dom/dispatcher.js.map +3 -3
  26. package/dist/dom/dom.d.ts +2 -0
  27. package/dist/dom/dom.js +72 -52
  28. package/dist/dom/dom.js.map +2 -2
  29. package/dist/dom/error-info.d.ts +2 -0
  30. package/dist/dom/error-info.js +16 -0
  31. package/dist/dom/error-info.js.map +7 -0
  32. package/dist/dom/event-replay.js +1 -1
  33. package/dist/dom/features/activity/full.d.ts +1 -0
  34. package/dist/dom/features/activity/full.js +162 -0
  35. package/dist/dom/features/activity/full.js.map +7 -0
  36. package/dist/dom/features/activity/index.d.ts +1 -0
  37. package/dist/dom/features/activity/index.js +3 -0
  38. package/dist/dom/features/activity/index.js.map +7 -0
  39. package/dist/dom/features/activity/stub.d.ts +1 -0
  40. package/dist/dom/features/activity/stub.js +12 -0
  41. package/dist/dom/features/activity/stub.js.map +7 -0
  42. package/dist/dom/features/class/full.js +87 -27
  43. package/dist/dom/features/class/full.js.map +2 -2
  44. package/dist/dom/features/class/index.d.ts +1 -1
  45. package/dist/dom/features/class/index.js +2 -2
  46. package/dist/dom/features/class/stub.js +3 -3
  47. package/dist/dom/features/context/full.d.ts +4 -1
  48. package/dist/dom/features/context/full.js +69 -9
  49. package/dist/dom/features/context/full.js.map +2 -2
  50. package/dist/dom/features/context/index.d.ts +1 -1
  51. package/dist/dom/features/context/index.js +2 -2
  52. package/dist/dom/features/context/stub.d.ts +4 -1
  53. package/dist/dom/features/context/stub.js +15 -4
  54. package/dist/dom/features/context/stub.js.map +2 -2
  55. package/dist/dom/features/forward-ref/full.js +12 -21
  56. package/dist/dom/features/forward-ref/full.js.map +2 -2
  57. package/dist/dom/features/forward-ref/index.d.ts +1 -1
  58. package/dist/dom/features/forward-ref/index.js +2 -2
  59. package/dist/dom/features/forward-ref/stub.js +4 -4
  60. package/dist/dom/features/fragment-refs/index.d.ts +1 -0
  61. package/dist/dom/features/fragment-refs/index.js +8 -0
  62. package/dist/dom/features/fragment-refs/index.js.map +7 -0
  63. package/dist/dom/features/fragment-refs/stub.d.ts +3 -0
  64. package/dist/dom/features/fragment-refs/stub.js +14 -0
  65. package/dist/dom/features/fragment-refs/stub.js.map +7 -0
  66. package/dist/dom/features/hydration/full.d.ts +11 -6
  67. package/dist/dom/features/hydration/full.js +76 -77
  68. package/dist/dom/features/hydration/full.js.map +2 -2
  69. package/dist/dom/features/hydration/index.d.ts +1 -1
  70. package/dist/dom/features/hydration/index.js +2 -2
  71. package/dist/dom/features/hydration/stub.d.ts +7 -2
  72. package/dist/dom/features/hydration/stub.js +1 -1
  73. package/dist/dom/features/hydration/stub.js.map +1 -1
  74. package/dist/dom/features/index.d.ts +8 -7
  75. package/dist/dom/features/index.js +9 -8
  76. package/dist/dom/features/index.js.map +2 -2
  77. package/dist/dom/features/lazy/full.js +4 -4
  78. package/dist/dom/features/lazy/index.d.ts +1 -1
  79. package/dist/dom/features/lazy/index.js +2 -2
  80. package/dist/dom/features/lazy/stub.js +4 -4
  81. package/dist/dom/features/memo/full.js +8 -6
  82. package/dist/dom/features/memo/full.js.map +2 -2
  83. package/dist/dom/features/memo/index.d.ts +1 -1
  84. package/dist/dom/features/memo/index.js +2 -2
  85. package/dist/dom/features/memo/stub.js +4 -4
  86. package/dist/dom/features/portal/full.js +4 -4
  87. package/dist/dom/features/portal/index.d.ts +1 -1
  88. package/dist/dom/features/portal/index.js +2 -2
  89. package/dist/dom/features/portal/stub.js +4 -4
  90. package/dist/dom/features/suspense/full.js +197 -52
  91. package/dist/dom/features/suspense/full.js.map +2 -2
  92. package/dist/dom/features/suspense/index.d.ts +1 -1
  93. package/dist/dom/features/suspense/index.js +2 -2
  94. package/dist/dom/features/suspense/stub.js +4 -4
  95. package/dist/dom/features/view-transition/full.d.ts +6 -0
  96. package/dist/dom/features/view-transition/full.js +280 -0
  97. package/dist/dom/features/view-transition/full.js.map +7 -0
  98. package/dist/dom/features/view-transition/index.d.ts +1 -0
  99. package/dist/dom/features/view-transition/index.js +3 -0
  100. package/dist/dom/features/view-transition/index.js.map +7 -0
  101. package/dist/dom/features/view-transition/resources.d.ts +11 -0
  102. package/dist/dom/features/view-transition/resources.js +108 -0
  103. package/dist/dom/features/view-transition/resources.js.map +7 -0
  104. package/dist/dom/features/view-transition/stub.d.ts +6 -0
  105. package/dist/dom/features/view-transition/stub.js +22 -0
  106. package/dist/dom/features/view-transition/stub.js.map +7 -0
  107. package/dist/dom/features/view-transition/visual.d.ts +14 -0
  108. package/dist/dom/features/view-transition/visual.js +356 -0
  109. package/dist/dom/features/view-transition/visual.js.map +7 -0
  110. package/dist/dom/fragment-instance.d.ts +40 -0
  111. package/dist/dom/fragment-instance.js +324 -0
  112. package/dist/dom/fragment-instance.js.map +7 -0
  113. package/dist/dom/index.d.ts +11 -11
  114. package/dist/dom/index.js +11 -18
  115. package/dist/dom/index.js.map +3 -3
  116. package/dist/dom/portal.d.ts +2 -2
  117. package/dist/dom/portal.js +2 -2
  118. package/dist/dom/portal.js.map +1 -1
  119. package/dist/dom/reconcile.d.ts +32 -3
  120. package/dist/dom/reconcile.js +689 -221
  121. package/dist/dom/reconcile.js.map +2 -2
  122. package/dist/dom/resource-hints.d.ts +6 -0
  123. package/dist/dom/resource-hints.js +115 -0
  124. package/dist/dom/resource-hints.js.map +7 -0
  125. package/dist/dom/resource-store.d.ts +13 -0
  126. package/dist/dom/resource-store.js +43 -0
  127. package/dist/dom/resource-store.js.map +7 -0
  128. package/dist/dom/resources.d.ts +1 -0
  129. package/dist/dom/resources.js +44 -0
  130. package/dist/dom/resources.js.map +7 -0
  131. package/dist/dom/retained-effects.d.ts +6 -0
  132. package/dist/dom/retained-effects.js +49 -0
  133. package/dist/dom/retained-effects.js.map +7 -0
  134. package/dist/dom/root-internal.d.ts +4 -4
  135. package/dist/dom/root-internal.js +2 -2
  136. package/dist/dom/root-internal.js.map +2 -2
  137. package/dist/dom/root.d.ts +5 -5
  138. package/dist/dom/root.js +11 -11
  139. package/dist/dom/root.js.map +2 -2
  140. package/dist/dom/test-utils.js +1 -1
  141. package/dist/react/activity.d.ts +7 -0
  142. package/dist/react/activity.js +8 -0
  143. package/dist/react/activity.js.map +7 -0
  144. package/dist/react/children.d.ts +1 -1
  145. package/dist/react/children.js +3 -3
  146. package/dist/react/children.js.map +1 -1
  147. package/dist/react/class.d.ts +1 -1
  148. package/dist/react/class.js +3 -3
  149. package/dist/react/class.js.map +1 -1
  150. package/dist/react/compiler-runtime.js +2 -2
  151. package/dist/react/context.d.ts +1 -1
  152. package/dist/react/context.js +3 -3
  153. package/dist/react/context.js.map +1 -1
  154. package/dist/react/element.d.ts +6 -3
  155. package/dist/react/element.js +2 -2
  156. package/dist/react/element.js.map +2 -2
  157. package/dist/react/hooks.d.ts +26 -7
  158. package/dist/react/hooks.js +13 -3
  159. package/dist/react/hooks.js.map +2 -2
  160. package/dist/react/index.d.ts +39 -24
  161. package/dist/react/index.js +39 -19
  162. package/dist/react/index.js.map +3 -3
  163. package/dist/react/jsx-runtime.d.ts +2 -2
  164. package/dist/react/jsx-runtime.js +3 -3
  165. package/dist/react/memo.d.ts +1 -1
  166. package/dist/react/memo.js +1 -1
  167. package/dist/react/portal.js +1 -1
  168. package/dist/react/shared-internals.d.ts +15 -5
  169. package/dist/react/shared-internals.js +2 -3
  170. package/dist/react/shared-internals.js.map +2 -2
  171. package/dist/react/suspense.js +1 -1
  172. package/dist/react/view-transition.d.ts +32 -0
  173. package/dist/react/view-transition.js +13 -0
  174. package/dist/react/view-transition.js.map +7 -0
  175. package/dist/scheduler/index.js +1 -1
  176. package/dist/server/bootstrap-script.d.ts +1 -23
  177. package/dist/server/bootstrap-script.js +7 -6
  178. package/dist/server/bootstrap-script.js.map +2 -2
  179. package/dist/server/dispatcher.d.ts +28 -6
  180. package/dist/server/dispatcher.js +33 -15
  181. package/dist/server/dispatcher.js.map +2 -2
  182. package/dist/server/escape.js +16 -15
  183. package/dist/server/escape.js.map +2 -2
  184. package/dist/server/index.d.ts +6 -6
  185. package/dist/server/index.js +7 -7
  186. package/dist/server/renderToString.d.ts +1 -1
  187. package/dist/server/renderToString.js +12 -8
  188. package/dist/server/renderToString.js.map +2 -2
  189. package/dist/server/resource-hints.d.ts +22 -0
  190. package/dist/server/resource-hints.js +148 -0
  191. package/dist/server/resource-hints.js.map +7 -0
  192. package/dist/server/stream.d.ts +15 -2
  193. package/dist/server/stream.js +155 -63
  194. package/dist/server/stream.js.map +2 -2
  195. package/dist/server/walk.d.ts +15 -2
  196. package/dist/server/walk.js +143 -96
  197. package/dist/server/walk.js.map +2 -2
  198. package/dist/vite/index.d.ts +6 -0
  199. package/dist/vite/index.js +22 -6
  200. package/dist/vite/index.js.map +2 -2
  201. package/package.json +1 -1
  202. package/src/core/attributes.ts +1 -0
  203. package/src/core/browser.ts +33 -0
  204. package/src/core/internal.ts +24 -6
  205. package/src/core/resource-hints.ts +36 -0
  206. package/src/dom/_all.ts +1 -7
  207. package/src/dom/commit.ts +186 -0
  208. package/src/dom/dispatcher.ts +190 -134
  209. package/src/dom/dom.ts +70 -54
  210. package/src/dom/error-info.ts +15 -0
  211. package/src/dom/features/activity/full.ts +166 -0
  212. package/src/dom/features/activity/index.ts +1 -0
  213. package/src/dom/features/activity/stub.ts +14 -0
  214. package/src/dom/features/class/full.ts +72 -28
  215. package/src/dom/features/context/full.ts +66 -4
  216. package/src/dom/features/context/stub.ts +6 -0
  217. package/src/dom/features/forward-ref/full.ts +9 -19
  218. package/src/dom/features/fragment-refs/index.ts +1 -0
  219. package/src/dom/features/fragment-refs/stub.ts +3 -0
  220. package/src/dom/features/hydration/full.ts +84 -85
  221. package/src/dom/features/hydration/stub.ts +1 -1
  222. package/src/dom/features/index.ts +1 -0
  223. package/src/dom/features/memo/full.ts +4 -3
  224. package/src/dom/features/suspense/full.ts +192 -55
  225. package/src/dom/features/view-transition/full.ts +288 -0
  226. package/src/dom/features/view-transition/index.ts +1 -0
  227. package/src/dom/features/view-transition/resources.ts +107 -0
  228. package/src/dom/features/view-transition/stub.ts +7 -0
  229. package/src/dom/features/view-transition/visual.ts +406 -0
  230. package/src/dom/fragment-instance.ts +337 -0
  231. package/src/dom/index.ts +6 -7
  232. package/src/dom/portal.ts +1 -1
  233. package/src/dom/reconcile.ts +695 -242
  234. package/src/dom/resource-hints.ts +115 -0
  235. package/src/dom/resource-store.ts +52 -0
  236. package/src/dom/resources.ts +39 -0
  237. package/src/dom/retained-effects.ts +38 -0
  238. package/src/dom/root-internal.ts +4 -4
  239. package/src/dom/root.ts +12 -14
  240. package/src/react/activity.ts +10 -0
  241. package/src/react/element.ts +6 -2
  242. package/src/react/hooks.ts +12 -3
  243. package/src/react/index.ts +18 -0
  244. package/src/react/shared-internals.ts +3 -3
  245. package/src/react/view-transition.ts +41 -0
  246. package/src/server/bootstrap-script.ts +36 -5
  247. package/src/server/dispatcher.ts +35 -13
  248. package/src/server/escape.ts +15 -12
  249. package/src/server/renderToString.ts +7 -5
  250. package/src/server/resource-hints.ts +165 -0
  251. package/src/server/stream.ts +154 -62
  252. package/src/server/walk.ts +72 -11
  253. package/src/vite/index.ts +30 -13
@@ -1,37 +1,70 @@
1
- // packages/redact/src/server/stream.ts
1
+ // src/server/stream.ts
2
2
  import {
3
3
  beginSSR,
4
4
  endSSR,
5
- installSSRDispatcher,
6
- uninstallSSRDispatcher,
7
- applyContextSnapshot
8
- } from "./dispatcher";
9
- import { walk } from "./walk";
10
- import { BOUNDARY_REVEAL_RUNTIME, revealScript } from "./bootstrap-script";
11
- 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
- installSSRDispatcher();
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
- await err;
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 (err) {
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 (options.onError) options.onError(err);
91
- restore();
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
- restore();
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.finally(() => state.pending.delete(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
- options.signal?.addEventListener("abort", () => {
194
- state.closed = true;
195
- try {
196
- controller.close();
197
- } catch {
198
- }
199
- });
286
+ },
287
+ cancel(reason) {
288
+ state.abort(reason);
289
+ detachAbortListener();
200
290
  }
201
291
  });
202
- return Promise.resolve(Object.assign(stream, { allReady }));
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 aborted = false;
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 (aborted || finished) return;
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
- options.onError?.(err);
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.end();
343
+ if (!failed) flushTo(target);
344
+ if (finished) finishDestination(target);
251
345
  return target;
252
346
  },
253
- abort(_reason) {
254
- aborted = true;
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,EACA;AAAA,OACK;AACP,SAAS,YAAoC;AAC7C,SAAS,yBAAyB,oBAAoB;AACtD,SAAS,oBAAoB;AA+B7B,eAAsB,WACpB,UACA,MACA,SACA,OACe;AACf,uBAAqB;AACrB,WAAS,QAAQ,gBAAgB;AACjC,QAAM,QAAQ,QAAQ;AAEtB,MAAI;AACF,UAAM,aAAkC,CAAC;AASzC,UAAM,cAAwB,CAAC;AAC/B,UAAM,eAAqB,CAAC,UAAU;AACpC,kBAAY,KAAK,KAAK;AAAA,IACxB;AAMA,QAAI,gBAAgB;AACpB,QAAI,cAAc;AAClB,WAAO,CAAC,eAAe;AACrB,YAAM,aAAa,YAAY;AAC/B,YAAM,gBAAgB,WAAW;AACjC,YAAM,SAAS,MAAM;AACrB,UAAI;AACF,aAAK,UAAU;AAAA,UACb,MAAM;AAAA,UACN,WAAW,CAAC,MAAM,WAAW,KAAK,CAAC;AAAA,UACnC,gBAAgB,MAAM,MAAM;AAAA,QAC9B,CAAC;AACD,wBAAgB;AAAA,MAClB,SAAS,KAAK;AACZ,oBAAY,SAAS;AACrB,mBAAW,SAAS;AACpB,cAAM,SAAS;AACf,YAAI,CAAC,WAAW,GAAG,EAAG,OAAM;AAC5B,YAAI,EAAE,cAAc,IAAI;AACtB,gBAAM,IAAI,MAAM,6DAA6D;AAAA,QAC/E;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAQA,UAAM,eACJ,8BAA8B,QAAQ,sBAAsB,EAAE,SAAS,MACtE,QAAQ,kBAAkB,UAAU,KAAK,MACzC,QAAQ,kBAAkB,UAAU,KAAK;AAC5C,QAAI,WAAW,SAAS,KAAK,cAAc;AACzC,kBAAY,KAAK,UAAU,QAAQ,WAAW,KAAK,MAAM,EAAE,IAAI,uBAAuB,YAAW;AACjG,iBAAW,WAAW,8BAA8B,QAAQ,sBAAsB,GAAG;AACnF,oBAAY,KAAK,mBAAmB,SAAS,KAAK,CAAC;AAAA,MACrD;AACA,iBAAW,KAAK,QAAQ,oBAAoB,CAAC,GAAG;AAC9C,oBAAY,KAAK,aAAa,GAAG,UAAU,KAAK,CAAC;AAAA,MACnD;AACA,iBAAW,KAAK,QAAQ,oBAAoB,CAAC,GAAG;AAC9C,oBAAY,KAAK,aAAa,GAAG,UAAU,KAAK,CAAC;AAAA,MACnD;AAAA,IACF;AAEA,QAAI,YAAY,OAAQ,MAAK,uBAAuB,YAAY,KAAK,EAAE,CAAC,CAAC;AAGzE,eAAW,KAAK,WAAY,gBAAe,GAAG,MAAM,SAAS,KAAK;AAClE,UAAM,MAAM,KAAK;AAAA,EACnB,SAAS,KAAK;AACZ,UAAM,UAAU;AAChB,QAAI,QAAQ,QAAS,SAAQ,QAAQ,GAAG;AACxC,UAAM;AAAA,EACR,UAAE;AACA,WAAO;AACP,2BAAuB;AACvB,UAAM,SAAS;AAAA,EACjB;AACF;AAEA,SAAS,eACP,GACA,MACA,SACA,OACM;AACN,QAAM,QAAQ,YAAY;AACxB,QAAI;AACF,YAAM,EAAE;AAAA,IACV,SAAS,KAAK;AACZ,UAAI,QAAQ,QAAS,SAAQ,QAAQ,GAAG;AAAA,IAC1C;AACA,QAAI,MAAM,OAAQ;AAIlB,UAAM,QAAkB,CAAC;AACzB,UAAM,MAA2B,CAAC;AAClC,UAAM,UAAU,qBAAqB,EAAE,eAAe;AACtD,QAAI;AACF,WAAK,EAAE,UAAU;AAAA,QACf,MAAM,CAAC,MAAM,MAAM,KAAK,CAAC;AAAA,QACzB,WAAW,CAAC,MAAM,IAAI,KAAK,CAAC;AAAA,QAC5B,gBAAgB,MAAM,MAAM;AAAA,MAC9B,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,UAAI,QAAQ,QAAS,SAAQ,QAAQ,GAAG;AACxC,cAAQ;AACR;AAAA,IACF;AACA,YAAQ;AAER,SAAK,qBAAqB,EAAE,EAAE,KAAK,MAAM,KAAK,EAAE,CAAC,SAAS,aAAa,EAAE,IAAI,QAAQ,KAAK,CAAC,EAAE;AAG7F,eAAW,KAAK,IAAK,gBAAe,GAAG,MAAM,SAAS,KAAK;AAAA,EAC7D,GAAG;AACH,QAAM,QAAQ,IAAI,IAAI;AACtB,OAAK,QAAQ,MAAM,MAAM,QAAQ,OAAO,IAAI,CAAC;AAC/C;AAEA,eAAe,MAAM,OAAyC;AAC5D,SAAO,MAAM,QAAQ,OAAO,GAAG;AAC7B,UAAM,QAAQ,KAAK,MAAM,OAAO;AAAA,EAClC;AACF;AAEA,SAAS,WAAW,OAA2C;AAC7D,SAAO,CAAC,CAAC,SAAS,OAAQ,MAA6B,SAAS;AAClE;AAEA,SAAS,8BACP,SACU;AACV,MAAI,YAAY,OAAW,QAAO,CAAC;AACnC,SAAO,OAAO,YAAY,WAAW,CAAC,OAAO,IAAI,CAAC,GAAG,OAAO;AAC9D;AAEA,SAAS,mBAAmB,SAAiB,cAA0C;AACrF,QAAM,QAAQ,eAAe,WAAW,YAAY,MAAM;AAC1D,SAAO,UAAU,KAAK,IAAI,aAAa,OAAO,CAAC;AACjD;AAEA,SAAS,uBAAuB,MAAsB;AACpD,QAAM,eAAe,KAAK,QAAQ,sBAAsB;AACxD,MAAI,gBAAgB,EAAG,QAAO;AAE9B,QAAM,aAAa,KAAK,MAAM,GAAG,YAAY;AAC7C,MAAI,CAAC,aAAa,UAAU,EAAG,QAAO;AAEtC,QAAM,eAAe,KAAK,MAAM,YAAY;AAC5C,QAAM,WAAW,aAAa,MAAM,oBAAoB;AACxD,MAAI,CAAC,YAAY,SAAS,UAAU,OAAW,QAAO;AAEtD,QAAM,WAAW,SAAS,QAAQ,SAAS,CAAC,EAAE;AAC9C,SAAO,aAAa,MAAM,GAAG,QAAQ,IAAI,aAAa,aAAa,MAAM,QAAQ;AACnF;AAEA,SAAS,aAAa,OAAwB;AAC5C,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,qBAAqB,KAAK,EAAE,KAAK,MAAM;AAChD;AAEA,SAAS,qBAAqB,OAAuB;AACnD,MAAI,OAAO;AACX,MAAI,UAAU;AACd,SAAO,SAAS;AACd,cAAU;AACV,UAAM,OAAO,KAAK;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AACA,QAAI,SAAS,MAAM;AACjB,aAAO;AACP,gBAAU;AAAA,IACZ;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,aACP,OACA,MACA,cACQ;AACR,QAAM,MAAM,OAAO,UAAU,WAAW,QAAQ,MAAM;AACtD,QAAM,QAAQ,OAAO,UAAU,WAAW,eAAe,MAAM,SAAS;AACxE,QAAM,QAAQ,QAAQ,WAAW,KAAK,MAAM;AAC5C,MAAI,SAAS,SAAU,QAAO,wBAAwB,KAAK,SAAS,GAAG;AACvE,SAAO,gBAAgB,KAAK,SAAS,GAAG;AAC1C;AAMO,SAAS,uBACd,UACA,UAAyB,CAAC,GACK;AAC/B,QAAM,QAA2B;AAAA,IAC/B,QAAQ;AAAA,IACR,SAAS,oBAAI,IAAI;AAAA,IACjB,QAAQ;AAAA,IACR,SAAS;AAAA,EACX;AACA,QAAM,UAAU,IAAI,YAAY;AAEhC,MAAI;AACJ,MAAI;AACJ,QAAM,WAAW,IAAI,QAAc,CAAC,GAAG,QAAQ;AAC7C,sBAAkB;AAClB,qBAAiB;AAAA,EACnB,CAAC;AAED,QAAM,SAAS,IAAI,eAA2B;AAAA,IAC5C,MAAM,YAAY;AAChB,YAAM,OAAO,CAAC,UAAkB;AAC9B,YAAI;AACF,qBAAW,QAAQ,QAAQ,OAAO,KAAK,CAAC;AAAA,QAC1C,QAAQ;AAAA,QAAC;AAAA,MACX;AAEA,iBAAW,UAAU,MAAM,SAAS,KAAK,EAAE;AAAA,QACzC,MAAM;AACJ,cAAI;AACF,uBAAW,MAAM;AAAA,UACnB,QAAQ;AAAA,UAAC;AACT,0BAAgB;AAAA,QAClB;AAAA,QACA,CAAC,QAAQ;AACP,cAAI;AACF,uBAAW,MAAM,GAAG;AAAA,UACtB,QAAQ;AAAA,UAAC;AACT,yBAAe,GAAG;AAAA,QACpB;AAAA,MACF;AAEA,cAAQ,QAAQ,iBAAiB,SAAS,MAAM;AAC9C,cAAM,SAAS;AACf,YAAI;AACF,qBAAW,MAAM;AAAA,QACnB,QAAQ;AAAA,QAAC;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,SAAO,QAAQ,QAAQ,OAAO,OAAO,QAAQ,EAAE,SAAS,CAAC,CAAC;AAC5D;AAiBO,SAAS,uBACd,UACA,UAA2B,CAAC,GACZ;AAChB,QAAM,QAA2B;AAAA,IAC/B,QAAQ;AAAA,IACR,SAAS,oBAAI,IAAI;AAAA,IACjB,QAAQ;AAAA,IACR,SAAS;AAAA,EACX;AAEA,QAAM,UAAoB,CAAC;AAC3B,MAAI,OAAgC;AACpC,MAAI,aAAa;AACjB,MAAI,WAAW;AACf,MAAI,UAAU;AAEd,QAAM,UAAU,CAAC,MAAwB;AACvC,QAAI,CAAC,QAAQ,OAAQ;AACrB,eAAW,KAAK,QAAS,GAAE,MAAM,CAAC;AAClC,YAAQ,SAAS;AAAA,EACnB;AAEA,QAAM,OAAa,CAAC,UAAU;AAC5B,QAAI,WAAW,SAAU;AACzB,QAAI,KAAM,MAAK,MAAM,KAAK;AAAA,QACrB,SAAQ,KAAK,KAAK;AAAA,EACzB;AAGA,aAAW,UAAU,MAAM,SAAS,KAAK,EAAE;AAAA,IACzC,MAAM;AACJ,iBAAW;AACX,UAAI,KAAM,MAAK,IAAI;AACnB,cAAQ,aAAa;AAAA,IACvB;AAAA,IACA,CAAC,QAAQ;AACP,UAAI,CAAC,YAAY;AACf,gBAAQ,eAAe,GAAG;AAAA,MAC5B,OAAO;AACL,gBAAQ,UAAU,GAAG;AACrB,YAAI,KAAM,MAAK,IAAI;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAKA,iBAAe,MAAM;AACnB,QAAI,WAAW,SAAU;AACzB,iBAAa;AACb,YAAQ,eAAe;AAAA,EACzB,CAAC;AAED,SAAO;AAAA,IACL,KAAiC,QAAc;AAC7C,aAAO;AACP,cAAQ,MAAM;AACd,UAAI,SAAU,QAAO,IAAI;AACzB,aAAO;AAAA,IACT;AAAA,IACA,MAAM,SAAmB;AACvB,gBAAU;AACV,YAAM,SAAS;AACf,UAAI,KAAM,MAAK,IAAI;AAAA,IACrB;AAAA,EACF;AACF;",
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
  }
@@ -1,19 +1,32 @@
1
- import { type ReactNode } from '../core';
2
- import { type ContextSnapshot } from './dispatcher';
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