@fictjs/runtime 0.5.1 → 0.5.2

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 (48) hide show
  1. package/dist/advanced.cjs +9 -9
  2. package/dist/advanced.js +4 -4
  3. package/dist/{chunk-AR6NSCZM.js → chunk-4NUHM77Z.js} +3 -3
  4. package/dist/{chunk-RY5CY4CI.js → chunk-D2IWOO4X.js} +2 -2
  5. package/dist/{chunk-LFMXNQZC.cjs → chunk-KNGHYGK4.cjs} +17 -17
  6. package/dist/{chunk-LFMXNQZC.cjs.map → chunk-KNGHYGK4.cjs.map} +1 -1
  7. package/dist/{chunk-7BO6P2KP.js → chunk-LRFMCJY3.js} +84 -1
  8. package/dist/chunk-LRFMCJY3.js.map +1 -0
  9. package/dist/{chunk-4ZPZM5IG.cjs → chunk-QB2UD62G.cjs} +8 -8
  10. package/dist/{chunk-4ZPZM5IG.cjs.map → chunk-QB2UD62G.cjs.map} +1 -1
  11. package/dist/{chunk-5OYBRKE4.js → chunk-SLFAEVKJ.js} +3 -3
  12. package/dist/{chunk-WJHXPF7M.cjs → chunk-Z6M3HKLG.cjs} +156 -156
  13. package/dist/{chunk-WJHXPF7M.cjs.map → chunk-Z6M3HKLG.cjs.map} +1 -1
  14. package/dist/{chunk-6RCEIWZL.cjs → chunk-ZR435MDC.cjs} +85 -2
  15. package/dist/chunk-ZR435MDC.cjs.map +1 -0
  16. package/dist/index.cjs +95 -45
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.dev.js +87 -7
  19. package/dist/index.dev.js.map +1 -1
  20. package/dist/index.js +60 -10
  21. package/dist/index.js.map +1 -1
  22. package/dist/internal.cjs +51 -41
  23. package/dist/internal.cjs.map +1 -1
  24. package/dist/internal.d.cts +11 -2
  25. package/dist/internal.d.ts +11 -2
  26. package/dist/internal.js +13 -3
  27. package/dist/internal.js.map +1 -1
  28. package/dist/jsx-dev-runtime.d.cts +671 -0
  29. package/dist/jsx-dev-runtime.d.ts +671 -0
  30. package/dist/loader.cjs +60 -8
  31. package/dist/loader.cjs.map +1 -1
  32. package/dist/loader.d.cts +1 -1
  33. package/dist/loader.d.ts +1 -1
  34. package/dist/loader.js +53 -1
  35. package/dist/loader.js.map +1 -1
  36. package/dist/{resume-Dx8_l72o.d.ts → resume-CqeQ3v_q.d.ts} +5 -1
  37. package/dist/{resume-BrAkmSTY.d.cts → resume-i-A3EFox.d.cts} +5 -1
  38. package/package.json +1 -1
  39. package/src/internal.ts +4 -0
  40. package/src/loader.ts +58 -0
  41. package/src/resume.ts +55 -0
  42. package/src/ssr-stream.ts +38 -0
  43. package/src/suspense.ts +62 -7
  44. package/dist/chunk-6RCEIWZL.cjs.map +0 -1
  45. package/dist/chunk-7BO6P2KP.js.map +0 -1
  46. /package/dist/{chunk-AR6NSCZM.js.map → chunk-4NUHM77Z.js.map} +0 -0
  47. /package/dist/{chunk-RY5CY4CI.js.map → chunk-D2IWOO4X.js.map} +0 -0
  48. /package/dist/{chunk-5OYBRKE4.js.map → chunk-SLFAEVKJ.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
 
4
4
 
5
- var _chunkLFMXNQZCcjs = require('./chunk-LFMXNQZC.cjs');
5
+ var _chunkKNGHYGK4cjs = require('./chunk-KNGHYGK4.cjs');
6
6
 
7
7
 
8
8
 
@@ -19,7 +19,7 @@ var _chunkLFMXNQZCcjs = require('./chunk-LFMXNQZC.cjs');
19
19
 
20
20
 
21
21
 
22
- var _chunkWJHXPF7Mcjs = require('./chunk-WJHXPF7M.cjs');
22
+ var _chunkZ6M3HKLGcjs = require('./chunk-Z6M3HKLG.cjs');
23
23
 
24
24
 
25
25
 
@@ -37,7 +37,10 @@ var _chunkWJHXPF7Mcjs = require('./chunk-WJHXPF7M.cjs');
37
37
 
38
38
 
39
39
 
40
- var _chunk6RCEIWZLcjs = require('./chunk-6RCEIWZL.cjs');
40
+
41
+
42
+
43
+ var _chunkZR435MDCcjs = require('./chunk-ZR435MDC.cjs');
41
44
 
42
45
  // src/ref.ts
43
46
  function createRef() {
@@ -49,7 +52,7 @@ function ErrorBoundary(props) {
49
52
  const fragment = document.createDocumentFragment();
50
53
  const marker = document.createComment("fict:error-boundary");
51
54
  fragment.appendChild(marker);
52
- const hostRoot = _chunk6RCEIWZLcjs.getCurrentRoot.call(void 0, );
55
+ const hostRoot = _chunkZR435MDCcjs.getCurrentRoot.call(void 0, );
53
56
  let cleanup;
54
57
  let activeNodes = [];
55
58
  let renderingFallback = false;
@@ -67,25 +70,25 @@ function ErrorBoundary(props) {
67
70
  cleanup = void 0;
68
71
  }
69
72
  if (activeNodes.length) {
70
- _chunkWJHXPF7Mcjs.removeNodes.call(void 0, activeNodes);
73
+ _chunkZ6M3HKLGcjs.removeNodes.call(void 0, activeNodes);
71
74
  activeNodes = [];
72
75
  }
73
76
  if (value == null || value === false) {
74
77
  return;
75
78
  }
76
- const root = _chunk6RCEIWZLcjs.createRootContext.call(void 0, hostRoot);
77
- const prev = _chunk6RCEIWZLcjs.pushRoot.call(void 0, root);
79
+ const root = _chunkZR435MDCcjs.createRootContext.call(void 0, hostRoot);
80
+ const prev = _chunkZR435MDCcjs.pushRoot.call(void 0, root);
78
81
  let nodes = [];
79
82
  try {
80
- const output = _chunkWJHXPF7Mcjs.createElement.call(void 0, value);
81
- nodes = _chunkWJHXPF7Mcjs.toNodeArray.call(void 0, output);
83
+ const output = _chunkZ6M3HKLGcjs.createElement.call(void 0, value);
84
+ nodes = _chunkZ6M3HKLGcjs.toNodeArray.call(void 0, output);
82
85
  const parentNode = marker.parentNode;
83
86
  if (parentNode) {
84
- _chunkWJHXPF7Mcjs.insertNodesBefore.call(void 0, parentNode, nodes, marker);
87
+ _chunkZ6M3HKLGcjs.insertNodesBefore.call(void 0, parentNode, nodes, marker);
85
88
  }
86
89
  } catch (err) {
87
- _chunk6RCEIWZLcjs.popRoot.call(void 0, prev);
88
- _chunk6RCEIWZLcjs.destroyRoot.call(void 0, root);
90
+ _chunkZR435MDCcjs.popRoot.call(void 0, prev);
91
+ _chunkZR435MDCcjs.destroyRoot.call(void 0, root);
89
92
  if (renderingFallback) {
90
93
  throw err;
91
94
  }
@@ -100,11 +103,11 @@ function ErrorBoundary(props) {
100
103
  }
101
104
  return;
102
105
  }
103
- _chunk6RCEIWZLcjs.popRoot.call(void 0, prev);
104
- _chunk6RCEIWZLcjs.flushOnMount.call(void 0, root);
106
+ _chunkZR435MDCcjs.popRoot.call(void 0, prev);
107
+ _chunkZR435MDCcjs.flushOnMount.call(void 0, root);
105
108
  cleanup = () => {
106
- _chunk6RCEIWZLcjs.destroyRoot.call(void 0, root);
107
- _chunkWJHXPF7Mcjs.removeNodes.call(void 0, nodes);
109
+ _chunkZR435MDCcjs.destroyRoot.call(void 0, root);
110
+ _chunkZ6M3HKLGcjs.removeNodes.call(void 0, nodes);
108
111
  };
109
112
  activeNodes = nodes;
110
113
  };
@@ -113,7 +116,7 @@ function ErrorBoundary(props) {
113
116
  renderValue(toView(null));
114
117
  };
115
118
  renderValue(_nullishCoalesce(props.children, () => ( null)));
116
- _chunk6RCEIWZLcjs.registerErrorHandler.call(void 0, (err) => {
119
+ _chunkZR435MDCcjs.registerErrorHandler.call(void 0, (err) => {
117
120
  renderValue(toView(err));
118
121
  _optionalChain([props, 'access', _5 => _5.onError, 'optionalCall', _6 => _6(err)]);
119
122
  return true;
@@ -122,7 +125,7 @@ function ErrorBoundary(props) {
122
125
  const isGetter = typeof props.resetKeys === "function" && props.resetKeys.length === 0;
123
126
  const getter = isGetter ? props.resetKeys : void 0;
124
127
  let prev = isGetter ? getter() : props.resetKeys;
125
- _chunk6RCEIWZLcjs.createEffect.call(void 0, () => {
128
+ _chunkZR435MDCcjs.createEffect.call(void 0, () => {
126
129
  const next = getter ? getter() : props.resetKeys;
127
130
  if (prev !== next) {
128
131
  prev = next;
@@ -151,10 +154,11 @@ function createSuspenseToken() {
151
154
  }
152
155
  var isThenable = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
153
156
  function Suspense(props) {
154
- const pending = _chunk6RCEIWZLcjs.signal.call(void 0, 0);
157
+ const streamHooks = _chunkZR435MDCcjs.__fictGetSSRStreamHooks.call(void 0, );
158
+ const pending = _chunkZR435MDCcjs.signal.call(void 0, 0);
155
159
  let resolvedOnce = false;
156
160
  let epoch = 0;
157
- const hostRoot = _chunk6RCEIWZLcjs.getCurrentRoot.call(void 0, );
161
+ const hostRoot = _chunkZR435MDCcjs.getCurrentRoot.call(void 0, );
158
162
  const toFallback = (err) => typeof props.fallback === "function" ? props.fallback(err) : props.fallback;
159
163
  const renderView = (view) => {
160
164
  if (cleanup) {
@@ -162,57 +166,81 @@ function Suspense(props) {
162
166
  cleanup = void 0;
163
167
  }
164
168
  if (activeNodes.length) {
165
- _chunkWJHXPF7Mcjs.removeNodes.call(void 0, activeNodes);
169
+ _chunkZ6M3HKLGcjs.removeNodes.call(void 0, activeNodes);
166
170
  activeNodes = [];
167
171
  }
168
172
  if (view == null || view === false) {
169
173
  return;
170
174
  }
171
- const root = _chunk6RCEIWZLcjs.createRootContext.call(void 0, hostRoot);
172
- const prev = _chunk6RCEIWZLcjs.pushRoot.call(void 0, root);
175
+ const root = _chunkZR435MDCcjs.createRootContext.call(void 0, hostRoot);
176
+ const prev = _chunkZR435MDCcjs.pushRoot.call(void 0, root);
173
177
  let nodes = [];
178
+ let boundaryPushed = false;
174
179
  try {
175
- const output = _chunkWJHXPF7Mcjs.createElement.call(void 0, view);
176
- nodes = _chunkWJHXPF7Mcjs.toNodeArray.call(void 0, output);
180
+ if (streamBoundaryId) {
181
+ _chunkZR435MDCcjs.__fictPushSSRBoundary.call(void 0, streamBoundaryId);
182
+ boundaryPushed = true;
183
+ }
184
+ const output = _chunkZ6M3HKLGcjs.createElement.call(void 0, view);
185
+ nodes = _chunkZ6M3HKLGcjs.toNodeArray.call(void 0, output);
177
186
  const suspendedAttempt = root.suspended || nodes.length > 0 && nodes.every((node) => node instanceof Comment && node.data === "fict:suspend");
178
187
  if (suspendedAttempt) {
179
- _chunk6RCEIWZLcjs.popRoot.call(void 0, prev);
180
- _chunk6RCEIWZLcjs.destroyRoot.call(void 0, root);
188
+ _chunkZR435MDCcjs.popRoot.call(void 0, prev);
189
+ _chunkZR435MDCcjs.destroyRoot.call(void 0, root);
181
190
  return;
182
191
  }
183
- const parentNode = marker.parentNode;
192
+ const parentNode = endMarker.parentNode;
184
193
  if (parentNode) {
185
- _chunkWJHXPF7Mcjs.insertNodesBefore.call(void 0, parentNode, nodes, marker);
194
+ _chunkZ6M3HKLGcjs.insertNodesBefore.call(void 0, parentNode, nodes, endMarker);
186
195
  }
187
196
  } catch (err) {
188
- _chunk6RCEIWZLcjs.popRoot.call(void 0, prev);
189
- _chunk6RCEIWZLcjs.destroyRoot.call(void 0, root);
190
- if (!_chunk6RCEIWZLcjs.handleError.call(void 0, err, { source: "render" }, hostRoot)) {
197
+ _chunkZR435MDCcjs.popRoot.call(void 0, prev);
198
+ _chunkZR435MDCcjs.destroyRoot.call(void 0, root);
199
+ if (!_chunkZR435MDCcjs.handleError.call(void 0, err, { source: "render" }, hostRoot)) {
191
200
  throw err;
192
201
  }
193
202
  return;
203
+ } finally {
204
+ if (boundaryPushed) {
205
+ _chunkZR435MDCcjs.__fictPopSSRBoundary.call(void 0, _nullishCoalesce(streamBoundaryId, () => ( void 0)));
206
+ }
194
207
  }
195
- _chunk6RCEIWZLcjs.popRoot.call(void 0, prev);
196
- _chunk6RCEIWZLcjs.flushOnMount.call(void 0, root);
208
+ _chunkZR435MDCcjs.popRoot.call(void 0, prev);
209
+ _chunkZR435MDCcjs.flushOnMount.call(void 0, root);
197
210
  cleanup = () => {
198
- _chunk6RCEIWZLcjs.destroyRoot.call(void 0, root);
199
- _chunkWJHXPF7Mcjs.removeNodes.call(void 0, nodes);
211
+ _chunkZR435MDCcjs.destroyRoot.call(void 0, root);
212
+ _chunkZ6M3HKLGcjs.removeNodes.call(void 0, nodes);
200
213
  };
201
214
  activeNodes = nodes;
202
215
  };
203
216
  const fragment = document.createDocumentFragment();
204
- const marker = document.createComment("fict:suspense");
205
- fragment.appendChild(marker);
217
+ const startMarker = document.createComment("fict:suspense-start");
218
+ const endMarker = document.createComment("fict:suspense-end");
219
+ fragment.appendChild(startMarker);
220
+ fragment.appendChild(endMarker);
206
221
  let cleanup;
207
222
  let activeNodes = [];
223
+ let streamBoundaryId = null;
224
+ let streamPending = false;
225
+ if (_optionalChain([streamHooks, 'optionalAccess', _7 => _7.registerBoundary])) {
226
+ streamBoundaryId = _nullishCoalesce(streamHooks.registerBoundary(startMarker, endMarker), () => ( null));
227
+ if (streamBoundaryId) {
228
+ startMarker.data = `fict:suspense-start:${streamBoundaryId}`;
229
+ endMarker.data = `fict:suspense-end:${streamBoundaryId}`;
230
+ }
231
+ }
208
232
  const onResolveMaybe = () => {
209
233
  if (!resolvedOnce) {
210
234
  resolvedOnce = true;
211
- _optionalChain([props, 'access', _7 => _7.onResolve, 'optionalCall', _8 => _8()]);
235
+ _optionalChain([props, 'access', _8 => _8.onResolve, 'optionalCall', _9 => _9()]);
212
236
  }
213
237
  };
214
- _chunk6RCEIWZLcjs.registerSuspenseHandler.call(void 0, (token) => {
238
+ _chunkZR435MDCcjs.registerSuspenseHandler.call(void 0, (token) => {
215
239
  const tokenEpoch = epoch;
240
+ if (!streamPending && streamBoundaryId && _optionalChain([streamHooks, 'optionalAccess', _10 => _10.boundaryPending])) {
241
+ streamPending = true;
242
+ streamHooks.boundaryPending(streamBoundaryId);
243
+ }
216
244
  pending(pending() + 1);
217
245
  renderView(toFallback());
218
246
  const thenable = token.then ? token : isThenable(token) ? token : null;
@@ -226,6 +254,10 @@ function Suspense(props) {
226
254
  pending(newPending);
227
255
  if (newPending === 0) {
228
256
  renderView(_nullishCoalesce(props.children, () => ( null)));
257
+ if (streamPending && streamBoundaryId && _optionalChain([streamHooks, 'optionalAccess', _11 => _11.boundaryResolved])) {
258
+ streamPending = false;
259
+ streamHooks.boundaryResolved(streamBoundaryId);
260
+ }
229
261
  onResolveMaybe();
230
262
  }
231
263
  },
@@ -235,9 +267,23 @@ function Suspense(props) {
235
267
  }
236
268
  const newPending = Math.max(0, pending() - 1);
237
269
  pending(newPending);
238
- _optionalChain([props, 'access', _9 => _9.onReject, 'optionalCall', _10 => _10(err)]);
239
- if (!_chunk6RCEIWZLcjs.handleError.call(void 0, err, { source: "render" }, hostRoot)) {
240
- throw err;
270
+ let rejectionError = err;
271
+ try {
272
+ _optionalChain([props, 'access', _12 => _12.onReject, 'optionalCall', _13 => _13(err)]);
273
+ } catch (callbackError) {
274
+ rejectionError = callbackError;
275
+ }
276
+ const handled = _chunkZR435MDCcjs.handleError.call(void 0, rejectionError, { source: "render" }, hostRoot);
277
+ if (!handled) {
278
+ if (_optionalChain([streamHooks, 'optionalAccess', _14 => _14.onError])) {
279
+ streamHooks.onError(rejectionError, _nullishCoalesce(streamBoundaryId, () => ( void 0)));
280
+ return;
281
+ }
282
+ throw rejectionError;
283
+ }
284
+ if (newPending === 0 && streamPending && streamBoundaryId && _optionalChain([streamHooks, 'optionalAccess', _15 => _15.boundaryResolved])) {
285
+ streamPending = false;
286
+ streamHooks.boundaryResolved(streamBoundaryId);
241
287
  }
242
288
  }
243
289
  );
@@ -250,13 +296,17 @@ function Suspense(props) {
250
296
  const isGetter = typeof props.resetKeys === "function" && props.resetKeys.length === 0;
251
297
  const getter = isGetter ? props.resetKeys : void 0;
252
298
  let prev = isGetter ? getter() : props.resetKeys;
253
- _chunk6RCEIWZLcjs.createEffect.call(void 0, () => {
299
+ _chunkZR435MDCcjs.createEffect.call(void 0, () => {
254
300
  const next = getter ? getter() : props.resetKeys;
255
301
  if (prev !== next) {
256
302
  prev = next;
257
303
  epoch++;
258
304
  pending(0);
259
305
  renderView(_nullishCoalesce(props.children, () => ( null)));
306
+ if (streamPending && streamBoundaryId && _optionalChain([streamHooks, 'optionalAccess', _16 => _16.boundaryResolved])) {
307
+ streamPending = false;
308
+ streamHooks.boundaryResolved(streamBoundaryId);
309
+ }
260
310
  }
261
311
  });
262
312
  }
@@ -288,5 +338,5 @@ function Suspense(props) {
288
338
 
289
339
 
290
340
 
291
- exports.ErrorBoundary = ErrorBoundary; exports.Fragment = _chunkWJHXPF7Mcjs.Fragment; exports.Suspense = Suspense; exports.batch = _chunkWJHXPF7Mcjs.batch; exports.createContext = _chunkLFMXNQZCcjs.createContext; exports.createEffect = _chunk6RCEIWZLcjs.createEffect; exports.createElement = _chunkWJHXPF7Mcjs.createElement; exports.createMemo = _chunk6RCEIWZLcjs.createMemo; exports.createPortal = _chunkWJHXPF7Mcjs.createPortal; exports.createRef = createRef; exports.createRoot = _chunk6RCEIWZLcjs.createRoot; exports.createSuspenseToken = createSuspenseToken; exports.hasContext = _chunkLFMXNQZCcjs.hasContext; exports.keyed = _chunkWJHXPF7Mcjs.keyed; exports.mergeProps = _chunkWJHXPF7Mcjs.mergeProps; exports.onCleanup = _chunk6RCEIWZLcjs.onCleanup; exports.onDestroy = _chunk6RCEIWZLcjs.onDestroy; exports.onMount = _chunk6RCEIWZLcjs.onMount; exports.prop = _chunkWJHXPF7Mcjs.prop; exports.render = _chunkWJHXPF7Mcjs.render; exports.startTransition = _chunkWJHXPF7Mcjs.startTransition; exports.untrack = _chunkWJHXPF7Mcjs.untrack; exports.useContext = _chunkLFMXNQZCcjs.useContext; exports.useDeferredValue = _chunkWJHXPF7Mcjs.useDeferredValue; exports.useTransition = _chunkWJHXPF7Mcjs.useTransition;
341
+ exports.ErrorBoundary = ErrorBoundary; exports.Fragment = _chunkZ6M3HKLGcjs.Fragment; exports.Suspense = Suspense; exports.batch = _chunkZ6M3HKLGcjs.batch; exports.createContext = _chunkKNGHYGK4cjs.createContext; exports.createEffect = _chunkZR435MDCcjs.createEffect; exports.createElement = _chunkZ6M3HKLGcjs.createElement; exports.createMemo = _chunkZR435MDCcjs.createMemo; exports.createPortal = _chunkZ6M3HKLGcjs.createPortal; exports.createRef = createRef; exports.createRoot = _chunkZR435MDCcjs.createRoot; exports.createSuspenseToken = createSuspenseToken; exports.hasContext = _chunkKNGHYGK4cjs.hasContext; exports.keyed = _chunkZ6M3HKLGcjs.keyed; exports.mergeProps = _chunkZ6M3HKLGcjs.mergeProps; exports.onCleanup = _chunkZR435MDCcjs.onCleanup; exports.onDestroy = _chunkZR435MDCcjs.onDestroy; exports.onMount = _chunkZR435MDCcjs.onMount; exports.prop = _chunkZ6M3HKLGcjs.prop; exports.render = _chunkZ6M3HKLGcjs.render; exports.startTransition = _chunkZ6M3HKLGcjs.startTransition; exports.untrack = _chunkZ6M3HKLGcjs.untrack; exports.useContext = _chunkKNGHYGK4cjs.useContext; exports.useDeferredValue = _chunkZ6M3HKLGcjs.useDeferredValue; exports.useTransition = _chunkZ6M3HKLGcjs.useTransition;
292
342
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/fict/fict/packages/runtime/dist/index.cjs","../src/ref.ts","../src/error-boundary.ts","../src/suspense.ts"],"names":[],"mappings":"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","file":"/home/runner/work/fict/fict/packages/runtime/dist/index.cjs","sourcesContent":[null,"import type { RefObject } from './types'\n\n/**\n * Create a ref object for DOM element references.\n *\n * @returns A ref object with a `current` property initialized to `null`\n *\n * @example\n * ```tsx\n * import { createRef } from 'fict'\n *\n * function Component() {\n * const inputRef = createRef<HTMLInputElement>()\n *\n * $effect(() => {\n * inputRef.current?.focus()\n * })\n *\n * return <input ref={inputRef} />\n * }\n * ```\n */\nexport function createRef<T extends Element = HTMLElement>(): RefObject<T> {\n return { current: null }\n}\n","import { createElement } from './dom'\nimport { createEffect } from './effect'\nimport {\n createRootContext,\n destroyRoot,\n flushOnMount,\n getCurrentRoot,\n pushRoot,\n popRoot,\n registerErrorHandler,\n} from './lifecycle'\nimport { insertNodesBefore, removeNodes, toNodeArray } from './node-ops'\nimport type { BaseProps, FictNode } from './types'\n\ninterface ErrorBoundaryProps extends BaseProps {\n fallback: FictNode | ((err: unknown, reset?: () => void) => FictNode)\n onError?: (err: unknown) => void\n resetKeys?: unknown | (() => unknown)\n}\n\nexport function ErrorBoundary(props: ErrorBoundaryProps): FictNode {\n const fragment = document.createDocumentFragment()\n const marker = document.createComment('fict:error-boundary')\n fragment.appendChild(marker)\n\n const hostRoot = getCurrentRoot()\n\n let cleanup: (() => void) | undefined\n let activeNodes: Node[] = []\n let renderingFallback = false\n\n let reset = () => {}\n const toView = (err: unknown | null): FictNode | null => {\n if (err != null) {\n return typeof props.fallback === 'function'\n ? (props.fallback as (e: unknown, reset?: () => void) => FictNode)(err, reset)\n : props.fallback\n }\n return props.children ?? null\n }\n\n const renderValue = (value: FictNode | null) => {\n if (cleanup) {\n cleanup()\n cleanup = undefined\n }\n if (activeNodes.length) {\n removeNodes(activeNodes)\n activeNodes = []\n }\n\n if (value == null || value === false) {\n return\n }\n\n const root = createRootContext(hostRoot)\n const prev = pushRoot(root)\n let nodes: Node[] = []\n try {\n const output = createElement(value)\n nodes = toNodeArray(output)\n const parentNode = marker.parentNode as (ParentNode & Node) | null\n if (parentNode) {\n insertNodesBefore(parentNode, nodes, marker)\n }\n } catch (err) {\n popRoot(prev)\n destroyRoot(root)\n // Fall back immediately on render errors, avoid infinite recursion\n if (renderingFallback) {\n throw err\n }\n // nested errors. If fallback rendering also throws, we should NOT reset\n // the flag until we're sure no more recursion is happening.\n renderingFallback = true\n try {\n renderValue(toView(err))\n // Only reset if successful - if renderValue threw, we want to keep\n // renderingFallback = true to prevent infinite recursion\n renderingFallback = false\n props.onError?.(err)\n } catch (fallbackErr) {\n // Fallback rendering failed - keep renderingFallback = true\n // to prevent further attempts, then rethrow\n // If fallback fails, report both errors\n props.onError?.(err)\n throw fallbackErr\n }\n return\n }\n popRoot(prev)\n flushOnMount(root)\n\n cleanup = () => {\n destroyRoot(root)\n removeNodes(nodes)\n }\n activeNodes = nodes\n }\n\n reset = () => {\n renderingFallback = false\n renderValue(toView(null))\n }\n\n renderValue(props.children ?? null)\n\n registerErrorHandler(err => {\n renderValue(toView(err))\n props.onError?.(err)\n return true\n })\n\n if (props.resetKeys !== undefined) {\n const isGetter =\n typeof props.resetKeys === 'function' && (props.resetKeys as () => unknown).length === 0\n const getter = isGetter ? (props.resetKeys as () => unknown) : undefined\n let prev = isGetter ? getter!() : props.resetKeys\n createEffect(() => {\n const next = getter ? getter() : props.resetKeys\n if (prev !== next) {\n prev = next\n renderValue(toView(null))\n }\n })\n }\n\n return fragment\n}\n","import { createElement } from './dom'\nimport { createEffect } from './effect'\nimport {\n createRootContext,\n destroyRoot,\n flushOnMount,\n getCurrentRoot,\n handleError,\n pushRoot,\n popRoot,\n registerSuspenseHandler,\n} from './lifecycle'\nimport { insertNodesBefore, removeNodes, toNodeArray } from './node-ops'\nimport { createSignal } from './signal'\nimport type { BaseProps, FictNode, SuspenseToken } from './types'\n\nexport interface SuspenseProps extends BaseProps {\n fallback: FictNode | ((err?: unknown) => FictNode)\n onResolve?: () => void\n onReject?: (err: unknown) => void\n resetKeys?: unknown | (() => unknown)\n}\n\nexport interface SuspenseHandle {\n token: SuspenseToken\n resolve: () => void\n reject: (err: unknown) => void\n}\n\nexport function createSuspenseToken(): SuspenseHandle {\n let resolve!: () => void\n let reject!: (err: unknown) => void\n const promise = new Promise<void>((res, rej) => {\n resolve = res\n reject = rej\n })\n return {\n token: {\n then: promise.then.bind(promise),\n },\n resolve,\n reject,\n }\n}\n\nconst isThenable = (value: unknown): value is PromiseLike<unknown> =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as PromiseLike<unknown>).then === 'function'\n\nexport function Suspense(props: SuspenseProps): FictNode {\n const pending = createSignal(0)\n let resolvedOnce = false\n let epoch = 0\n const hostRoot = getCurrentRoot()\n\n const toFallback = (err?: unknown) =>\n typeof props.fallback === 'function'\n ? (props.fallback as (e?: unknown) => FictNode)(err)\n : props.fallback\n\n const renderView = (view: FictNode | null) => {\n if (cleanup) {\n cleanup()\n cleanup = undefined\n }\n if (activeNodes.length) {\n removeNodes(activeNodes)\n activeNodes = []\n }\n\n if (view == null || view === false) {\n return\n }\n\n const root = createRootContext(hostRoot)\n const prev = pushRoot(root)\n let nodes: Node[] = []\n try {\n const output = createElement(view)\n nodes = toNodeArray(output)\n // Suspended view: child threw a suspense token and was handled upstream.\n // Avoid replacing existing fallback content; tear down this attempt.\n const suspendedAttempt =\n root.suspended ||\n (nodes.length > 0 &&\n nodes.every(node => node instanceof Comment && (node as Comment).data === 'fict:suspend'))\n if (suspendedAttempt) {\n popRoot(prev)\n destroyRoot(root)\n return\n }\n const parentNode = marker.parentNode as (ParentNode & Node) | null\n if (parentNode) {\n insertNodesBefore(parentNode, nodes, marker)\n }\n } catch (err) {\n popRoot(prev)\n destroyRoot(root)\n if (!handleError(err, { source: 'render' }, hostRoot)) {\n throw err\n }\n return\n }\n popRoot(prev)\n flushOnMount(root)\n\n cleanup = () => {\n destroyRoot(root)\n removeNodes(nodes)\n }\n activeNodes = nodes\n }\n\n const fragment = document.createDocumentFragment()\n const marker = document.createComment('fict:suspense')\n fragment.appendChild(marker)\n let cleanup: (() => void) | undefined\n let activeNodes: Node[] = []\n\n const onResolveMaybe = () => {\n if (!resolvedOnce) {\n resolvedOnce = true\n props.onResolve?.()\n }\n }\n\n registerSuspenseHandler(token => {\n const tokenEpoch = epoch\n pending(pending() + 1)\n // Directly render fallback instead of using switchView to avoid\n // triggering the effect which would cause duplicate renders\n renderView(toFallback())\n\n const thenable = (token as SuspenseToken).then\n ? (token as SuspenseToken)\n : isThenable(token)\n ? token\n : null\n\n if (thenable) {\n thenable.then(\n () => {\n // This prevents stale token resolutions from affecting state after\n // a reset. The order is important: check epoch first, then update state.\n if (epoch !== tokenEpoch) {\n // Token is stale (from before a reset), ignore it completely\n return\n }\n // Use Math.max as a defensive measure - pending should never go below 0,\n // but this protects against edge cases where a token might resolve twice\n // or after the component has been reset.\n const newPending = Math.max(0, pending() - 1)\n pending(newPending)\n if (newPending === 0) {\n // Directly render children instead of using switchView\n renderView(props.children ?? null)\n onResolveMaybe()\n }\n },\n err => {\n // Same epoch check - ignore stale tokens\n if (epoch !== tokenEpoch) {\n return\n }\n const newPending = Math.max(0, pending() - 1)\n pending(newPending)\n props.onReject?.(err)\n if (!handleError(err, { source: 'render' }, hostRoot)) {\n throw err\n }\n },\n )\n return true\n }\n\n return false\n })\n\n // Initial render - render children directly\n // Note: This will be called synchronously during component creation.\n // If children suspend, the handler above will be called and switch to fallback.\n renderView(props.children ?? null)\n\n if (props.resetKeys !== undefined) {\n const isGetter =\n typeof props.resetKeys === 'function' && (props.resetKeys as () => unknown).length === 0\n const getter = isGetter ? (props.resetKeys as () => unknown) : undefined\n let prev = isGetter ? getter!() : props.resetKeys\n createEffect(() => {\n const next = getter ? getter() : props.resetKeys\n if (prev !== next) {\n prev = next\n epoch++\n pending(0)\n // Directly render children instead of using switchView\n renderView(props.children ?? null)\n }\n })\n }\n\n return fragment\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/fict/fict/packages/runtime/dist/index.cjs","../src/ref.ts","../src/error-boundary.ts","../src/suspense.ts"],"names":[],"mappings":"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","file":"/home/runner/work/fict/fict/packages/runtime/dist/index.cjs","sourcesContent":[null,"import type { RefObject } from './types'\n\n/**\n * Create a ref object for DOM element references.\n *\n * @returns A ref object with a `current` property initialized to `null`\n *\n * @example\n * ```tsx\n * import { createRef } from 'fict'\n *\n * function Component() {\n * const inputRef = createRef<HTMLInputElement>()\n *\n * $effect(() => {\n * inputRef.current?.focus()\n * })\n *\n * return <input ref={inputRef} />\n * }\n * ```\n */\nexport function createRef<T extends Element = HTMLElement>(): RefObject<T> {\n return { current: null }\n}\n","import { createElement } from './dom'\nimport { createEffect } from './effect'\nimport {\n createRootContext,\n destroyRoot,\n flushOnMount,\n getCurrentRoot,\n pushRoot,\n popRoot,\n registerErrorHandler,\n} from './lifecycle'\nimport { insertNodesBefore, removeNodes, toNodeArray } from './node-ops'\nimport type { BaseProps, FictNode } from './types'\n\ninterface ErrorBoundaryProps extends BaseProps {\n fallback: FictNode | ((err: unknown, reset?: () => void) => FictNode)\n onError?: (err: unknown) => void\n resetKeys?: unknown | (() => unknown)\n}\n\nexport function ErrorBoundary(props: ErrorBoundaryProps): FictNode {\n const fragment = document.createDocumentFragment()\n const marker = document.createComment('fict:error-boundary')\n fragment.appendChild(marker)\n\n const hostRoot = getCurrentRoot()\n\n let cleanup: (() => void) | undefined\n let activeNodes: Node[] = []\n let renderingFallback = false\n\n let reset = () => {}\n const toView = (err: unknown | null): FictNode | null => {\n if (err != null) {\n return typeof props.fallback === 'function'\n ? (props.fallback as (e: unknown, reset?: () => void) => FictNode)(err, reset)\n : props.fallback\n }\n return props.children ?? null\n }\n\n const renderValue = (value: FictNode | null) => {\n if (cleanup) {\n cleanup()\n cleanup = undefined\n }\n if (activeNodes.length) {\n removeNodes(activeNodes)\n activeNodes = []\n }\n\n if (value == null || value === false) {\n return\n }\n\n const root = createRootContext(hostRoot)\n const prev = pushRoot(root)\n let nodes: Node[] = []\n try {\n const output = createElement(value)\n nodes = toNodeArray(output)\n const parentNode = marker.parentNode as (ParentNode & Node) | null\n if (parentNode) {\n insertNodesBefore(parentNode, nodes, marker)\n }\n } catch (err) {\n popRoot(prev)\n destroyRoot(root)\n // Fall back immediately on render errors, avoid infinite recursion\n if (renderingFallback) {\n throw err\n }\n // nested errors. If fallback rendering also throws, we should NOT reset\n // the flag until we're sure no more recursion is happening.\n renderingFallback = true\n try {\n renderValue(toView(err))\n // Only reset if successful - if renderValue threw, we want to keep\n // renderingFallback = true to prevent infinite recursion\n renderingFallback = false\n props.onError?.(err)\n } catch (fallbackErr) {\n // Fallback rendering failed - keep renderingFallback = true\n // to prevent further attempts, then rethrow\n // If fallback fails, report both errors\n props.onError?.(err)\n throw fallbackErr\n }\n return\n }\n popRoot(prev)\n flushOnMount(root)\n\n cleanup = () => {\n destroyRoot(root)\n removeNodes(nodes)\n }\n activeNodes = nodes\n }\n\n reset = () => {\n renderingFallback = false\n renderValue(toView(null))\n }\n\n renderValue(props.children ?? null)\n\n registerErrorHandler(err => {\n renderValue(toView(err))\n props.onError?.(err)\n return true\n })\n\n if (props.resetKeys !== undefined) {\n const isGetter =\n typeof props.resetKeys === 'function' && (props.resetKeys as () => unknown).length === 0\n const getter = isGetter ? (props.resetKeys as () => unknown) : undefined\n let prev = isGetter ? getter!() : props.resetKeys\n createEffect(() => {\n const next = getter ? getter() : props.resetKeys\n if (prev !== next) {\n prev = next\n renderValue(toView(null))\n }\n })\n }\n\n return fragment\n}\n","import { createElement } from './dom'\nimport { createEffect } from './effect'\nimport {\n createRootContext,\n destroyRoot,\n flushOnMount,\n getCurrentRoot,\n handleError,\n pushRoot,\n popRoot,\n registerSuspenseHandler,\n} from './lifecycle'\nimport { insertNodesBefore, removeNodes, toNodeArray } from './node-ops'\nimport { createSignal } from './signal'\nimport { __fictGetSSRStreamHooks, __fictPopSSRBoundary, __fictPushSSRBoundary } from './ssr-stream'\nimport type { BaseProps, FictNode, SuspenseToken } from './types'\n\nexport interface SuspenseProps extends BaseProps {\n fallback: FictNode | ((err?: unknown) => FictNode)\n onResolve?: () => void\n onReject?: (err: unknown) => void\n resetKeys?: unknown | (() => unknown)\n}\n\nexport interface SuspenseHandle {\n token: SuspenseToken\n resolve: () => void\n reject: (err: unknown) => void\n}\n\nexport function createSuspenseToken(): SuspenseHandle {\n let resolve!: () => void\n let reject!: (err: unknown) => void\n const promise = new Promise<void>((res, rej) => {\n resolve = res\n reject = rej\n })\n return {\n token: {\n then: promise.then.bind(promise),\n },\n resolve,\n reject,\n }\n}\n\nconst isThenable = (value: unknown): value is PromiseLike<unknown> =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as PromiseLike<unknown>).then === 'function'\n\nexport function Suspense(props: SuspenseProps): FictNode {\n const streamHooks = __fictGetSSRStreamHooks()\n const pending = createSignal(0)\n let resolvedOnce = false\n let epoch = 0\n const hostRoot = getCurrentRoot()\n\n const toFallback = (err?: unknown) =>\n typeof props.fallback === 'function'\n ? (props.fallback as (e?: unknown) => FictNode)(err)\n : props.fallback\n\n const renderView = (view: FictNode | null) => {\n if (cleanup) {\n cleanup()\n cleanup = undefined\n }\n if (activeNodes.length) {\n removeNodes(activeNodes)\n activeNodes = []\n }\n\n if (view == null || view === false) {\n return\n }\n\n const root = createRootContext(hostRoot)\n const prev = pushRoot(root)\n let nodes: Node[] = []\n let boundaryPushed = false\n try {\n if (streamBoundaryId) {\n __fictPushSSRBoundary(streamBoundaryId)\n boundaryPushed = true\n }\n const output = createElement(view)\n nodes = toNodeArray(output)\n // Suspended view: child threw a suspense token and was handled upstream.\n // Avoid replacing existing fallback content; tear down this attempt.\n const suspendedAttempt =\n root.suspended ||\n (nodes.length > 0 &&\n nodes.every(node => node instanceof Comment && (node as Comment).data === 'fict:suspend'))\n if (suspendedAttempt) {\n popRoot(prev)\n destroyRoot(root)\n return\n }\n const parentNode = endMarker.parentNode as (ParentNode & Node) | null\n if (parentNode) {\n insertNodesBefore(parentNode, nodes, endMarker)\n }\n } catch (err) {\n popRoot(prev)\n destroyRoot(root)\n if (!handleError(err, { source: 'render' }, hostRoot)) {\n throw err\n }\n return\n } finally {\n if (boundaryPushed) {\n __fictPopSSRBoundary(streamBoundaryId ?? undefined)\n }\n }\n popRoot(prev)\n flushOnMount(root)\n\n cleanup = () => {\n destroyRoot(root)\n removeNodes(nodes)\n }\n activeNodes = nodes\n }\n\n const fragment = document.createDocumentFragment()\n const startMarker = document.createComment('fict:suspense-start')\n const endMarker = document.createComment('fict:suspense-end')\n fragment.appendChild(startMarker)\n fragment.appendChild(endMarker)\n let cleanup: (() => void) | undefined\n let activeNodes: Node[] = []\n let streamBoundaryId: string | null = null\n let streamPending = false\n\n if (streamHooks?.registerBoundary) {\n streamBoundaryId = streamHooks.registerBoundary(startMarker, endMarker) ?? null\n if (streamBoundaryId) {\n startMarker.data = `fict:suspense-start:${streamBoundaryId}`\n endMarker.data = `fict:suspense-end:${streamBoundaryId}`\n }\n }\n\n const onResolveMaybe = () => {\n if (!resolvedOnce) {\n resolvedOnce = true\n props.onResolve?.()\n }\n }\n\n registerSuspenseHandler(token => {\n const tokenEpoch = epoch\n if (!streamPending && streamBoundaryId && streamHooks?.boundaryPending) {\n streamPending = true\n streamHooks.boundaryPending(streamBoundaryId)\n }\n pending(pending() + 1)\n // Directly render fallback instead of using switchView to avoid\n // triggering the effect which would cause duplicate renders\n renderView(toFallback())\n\n const thenable = (token as SuspenseToken).then\n ? (token as SuspenseToken)\n : isThenable(token)\n ? token\n : null\n\n if (thenable) {\n thenable.then(\n () => {\n // This prevents stale token resolutions from affecting state after\n // a reset. The order is important: check epoch first, then update state.\n if (epoch !== tokenEpoch) {\n // Token is stale (from before a reset), ignore it completely\n return\n }\n // Use Math.max as a defensive measure - pending should never go below 0,\n // but this protects against edge cases where a token might resolve twice\n // or after the component has been reset.\n const newPending = Math.max(0, pending() - 1)\n pending(newPending)\n if (newPending === 0) {\n // Directly render children instead of using switchView\n renderView(props.children ?? null)\n if (streamPending && streamBoundaryId && streamHooks?.boundaryResolved) {\n streamPending = false\n streamHooks.boundaryResolved(streamBoundaryId)\n }\n onResolveMaybe()\n }\n },\n err => {\n // Same epoch check - ignore stale tokens\n if (epoch !== tokenEpoch) {\n return\n }\n const newPending = Math.max(0, pending() - 1)\n pending(newPending)\n let rejectionError = err\n try {\n props.onReject?.(err)\n } catch (callbackError) {\n rejectionError = callbackError\n }\n\n const handled = handleError(rejectionError, { source: 'render' }, hostRoot)\n if (!handled) {\n if (streamHooks?.onError) {\n streamHooks.onError(rejectionError, streamBoundaryId ?? undefined)\n return\n }\n throw rejectionError\n }\n if (\n newPending === 0 &&\n streamPending &&\n streamBoundaryId &&\n streamHooks?.boundaryResolved\n ) {\n streamPending = false\n streamHooks.boundaryResolved(streamBoundaryId)\n }\n },\n )\n return true\n }\n\n return false\n })\n\n // Initial render - render children directly\n // Note: This will be called synchronously during component creation.\n // If children suspend, the handler above will be called and switch to fallback.\n renderView(props.children ?? null)\n\n if (props.resetKeys !== undefined) {\n const isGetter =\n typeof props.resetKeys === 'function' && (props.resetKeys as () => unknown).length === 0\n const getter = isGetter ? (props.resetKeys as () => unknown) : undefined\n let prev = isGetter ? getter!() : props.resetKeys\n createEffect(() => {\n const next = getter ? getter() : props.resetKeys\n if (prev !== next) {\n prev = next\n epoch++\n pending(0)\n // Directly render children instead of using switchView\n renderView(props.children ?? null)\n if (streamPending && streamBoundaryId && streamHooks?.boundaryResolved) {\n streamPending = false\n streamHooks.boundaryResolved(streamBoundaryId)\n }\n }\n })\n }\n\n return fragment\n}\n"]}
package/dist/index.dev.js CHANGED
@@ -1849,12 +1849,35 @@ function removeNodes(nodes) {
1849
1849
  }
1850
1850
  }
1851
1851
 
1852
+ // src/ssr-stream.ts
1853
+ var ssrStreamHooks = null;
1854
+ var boundaryStack = [];
1855
+ function __fictGetSSRStreamHooks() {
1856
+ return ssrStreamHooks;
1857
+ }
1858
+ function __fictPushSSRBoundary(id) {
1859
+ boundaryStack.push(id);
1860
+ }
1861
+ function __fictPopSSRBoundary(expected) {
1862
+ if (boundaryStack.length === 0) return;
1863
+ const top = boundaryStack[boundaryStack.length - 1];
1864
+ if (expected && top !== expected) {
1865
+ boundaryStack.pop();
1866
+ return;
1867
+ }
1868
+ boundaryStack.pop();
1869
+ }
1870
+ function __fictGetCurrentSSRBoundary() {
1871
+ return boundaryStack.length > 0 ? boundaryStack[boundaryStack.length - 1] : null;
1872
+ }
1873
+
1852
1874
  // src/resume.ts
1853
1875
  var ssrEnabled = false;
1854
1876
  var resumableEnabled = false;
1855
1877
  var hydrating = false;
1856
1878
  var scopeCounter = 0;
1857
1879
  var scopeRegistry = /* @__PURE__ */ new Map();
1880
+ var boundaryScopes = /* @__PURE__ */ new Map();
1858
1881
  function __fictIsResumable() {
1859
1882
  return ssrEnabled || resumableEnabled;
1860
1883
  }
@@ -1879,6 +1902,16 @@ function __fictRegisterScope(ctx, host, type, props) {
1879
1902
  if (props !== void 0) {
1880
1903
  record.props = props;
1881
1904
  }
1905
+ const boundaryId = __fictGetCurrentSSRBoundary();
1906
+ if (boundaryId) {
1907
+ record.boundaryId = boundaryId;
1908
+ let scopes = boundaryScopes.get(boundaryId);
1909
+ if (!scopes) {
1910
+ scopes = /* @__PURE__ */ new Set();
1911
+ boundaryScopes.set(boundaryId, scopes);
1912
+ }
1913
+ scopes.add(id);
1914
+ }
1882
1915
  scopeRegistry.set(id, record);
1883
1916
  return id;
1884
1917
  }
@@ -3020,6 +3053,7 @@ function createSuspenseToken() {
3020
3053
  }
3021
3054
  var isThenable = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
3022
3055
  function Suspense(props) {
3056
+ const streamHooks = __fictGetSSRStreamHooks();
3023
3057
  const pending = signal(0);
3024
3058
  let resolvedOnce = false;
3025
3059
  let epoch = 0;
@@ -3040,7 +3074,12 @@ function Suspense(props) {
3040
3074
  const root = createRootContext(hostRoot);
3041
3075
  const prev = pushRoot(root);
3042
3076
  let nodes = [];
3077
+ let boundaryPushed = false;
3043
3078
  try {
3079
+ if (streamBoundaryId) {
3080
+ __fictPushSSRBoundary(streamBoundaryId);
3081
+ boundaryPushed = true;
3082
+ }
3044
3083
  const output = createElement(view);
3045
3084
  nodes = toNodeArray(output);
3046
3085
  const suspendedAttempt = root.suspended || nodes.length > 0 && nodes.every((node) => node instanceof Comment && node.data === "fict:suspend");
@@ -3049,9 +3088,9 @@ function Suspense(props) {
3049
3088
  destroyRoot(root);
3050
3089
  return;
3051
3090
  }
3052
- const parentNode = marker.parentNode;
3091
+ const parentNode = endMarker.parentNode;
3053
3092
  if (parentNode) {
3054
- insertNodesBefore(parentNode, nodes, marker);
3093
+ insertNodesBefore(parentNode, nodes, endMarker);
3055
3094
  }
3056
3095
  } catch (err) {
3057
3096
  popRoot(prev);
@@ -3060,6 +3099,10 @@ function Suspense(props) {
3060
3099
  throw err;
3061
3100
  }
3062
3101
  return;
3102
+ } finally {
3103
+ if (boundaryPushed) {
3104
+ __fictPopSSRBoundary(streamBoundaryId ?? void 0);
3105
+ }
3063
3106
  }
3064
3107
  popRoot(prev);
3065
3108
  flushOnMount(root);
@@ -3070,10 +3113,21 @@ function Suspense(props) {
3070
3113
  activeNodes = nodes;
3071
3114
  };
3072
3115
  const fragment = document.createDocumentFragment();
3073
- const marker = document.createComment("fict:suspense");
3074
- fragment.appendChild(marker);
3116
+ const startMarker = document.createComment("fict:suspense-start");
3117
+ const endMarker = document.createComment("fict:suspense-end");
3118
+ fragment.appendChild(startMarker);
3119
+ fragment.appendChild(endMarker);
3075
3120
  let cleanup;
3076
3121
  let activeNodes = [];
3122
+ let streamBoundaryId = null;
3123
+ let streamPending = false;
3124
+ if (streamHooks?.registerBoundary) {
3125
+ streamBoundaryId = streamHooks.registerBoundary(startMarker, endMarker) ?? null;
3126
+ if (streamBoundaryId) {
3127
+ startMarker.data = `fict:suspense-start:${streamBoundaryId}`;
3128
+ endMarker.data = `fict:suspense-end:${streamBoundaryId}`;
3129
+ }
3130
+ }
3077
3131
  const onResolveMaybe = () => {
3078
3132
  if (!resolvedOnce) {
3079
3133
  resolvedOnce = true;
@@ -3082,6 +3136,10 @@ function Suspense(props) {
3082
3136
  };
3083
3137
  registerSuspenseHandler((token) => {
3084
3138
  const tokenEpoch = epoch;
3139
+ if (!streamPending && streamBoundaryId && streamHooks?.boundaryPending) {
3140
+ streamPending = true;
3141
+ streamHooks.boundaryPending(streamBoundaryId);
3142
+ }
3085
3143
  pending(pending() + 1);
3086
3144
  renderView(toFallback());
3087
3145
  const thenable = token.then ? token : isThenable(token) ? token : null;
@@ -3095,6 +3153,10 @@ function Suspense(props) {
3095
3153
  pending(newPending);
3096
3154
  if (newPending === 0) {
3097
3155
  renderView(props.children ?? null);
3156
+ if (streamPending && streamBoundaryId && streamHooks?.boundaryResolved) {
3157
+ streamPending = false;
3158
+ streamHooks.boundaryResolved(streamBoundaryId);
3159
+ }
3098
3160
  onResolveMaybe();
3099
3161
  }
3100
3162
  },
@@ -3104,9 +3166,23 @@ function Suspense(props) {
3104
3166
  }
3105
3167
  const newPending = Math.max(0, pending() - 1);
3106
3168
  pending(newPending);
3107
- props.onReject?.(err);
3108
- if (!handleError(err, { source: "render" }, hostRoot)) {
3109
- throw err;
3169
+ let rejectionError = err;
3170
+ try {
3171
+ props.onReject?.(err);
3172
+ } catch (callbackError) {
3173
+ rejectionError = callbackError;
3174
+ }
3175
+ const handled = handleError(rejectionError, { source: "render" }, hostRoot);
3176
+ if (!handled) {
3177
+ if (streamHooks?.onError) {
3178
+ streamHooks.onError(rejectionError, streamBoundaryId ?? void 0);
3179
+ return;
3180
+ }
3181
+ throw rejectionError;
3182
+ }
3183
+ if (newPending === 0 && streamPending && streamBoundaryId && streamHooks?.boundaryResolved) {
3184
+ streamPending = false;
3185
+ streamHooks.boundaryResolved(streamBoundaryId);
3110
3186
  }
3111
3187
  }
3112
3188
  );
@@ -3126,6 +3202,10 @@ function Suspense(props) {
3126
3202
  epoch++;
3127
3203
  pending(0);
3128
3204
  renderView(props.children ?? null);
3205
+ if (streamPending && streamBoundaryId && streamHooks?.boundaryResolved) {
3206
+ streamPending = false;
3207
+ streamHooks.boundaryResolved(streamBoundaryId);
3208
+ }
3129
3209
  }
3130
3210
  });
3131
3211
  }