@fictjs/runtime 0.5.0 → 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 (51) hide show
  1. package/dist/advanced.cjs +9 -9
  2. package/dist/advanced.js +4 -4
  3. package/dist/{chunk-5AA7HP4S.js → chunk-4NUHM77Z.js} +3 -3
  4. package/dist/{chunk-BQG7VEBY.js → chunk-D2IWOO4X.js} +2 -2
  5. package/dist/{chunk-KYLNC4CD.cjs → chunk-KNGHYGK4.cjs} +17 -17
  6. package/dist/{chunk-KYLNC4CD.cjs.map → chunk-KNGHYGK4.cjs.map} +1 -1
  7. package/dist/{chunk-FKDMDAUR.js → chunk-LRFMCJY3.js} +119 -19
  8. package/dist/chunk-LRFMCJY3.js.map +1 -0
  9. package/dist/{chunk-GHUV2FLD.cjs → chunk-QB2UD62G.cjs} +8 -8
  10. package/dist/{chunk-GHUV2FLD.cjs.map → chunk-QB2UD62G.cjs.map} +1 -1
  11. package/dist/{chunk-KKKYW54Z.js → chunk-SLFAEVKJ.js} +3 -3
  12. package/dist/{chunk-TKWN42TA.cjs → chunk-Z6M3HKLG.cjs} +156 -156
  13. package/dist/{chunk-TKWN42TA.cjs.map → chunk-Z6M3HKLG.cjs.map} +1 -1
  14. package/dist/{chunk-6SOPF5LZ.cjs → chunk-ZR435MDC.cjs} +120 -20
  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 +120 -25
  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 +64 -42
  23. package/dist/internal.cjs.map +1 -1
  24. package/dist/internal.d.cts +12 -3
  25. package/dist/internal.d.ts +12 -3
  26. package/dist/internal.js +25 -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/cycle-guard.ts +1 -1
  40. package/src/internal.ts +4 -0
  41. package/src/list-helpers.ts +19 -4
  42. package/src/loader.ts +58 -0
  43. package/src/resume.ts +55 -0
  44. package/src/signal.ts +47 -22
  45. package/src/ssr-stream.ts +38 -0
  46. package/src/suspense.ts +62 -7
  47. package/dist/chunk-6SOPF5LZ.cjs.map +0 -1
  48. package/dist/chunk-FKDMDAUR.js.map +0 -1
  49. /package/dist/{chunk-5AA7HP4S.js.map → chunk-4NUHM77Z.js.map} +0 -0
  50. /package/dist/{chunk-BQG7VEBY.js.map → chunk-D2IWOO4X.js.map} +0 -0
  51. /package/dist/{chunk-KKKYW54Z.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 _chunkKYLNC4CDcjs = require('./chunk-KYLNC4CD.cjs');
5
+ var _chunkKNGHYGK4cjs = require('./chunk-KNGHYGK4.cjs');
6
6
 
7
7
 
8
8
 
@@ -19,7 +19,7 @@ var _chunkKYLNC4CDcjs = require('./chunk-KYLNC4CD.cjs');
19
19
 
20
20
 
21
21
 
22
- var _chunkTKWN42TAcjs = require('./chunk-TKWN42TA.cjs');
22
+ var _chunkZ6M3HKLGcjs = require('./chunk-Z6M3HKLG.cjs');
23
23
 
24
24
 
25
25
 
@@ -37,7 +37,10 @@ var _chunkTKWN42TAcjs = require('./chunk-TKWN42TA.cjs');
37
37
 
38
38
 
39
39
 
40
- var _chunk6SOPF5LZcjs = require('./chunk-6SOPF5LZ.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 = _chunk6SOPF5LZcjs.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
- _chunkTKWN42TAcjs.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 = _chunk6SOPF5LZcjs.createRootContext.call(void 0, hostRoot);
77
- const prev = _chunk6SOPF5LZcjs.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 = _chunkTKWN42TAcjs.createElement.call(void 0, value);
81
- nodes = _chunkTKWN42TAcjs.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
- _chunkTKWN42TAcjs.insertNodesBefore.call(void 0, parentNode, nodes, marker);
87
+ _chunkZ6M3HKLGcjs.insertNodesBefore.call(void 0, parentNode, nodes, marker);
85
88
  }
86
89
  } catch (err) {
87
- _chunk6SOPF5LZcjs.popRoot.call(void 0, prev);
88
- _chunk6SOPF5LZcjs.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
- _chunk6SOPF5LZcjs.popRoot.call(void 0, prev);
104
- _chunk6SOPF5LZcjs.flushOnMount.call(void 0, root);
106
+ _chunkZR435MDCcjs.popRoot.call(void 0, prev);
107
+ _chunkZR435MDCcjs.flushOnMount.call(void 0, root);
105
108
  cleanup = () => {
106
- _chunk6SOPF5LZcjs.destroyRoot.call(void 0, root);
107
- _chunkTKWN42TAcjs.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
- _chunk6SOPF5LZcjs.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
- _chunk6SOPF5LZcjs.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 = _chunk6SOPF5LZcjs.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 = _chunk6SOPF5LZcjs.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
- _chunkTKWN42TAcjs.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 = _chunk6SOPF5LZcjs.createRootContext.call(void 0, hostRoot);
172
- const prev = _chunk6SOPF5LZcjs.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 = _chunkTKWN42TAcjs.createElement.call(void 0, view);
176
- nodes = _chunkTKWN42TAcjs.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
- _chunk6SOPF5LZcjs.popRoot.call(void 0, prev);
180
- _chunk6SOPF5LZcjs.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
- _chunkTKWN42TAcjs.insertNodesBefore.call(void 0, parentNode, nodes, marker);
194
+ _chunkZ6M3HKLGcjs.insertNodesBefore.call(void 0, parentNode, nodes, endMarker);
186
195
  }
187
196
  } catch (err) {
188
- _chunk6SOPF5LZcjs.popRoot.call(void 0, prev);
189
- _chunk6SOPF5LZcjs.destroyRoot.call(void 0, root);
190
- if (!_chunk6SOPF5LZcjs.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
- _chunk6SOPF5LZcjs.popRoot.call(void 0, prev);
196
- _chunk6SOPF5LZcjs.flushOnMount.call(void 0, root);
208
+ _chunkZR435MDCcjs.popRoot.call(void 0, prev);
209
+ _chunkZR435MDCcjs.flushOnMount.call(void 0, root);
197
210
  cleanup = () => {
198
- _chunk6SOPF5LZcjs.destroyRoot.call(void 0, root);
199
- _chunkTKWN42TAcjs.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
- _chunk6SOPF5LZcjs.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 (!_chunk6SOPF5LZcjs.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
- _chunk6SOPF5LZcjs.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 = _chunkTKWN42TAcjs.Fragment; exports.Suspense = Suspense; exports.batch = _chunkTKWN42TAcjs.batch; exports.createContext = _chunkKYLNC4CDcjs.createContext; exports.createEffect = _chunk6SOPF5LZcjs.createEffect; exports.createElement = _chunkTKWN42TAcjs.createElement; exports.createMemo = _chunk6SOPF5LZcjs.createMemo; exports.createPortal = _chunkTKWN42TAcjs.createPortal; exports.createRef = createRef; exports.createRoot = _chunk6SOPF5LZcjs.createRoot; exports.createSuspenseToken = createSuspenseToken; exports.hasContext = _chunkKYLNC4CDcjs.hasContext; exports.keyed = _chunkTKWN42TAcjs.keyed; exports.mergeProps = _chunkTKWN42TAcjs.mergeProps; exports.onCleanup = _chunk6SOPF5LZcjs.onCleanup; exports.onDestroy = _chunk6SOPF5LZcjs.onDestroy; exports.onMount = _chunk6SOPF5LZcjs.onMount; exports.prop = _chunkTKWN42TAcjs.prop; exports.render = _chunkTKWN42TAcjs.render; exports.startTransition = _chunkTKWN42TAcjs.startTransition; exports.untrack = _chunkTKWN42TAcjs.untrack; exports.useContext = _chunkKYLNC4CDcjs.useContext; exports.useDeferredValue = _chunkTKWN42TAcjs.useDeferredValue; exports.useTransition = _chunkTKWN42TAcjs.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":"AAAA;AACE;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACA;ACnBO,SAAS,SAAA,CAAA,EAA2D;AACzE,EAAA,OAAO,EAAE,OAAA,EAAS,KAAK,CAAA;AACzB;ADqBA;AACA;AE1BO,SAAS,aAAA,CAAc,KAAA,EAAqC;AACjE,EAAA,MAAM,SAAA,EAAW,QAAA,CAAS,sBAAA,CAAuB,CAAA;AACjD,EAAA,MAAM,OAAA,EAAS,QAAA,CAAS,aAAA,CAAc,qBAAqB,CAAA;AAC3D,EAAA,QAAA,CAAS,WAAA,CAAY,MAAM,CAAA;AAE3B,EAAA,MAAM,SAAA,EAAW,8CAAA,CAAe;AAEhC,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,YAAA,EAAsB,CAAC,CAAA;AAC3B,EAAA,IAAI,kBAAA,EAAoB,KAAA;AAExB,EAAA,IAAI,MAAA,EAAQ,CAAA,EAAA,GAAM;AAAA,EAAC,CAAA;AACnB,EAAA,MAAM,OAAA,EAAS,CAAC,GAAA,EAAA,GAAyC;AACvD,IAAA,GAAA,CAAI,IAAA,GAAO,IAAA,EAAM;AACf,MAAA,OAAO,OAAO,KAAA,CAAM,SAAA,IAAa,WAAA,EAC5B,KAAA,CAAM,QAAA,CAA0D,GAAA,EAAK,KAAK,EAAA,EAC3E,KAAA,CAAM,QAAA;AAAA,IACZ;AACA,IAAA,wBAAO,KAAA,CAAM,QAAA,UAAY,MAAA;AAAA,EAC3B,CAAA;AAEA,EAAA,MAAM,YAAA,EAAc,CAAC,KAAA,EAAA,GAA2B;AAC9C,IAAA,GAAA,CAAI,OAAA,EAAS;AACX,MAAA,OAAA,CAAQ,CAAA;AACR,MAAA,QAAA,EAAU,KAAA,CAAA;AAAA,IACZ;AACA,IAAA,GAAA,CAAI,WAAA,CAAY,MAAA,EAAQ;AACtB,MAAA,2CAAA,WAAuB,CAAA;AACvB,MAAA,YAAA,EAAc,CAAC,CAAA;AAAA,IACjB;AAEA,IAAA,GAAA,CAAI,MAAA,GAAS,KAAA,GAAQ,MAAA,IAAU,KAAA,EAAO;AACpC,MAAA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,EAAO,iDAAA,QAA0B,CAAA;AACvC,IAAA,MAAM,KAAA,EAAO,wCAAA,IAAa,CAAA;AAC1B,IAAA,IAAI,MAAA,EAAgB,CAAC,CAAA;AACrB,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,EAAS,6CAAA,KAAmB,CAAA;AAClC,MAAA,MAAA,EAAQ,2CAAA,MAAkB,CAAA;AAC1B,MAAA,MAAM,WAAA,EAAa,MAAA,CAAO,UAAA;AAC1B,MAAA,GAAA,CAAI,UAAA,EAAY;AACd,QAAA,iDAAA,UAAkB,EAAY,KAAA,EAAO,MAAM,CAAA;AAAA,MAC7C;AAAA,IACF,EAAA,MAAA,CAAS,GAAA,EAAK;AACZ,MAAA,uCAAA,IAAY,CAAA;AACZ,MAAA,2CAAA,IAAgB,CAAA;AAEhB,MAAA,GAAA,CAAI,iBAAA,EAAmB;AACrB,QAAA,MAAM,GAAA;AAAA,MACR;AAGA,MAAA,kBAAA,EAAoB,IAAA;AACpB,MAAA,IAAI;AACF,QAAA,WAAA,CAAY,MAAA,CAAO,GAAG,CAAC,CAAA;AAGvB,QAAA,kBAAA,EAAoB,KAAA;AACpB,wBAAA,KAAA,mBAAM,OAAA,0BAAA,CAAU,GAAG,GAAA;AAAA,MACrB,EAAA,MAAA,CAAS,WAAA,EAAa;AAIpB,wBAAA,KAAA,qBAAM,OAAA,0BAAA,CAAU,GAAG,GAAA;AACnB,QAAA,MAAM,WAAA;AAAA,MACR;AACA,MAAA,MAAA;AAAA,IACF;AACA,IAAA,uCAAA,IAAY,CAAA;AACZ,IAAA,4CAAA,IAAiB,CAAA;AAEjB,IAAA,QAAA,EAAU,CAAA,EAAA,GAAM;AACd,MAAA,2CAAA,IAAgB,CAAA;AAChB,MAAA,2CAAA,KAAiB,CAAA;AAAA,IACnB,CAAA;AACA,IAAA,YAAA,EAAc,KAAA;AAAA,EAChB,CAAA;AAEA,EAAA,MAAA,EAAQ,CAAA,EAAA,GAAM;AACZ,IAAA,kBAAA,EAAoB,KAAA;AACpB,IAAA,WAAA,CAAY,MAAA,CAAO,IAAI,CAAC,CAAA;AAAA,EAC1B,CAAA;AAEA,EAAA,WAAA,kBAAY,KAAA,CAAM,QAAA,UAAY,MAAI,CAAA;AAElC,EAAA,oDAAA,CAAqB,GAAA,EAAA,GAAO;AAC1B,IAAA,WAAA,CAAY,MAAA,CAAO,GAAG,CAAC,CAAA;AACvB,oBAAA,KAAA,qBAAM,OAAA,0BAAA,CAAU,GAAG,GAAA;AACnB,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AAED,EAAA,GAAA,CAAI,KAAA,CAAM,UAAA,IAAc,KAAA,CAAA,EAAW;AACjC,IAAA,MAAM,SAAA,EACJ,OAAO,KAAA,CAAM,UAAA,IAAc,WAAA,GAAe,KAAA,CAAM,SAAA,CAA4B,OAAA,IAAW,CAAA;AACzF,IAAA,MAAM,OAAA,EAAS,SAAA,EAAY,KAAA,CAAM,UAAA,EAA8B,KAAA,CAAA;AAC/D,IAAA,IAAI,KAAA,EAAO,SAAA,EAAW,MAAA,CAAQ,EAAA,EAAI,KAAA,CAAM,SAAA;AACxC,IAAA,4CAAA,CAAa,EAAA,GAAM;AACjB,MAAA,MAAM,KAAA,EAAO,OAAA,EAAS,MAAA,CAAO,EAAA,EAAI,KAAA,CAAM,SAAA;AACvC,MAAA,GAAA,CAAI,KAAA,IAAS,IAAA,EAAM;AACjB,QAAA,KAAA,EAAO,IAAA;AACP,QAAA,WAAA,CAAY,MAAA,CAAO,IAAI,CAAC,CAAA;AAAA,MAC1B;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,QAAA;AACT;AFMA;AACA;AG1GO,SAAS,mBAAA,CAAA,EAAsC;AACpD,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,MAAA;AACJ,EAAA,MAAM,QAAA,EAAU,IAAI,OAAA,CAAc,CAAC,GAAA,EAAK,GAAA,EAAA,GAAQ;AAC9C,IAAA,QAAA,EAAU,GAAA;AACV,IAAA,OAAA,EAAS,GAAA;AAAA,EACX,CAAC,CAAA;AACD,EAAA,OAAO;AAAA,IACL,KAAA,EAAO;AAAA,MACL,IAAA,EAAM,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAK,OAAO;AAAA,IACjC,CAAA;AAAA,IACA,OAAA;AAAA,IACA;AAAA,EACF,CAAA;AACF;AAEA,IAAM,WAAA,EAAa,CAAC,KAAA,EAAA,GAClB,OAAO,MAAA,IAAU,SAAA,GACjB,MAAA,IAAU,KAAA,GACV,OAAQ,KAAA,CAA+B,KAAA,IAAS,UAAA;AAE3C,SAAS,QAAA,CAAS,KAAA,EAAgC;AACvD,EAAA,MAAM,QAAA,EAAU,sCAAA,CAAc,CAAA;AAC9B,EAAA,IAAI,aAAA,EAAe,KAAA;AACnB,EAAA,IAAI,MAAA,EAAQ,CAAA;AACZ,EAAA,MAAM,SAAA,EAAW,8CAAA,CAAe;AAEhC,EAAA,MAAM,WAAA,EAAa,CAAC,GAAA,EAAA,GAClB,OAAO,KAAA,CAAM,SAAA,IAAa,WAAA,EACrB,KAAA,CAAM,QAAA,CAAuC,GAAG,EAAA,EACjD,KAAA,CAAM,QAAA;AAEZ,EAAA,MAAM,WAAA,EAAa,CAAC,IAAA,EAAA,GAA0B;AAC5C,IAAA,GAAA,CAAI,OAAA,EAAS;AACX,MAAA,OAAA,CAAQ,CAAA;AACR,MAAA,QAAA,EAAU,KAAA,CAAA;AAAA,IACZ;AACA,IAAA,GAAA,CAAI,WAAA,CAAY,MAAA,EAAQ;AACtB,MAAA,2CAAA,WAAuB,CAAA;AACvB,MAAA,YAAA,EAAc,CAAC,CAAA;AAAA,IACjB;AAEA,IAAA,GAAA,CAAI,KAAA,GAAQ,KAAA,GAAQ,KAAA,IAAS,KAAA,EAAO;AAClC,MAAA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,EAAO,iDAAA,QAA0B,CAAA;AACvC,IAAA,MAAM,KAAA,EAAO,wCAAA,IAAa,CAAA;AAC1B,IAAA,IAAI,MAAA,EAAgB,CAAC,CAAA;AACrB,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,EAAS,6CAAA,IAAkB,CAAA;AACjC,MAAA,MAAA,EAAQ,2CAAA,MAAkB,CAAA;AAG1B,MAAA,MAAM,iBAAA,EACJ,IAAA,CAAK,UAAA,GACJ,KAAA,CAAM,OAAA,EAAS,EAAA,GACd,KAAA,CAAM,KAAA,CAAM,CAAA,IAAA,EAAA,GAAQ,KAAA,WAAgB,QAAA,GAAY,IAAA,CAAiB,KAAA,IAAS,cAAc,CAAA;AAC5F,MAAA,GAAA,CAAI,gBAAA,EAAkB;AACpB,QAAA,uCAAA,IAAY,CAAA;AACZ,QAAA,2CAAA,IAAgB,CAAA;AAChB,QAAA,MAAA;AAAA,MACF;AACA,MAAA,MAAM,WAAA,EAAa,MAAA,CAAO,UAAA;AAC1B,MAAA,GAAA,CAAI,UAAA,EAAY;AACd,QAAA,iDAAA,UAAkB,EAAY,KAAA,EAAO,MAAM,CAAA;AAAA,MAC7C;AAAA,IACF,EAAA,MAAA,CAAS,GAAA,EAAK;AACZ,MAAA,uCAAA,IAAY,CAAA;AACZ,MAAA,2CAAA,IAAgB,CAAA;AAChB,MAAA,GAAA,CAAI,CAAC,2CAAA,GAAY,EAAK,EAAE,MAAA,EAAQ,SAAS,CAAA,EAAG,QAAQ,CAAA,EAAG;AACrD,QAAA,MAAM,GAAA;AAAA,MACR;AACA,MAAA,MAAA;AAAA,IACF;AACA,IAAA,uCAAA,IAAY,CAAA;AACZ,IAAA,4CAAA,IAAiB,CAAA;AAEjB,IAAA,QAAA,EAAU,CAAA,EAAA,GAAM;AACd,MAAA,2CAAA,IAAgB,CAAA;AAChB,MAAA,2CAAA,KAAiB,CAAA;AAAA,IACnB,CAAA;AACA,IAAA,YAAA,EAAc,KAAA;AAAA,EAChB,CAAA;AAEA,EAAA,MAAM,SAAA,EAAW,QAAA,CAAS,sBAAA,CAAuB,CAAA;AACjD,EAAA,MAAM,OAAA,EAAS,QAAA,CAAS,aAAA,CAAc,eAAe,CAAA;AACrD,EAAA,QAAA,CAAS,WAAA,CAAY,MAAM,CAAA;AAC3B,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,YAAA,EAAsB,CAAC,CAAA;AAE3B,EAAA,MAAM,eAAA,EAAiB,CAAA,EAAA,GAAM;AAC3B,IAAA,GAAA,CAAI,CAAC,YAAA,EAAc;AACjB,MAAA,aAAA,EAAe,IAAA;AACf,sBAAA,KAAA,qBAAM,SAAA,0BAAA,CAAY,GAAA;AAAA,IACpB;AAAA,EACF,CAAA;AAEA,EAAA,uDAAA,CAAwB,KAAA,EAAA,GAAS;AAC/B,IAAA,MAAM,WAAA,EAAa,KAAA;AACnB,IAAA,OAAA,CAAQ,OAAA,CAAQ,EAAA,EAAI,CAAC,CAAA;AAGrB,IAAA,UAAA,CAAW,UAAA,CAAW,CAAC,CAAA;AAEvB,IAAA,MAAM,SAAA,EAAY,KAAA,CAAwB,KAAA,EACrC,MAAA,EACD,UAAA,CAAW,KAAK,EAAA,EACd,MAAA,EACA,IAAA;AAEN,IAAA,GAAA,CAAI,QAAA,EAAU;AACZ,MAAA,QAAA,CAAS,IAAA;AAAA,QACP,CAAA,EAAA,GAAM;AAGJ,UAAA,GAAA,CAAI,MAAA,IAAU,UAAA,EAAY;AAExB,YAAA,MAAA;AAAA,UACF;AAIA,UAAA,MAAM,WAAA,EAAa,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAA,CAAQ,EAAA,EAAI,CAAC,CAAA;AAC5C,UAAA,OAAA,CAAQ,UAAU,CAAA;AAClB,UAAA,GAAA,CAAI,WAAA,IAAe,CAAA,EAAG;AAEpB,YAAA,UAAA,kBAAW,KAAA,CAAM,QAAA,UAAY,MAAI,CAAA;AACjC,YAAA,cAAA,CAAe,CAAA;AAAA,UACjB;AAAA,QACF,CAAA;AAAA,QACA,CAAA,GAAA,EAAA,GAAO;AAEL,UAAA,GAAA,CAAI,MAAA,IAAU,UAAA,EAAY;AACxB,YAAA,MAAA;AAAA,UACF;AACA,UAAA,MAAM,WAAA,EAAa,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAA,CAAQ,EAAA,EAAI,CAAC,CAAA;AAC5C,UAAA,OAAA,CAAQ,UAAU,CAAA;AAClB,0BAAA,KAAA,qBAAM,QAAA,4BAAA,CAAW,GAAG,GAAA;AACpB,UAAA,GAAA,CAAI,CAAC,2CAAA,GAAY,EAAK,EAAE,MAAA,EAAQ,SAAS,CAAA,EAAG,QAAQ,CAAA,EAAG;AACrD,YAAA,MAAM,GAAA;AAAA,UACR;AAAA,QACF;AAAA,MACF,CAAA;AACA,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,OAAO,KAAA;AAAA,EACT,CAAC,CAAA;AAKD,EAAA,UAAA,kBAAW,KAAA,CAAM,QAAA,UAAY,MAAI,CAAA;AAEjC,EAAA,GAAA,CAAI,KAAA,CAAM,UAAA,IAAc,KAAA,CAAA,EAAW;AACjC,IAAA,MAAM,SAAA,EACJ,OAAO,KAAA,CAAM,UAAA,IAAc,WAAA,GAAe,KAAA,CAAM,SAAA,CAA4B,OAAA,IAAW,CAAA;AACzF,IAAA,MAAM,OAAA,EAAS,SAAA,EAAY,KAAA,CAAM,UAAA,EAA8B,KAAA,CAAA;AAC/D,IAAA,IAAI,KAAA,EAAO,SAAA,EAAW,MAAA,CAAQ,EAAA,EAAI,KAAA,CAAM,SAAA;AACxC,IAAA,4CAAA,CAAa,EAAA,GAAM;AACjB,MAAA,MAAM,KAAA,EAAO,OAAA,EAAS,MAAA,CAAO,EAAA,EAAI,KAAA,CAAM,SAAA;AACvC,MAAA,GAAA,CAAI,KAAA,IAAS,IAAA,EAAM;AACjB,QAAA,KAAA,EAAO,IAAA;AACP,QAAA,KAAA,EAAA;AACA,QAAA,OAAA,CAAQ,CAAC,CAAA;AAET,QAAA,UAAA,kBAAW,KAAA,CAAM,QAAA,UAAY,MAAI,CAAA;AAAA,MACnC;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,QAAA;AACT;AH8DA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wrCAAC","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":"AAAA;AACE;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACA;ACtBO,SAAS,SAAA,CAAA,EAA2D;AACzE,EAAA,OAAO,EAAE,OAAA,EAAS,KAAK,CAAA;AACzB;ADwBA;AACA;AE7BO,SAAS,aAAA,CAAc,KAAA,EAAqC;AACjE,EAAA,MAAM,SAAA,EAAW,QAAA,CAAS,sBAAA,CAAuB,CAAA;AACjD,EAAA,MAAM,OAAA,EAAS,QAAA,CAAS,aAAA,CAAc,qBAAqB,CAAA;AAC3D,EAAA,QAAA,CAAS,WAAA,CAAY,MAAM,CAAA;AAE3B,EAAA,MAAM,SAAA,EAAW,8CAAA,CAAe;AAEhC,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,YAAA,EAAsB,CAAC,CAAA;AAC3B,EAAA,IAAI,kBAAA,EAAoB,KAAA;AAExB,EAAA,IAAI,MAAA,EAAQ,CAAA,EAAA,GAAM;AAAA,EAAC,CAAA;AACnB,EAAA,MAAM,OAAA,EAAS,CAAC,GAAA,EAAA,GAAyC;AACvD,IAAA,GAAA,CAAI,IAAA,GAAO,IAAA,EAAM;AACf,MAAA,OAAO,OAAO,KAAA,CAAM,SAAA,IAAa,WAAA,EAC5B,KAAA,CAAM,QAAA,CAA0D,GAAA,EAAK,KAAK,EAAA,EAC3E,KAAA,CAAM,QAAA;AAAA,IACZ;AACA,IAAA,wBAAO,KAAA,CAAM,QAAA,UAAY,MAAA;AAAA,EAC3B,CAAA;AAEA,EAAA,MAAM,YAAA,EAAc,CAAC,KAAA,EAAA,GAA2B;AAC9C,IAAA,GAAA,CAAI,OAAA,EAAS;AACX,MAAA,OAAA,CAAQ,CAAA;AACR,MAAA,QAAA,EAAU,KAAA,CAAA;AAAA,IACZ;AACA,IAAA,GAAA,CAAI,WAAA,CAAY,MAAA,EAAQ;AACtB,MAAA,2CAAA,WAAuB,CAAA;AACvB,MAAA,YAAA,EAAc,CAAC,CAAA;AAAA,IACjB;AAEA,IAAA,GAAA,CAAI,MAAA,GAAS,KAAA,GAAQ,MAAA,IAAU,KAAA,EAAO;AACpC,MAAA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,EAAO,iDAAA,QAA0B,CAAA;AACvC,IAAA,MAAM,KAAA,EAAO,wCAAA,IAAa,CAAA;AAC1B,IAAA,IAAI,MAAA,EAAgB,CAAC,CAAA;AACrB,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,EAAS,6CAAA,KAAmB,CAAA;AAClC,MAAA,MAAA,EAAQ,2CAAA,MAAkB,CAAA;AAC1B,MAAA,MAAM,WAAA,EAAa,MAAA,CAAO,UAAA;AAC1B,MAAA,GAAA,CAAI,UAAA,EAAY;AACd,QAAA,iDAAA,UAAkB,EAAY,KAAA,EAAO,MAAM,CAAA;AAAA,MAC7C;AAAA,IACF,EAAA,MAAA,CAAS,GAAA,EAAK;AACZ,MAAA,uCAAA,IAAY,CAAA;AACZ,MAAA,2CAAA,IAAgB,CAAA;AAEhB,MAAA,GAAA,CAAI,iBAAA,EAAmB;AACrB,QAAA,MAAM,GAAA;AAAA,MACR;AAGA,MAAA,kBAAA,EAAoB,IAAA;AACpB,MAAA,IAAI;AACF,QAAA,WAAA,CAAY,MAAA,CAAO,GAAG,CAAC,CAAA;AAGvB,QAAA,kBAAA,EAAoB,KAAA;AACpB,wBAAA,KAAA,mBAAM,OAAA,0BAAA,CAAU,GAAG,GAAA;AAAA,MACrB,EAAA,MAAA,CAAS,WAAA,EAAa;AAIpB,wBAAA,KAAA,qBAAM,OAAA,0BAAA,CAAU,GAAG,GAAA;AACnB,QAAA,MAAM,WAAA;AAAA,MACR;AACA,MAAA,MAAA;AAAA,IACF;AACA,IAAA,uCAAA,IAAY,CAAA;AACZ,IAAA,4CAAA,IAAiB,CAAA;AAEjB,IAAA,QAAA,EAAU,CAAA,EAAA,GAAM;AACd,MAAA,2CAAA,IAAgB,CAAA;AAChB,MAAA,2CAAA,KAAiB,CAAA;AAAA,IACnB,CAAA;AACA,IAAA,YAAA,EAAc,KAAA;AAAA,EAChB,CAAA;AAEA,EAAA,MAAA,EAAQ,CAAA,EAAA,GAAM;AACZ,IAAA,kBAAA,EAAoB,KAAA;AACpB,IAAA,WAAA,CAAY,MAAA,CAAO,IAAI,CAAC,CAAA;AAAA,EAC1B,CAAA;AAEA,EAAA,WAAA,kBAAY,KAAA,CAAM,QAAA,UAAY,MAAI,CAAA;AAElC,EAAA,oDAAA,CAAqB,GAAA,EAAA,GAAO;AAC1B,IAAA,WAAA,CAAY,MAAA,CAAO,GAAG,CAAC,CAAA;AACvB,oBAAA,KAAA,qBAAM,OAAA,0BAAA,CAAU,GAAG,GAAA;AACnB,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AAED,EAAA,GAAA,CAAI,KAAA,CAAM,UAAA,IAAc,KAAA,CAAA,EAAW;AACjC,IAAA,MAAM,SAAA,EACJ,OAAO,KAAA,CAAM,UAAA,IAAc,WAAA,GAAe,KAAA,CAAM,SAAA,CAA4B,OAAA,IAAW,CAAA;AACzF,IAAA,MAAM,OAAA,EAAS,SAAA,EAAY,KAAA,CAAM,UAAA,EAA8B,KAAA,CAAA;AAC/D,IAAA,IAAI,KAAA,EAAO,SAAA,EAAW,MAAA,CAAQ,EAAA,EAAI,KAAA,CAAM,SAAA;AACxC,IAAA,4CAAA,CAAa,EAAA,GAAM;AACjB,MAAA,MAAM,KAAA,EAAO,OAAA,EAAS,MAAA,CAAO,EAAA,EAAI,KAAA,CAAM,SAAA;AACvC,MAAA,GAAA,CAAI,KAAA,IAAS,IAAA,EAAM;AACjB,QAAA,KAAA,EAAO,IAAA;AACP,QAAA,WAAA,CAAY,MAAA,CAAO,IAAI,CAAC,CAAA;AAAA,MAC1B;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,QAAA;AACT;AFSA;AACA;AG5GO,SAAS,mBAAA,CAAA,EAAsC;AACpD,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,MAAA;AACJ,EAAA,MAAM,QAAA,EAAU,IAAI,OAAA,CAAc,CAAC,GAAA,EAAK,GAAA,EAAA,GAAQ;AAC9C,IAAA,QAAA,EAAU,GAAA;AACV,IAAA,OAAA,EAAS,GAAA;AAAA,EACX,CAAC,CAAA;AACD,EAAA,OAAO;AAAA,IACL,KAAA,EAAO;AAAA,MACL,IAAA,EAAM,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAK,OAAO;AAAA,IACjC,CAAA;AAAA,IACA,OAAA;AAAA,IACA;AAAA,EACF,CAAA;AACF;AAEA,IAAM,WAAA,EAAa,CAAC,KAAA,EAAA,GAClB,OAAO,MAAA,IAAU,SAAA,GACjB,MAAA,IAAU,KAAA,GACV,OAAQ,KAAA,CAA+B,KAAA,IAAS,UAAA;AAE3C,SAAS,QAAA,CAAS,KAAA,EAAgC;AACvD,EAAA,MAAM,YAAA,EAAc,uDAAA,CAAwB;AAC5C,EAAA,MAAM,QAAA,EAAU,sCAAA,CAAc,CAAA;AAC9B,EAAA,IAAI,aAAA,EAAe,KAAA;AACnB,EAAA,IAAI,MAAA,EAAQ,CAAA;AACZ,EAAA,MAAM,SAAA,EAAW,8CAAA,CAAe;AAEhC,EAAA,MAAM,WAAA,EAAa,CAAC,GAAA,EAAA,GAClB,OAAO,KAAA,CAAM,SAAA,IAAa,WAAA,EACrB,KAAA,CAAM,QAAA,CAAuC,GAAG,EAAA,EACjD,KAAA,CAAM,QAAA;AAEZ,EAAA,MAAM,WAAA,EAAa,CAAC,IAAA,EAAA,GAA0B;AAC5C,IAAA,GAAA,CAAI,OAAA,EAAS;AACX,MAAA,OAAA,CAAQ,CAAA;AACR,MAAA,QAAA,EAAU,KAAA,CAAA;AAAA,IACZ;AACA,IAAA,GAAA,CAAI,WAAA,CAAY,MAAA,EAAQ;AACtB,MAAA,2CAAA,WAAuB,CAAA;AACvB,MAAA,YAAA,EAAc,CAAC,CAAA;AAAA,IACjB;AAEA,IAAA,GAAA,CAAI,KAAA,GAAQ,KAAA,GAAQ,KAAA,IAAS,KAAA,EAAO;AAClC,MAAA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,EAAO,iDAAA,QAA0B,CAAA;AACvC,IAAA,MAAM,KAAA,EAAO,wCAAA,IAAa,CAAA;AAC1B,IAAA,IAAI,MAAA,EAAgB,CAAC,CAAA;AACrB,IAAA,IAAI,eAAA,EAAiB,KAAA;AACrB,IAAA,IAAI;AACF,MAAA,GAAA,CAAI,gBAAA,EAAkB;AACpB,QAAA,qDAAA,gBAAsC,CAAA;AACtC,QAAA,eAAA,EAAiB,IAAA;AAAA,MACnB;AACA,MAAA,MAAM,OAAA,EAAS,6CAAA,IAAkB,CAAA;AACjC,MAAA,MAAA,EAAQ,2CAAA,MAAkB,CAAA;AAG1B,MAAA,MAAM,iBAAA,EACJ,IAAA,CAAK,UAAA,GACJ,KAAA,CAAM,OAAA,EAAS,EAAA,GACd,KAAA,CAAM,KAAA,CAAM,CAAA,IAAA,EAAA,GAAQ,KAAA,WAAgB,QAAA,GAAY,IAAA,CAAiB,KAAA,IAAS,cAAc,CAAA;AAC5F,MAAA,GAAA,CAAI,gBAAA,EAAkB;AACpB,QAAA,uCAAA,IAAY,CAAA;AACZ,QAAA,2CAAA,IAAgB,CAAA;AAChB,QAAA,MAAA;AAAA,MACF;AACA,MAAA,MAAM,WAAA,EAAa,SAAA,CAAU,UAAA;AAC7B,MAAA,GAAA,CAAI,UAAA,EAAY;AACd,QAAA,iDAAA,UAAkB,EAAY,KAAA,EAAO,SAAS,CAAA;AAAA,MAChD;AAAA,IACF,EAAA,MAAA,CAAS,GAAA,EAAK;AACZ,MAAA,uCAAA,IAAY,CAAA;AACZ,MAAA,2CAAA,IAAgB,CAAA;AAChB,MAAA,GAAA,CAAI,CAAC,2CAAA,GAAY,EAAK,EAAE,MAAA,EAAQ,SAAS,CAAA,EAAG,QAAQ,CAAA,EAAG;AACrD,QAAA,MAAM,GAAA;AAAA,MACR;AACA,MAAA,MAAA;AAAA,IACF,EAAA,QAAE;AACA,MAAA,GAAA,CAAI,cAAA,EAAgB;AAClB,QAAA,oDAAA,iBAAqB,gBAAA,UAAoB,KAAA,GAAS,CAAA;AAAA,MACpD;AAAA,IACF;AACA,IAAA,uCAAA,IAAY,CAAA;AACZ,IAAA,4CAAA,IAAiB,CAAA;AAEjB,IAAA,QAAA,EAAU,CAAA,EAAA,GAAM;AACd,MAAA,2CAAA,IAAgB,CAAA;AAChB,MAAA,2CAAA,KAAiB,CAAA;AAAA,IACnB,CAAA;AACA,IAAA,YAAA,EAAc,KAAA;AAAA,EAChB,CAAA;AAEA,EAAA,MAAM,SAAA,EAAW,QAAA,CAAS,sBAAA,CAAuB,CAAA;AACjD,EAAA,MAAM,YAAA,EAAc,QAAA,CAAS,aAAA,CAAc,qBAAqB,CAAA;AAChE,EAAA,MAAM,UAAA,EAAY,QAAA,CAAS,aAAA,CAAc,mBAAmB,CAAA;AAC5D,EAAA,QAAA,CAAS,WAAA,CAAY,WAAW,CAAA;AAChC,EAAA,QAAA,CAAS,WAAA,CAAY,SAAS,CAAA;AAC9B,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,YAAA,EAAsB,CAAC,CAAA;AAC3B,EAAA,IAAI,iBAAA,EAAkC,IAAA;AACtC,EAAA,IAAI,cAAA,EAAgB,KAAA;AAEpB,EAAA,GAAA,iBAAI,WAAA,6BAAa,kBAAA,EAAkB;AACjC,IAAA,iBAAA,mBAAmB,WAAA,CAAY,gBAAA,CAAiB,WAAA,EAAa,SAAS,CAAA,UAAK,MAAA;AAC3E,IAAA,GAAA,CAAI,gBAAA,EAAkB;AACpB,MAAA,WAAA,CAAY,KAAA,EAAO,CAAA,oBAAA,EAAuB,gBAAgB,CAAA,CAAA;AACJ,MAAA;AACxD,IAAA;AACF,EAAA;AAE6B,EAAA;AACR,IAAA;AACF,MAAA;AACG,sBAAA;AACpB,IAAA;AACF,EAAA;AAEiC,EAAA;AACZ,IAAA;AACoC,IAAA;AACrC,MAAA;AAC4B,MAAA;AAC9C,IAAA;AACqB,IAAA;AAGE,IAAA;AAKjB,IAAA;AAGQ,IAAA;AACH,MAAA;AACD,QAAA;AAGsB,UAAA;AAExB,YAAA;AACF,UAAA;AAI4C,UAAA;AAC1B,UAAA;AACI,UAAA;AAEa,YAAA;AACQ,YAAA;AACvB,cAAA;AAC6B,cAAA;AAC/C,YAAA;AACe,YAAA;AACjB,UAAA;AACF,QAAA;AACO,QAAA;AAEqB,UAAA;AACxB,YAAA;AACF,UAAA;AAC4C,UAAA;AAC1B,UAAA;AACG,UAAA;AACjB,UAAA;AACkB,4BAAA;AACE,UAAA;AACL,YAAA;AACnB,UAAA;AAEsD,UAAA;AACxC,UAAA;AACc,YAAA;AACY,cAAA;AACpC,cAAA;AACF,YAAA;AACM,YAAA;AACR,UAAA;AAIE,UAAA;AAGgB,YAAA;AAC6B,YAAA;AAC/C,UAAA;AACF,QAAA;AACF,MAAA;AACO,MAAA;AACT,IAAA;AAEO,IAAA;AACR,EAAA;AAKgC,EAAA;AAEE,EAAA;AAEW,IAAA;AACmB,IAAA;AACvB,IAAA;AACrB,IAAA;AACsB,MAAA;AACpB,MAAA;AACV,QAAA;AACP,QAAA;AACS,QAAA;AAEwB,QAAA;AACqB,QAAA;AACpC,UAAA;AAC6B,UAAA;AAC/C,QAAA;AACF,MAAA;AACD,IAAA;AACH,EAAA;AAEO,EAAA;AACT;AHyDiE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","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"]}