@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.dev.js CHANGED
@@ -22,7 +22,7 @@ var enterRootGuard = () => true;
22
22
  var exitRootGuard = () => {
23
23
  };
24
24
  var defaultOptions = {
25
- enabled: true,
25
+ enabled: isDev,
26
26
  maxFlushCyclesPerMicrotask: 1e4,
27
27
  maxEffectRunsPerFlush: 2e4,
28
28
  windowSize: 5,
@@ -526,6 +526,8 @@ var cycle = 0;
526
526
  var batchDepth = 0;
527
527
  var activeSub;
528
528
  var flushScheduled = false;
529
+ var currentFlushId = 0;
530
+ var activeCleanupFlushId = 0;
529
531
  var highPriorityQueue = [];
530
532
  var lowPriorityQueue = [];
531
533
  var isInTransition = false;
@@ -771,6 +773,8 @@ function updateSignal(s) {
771
773
  const current = s.currentValue;
772
774
  const pending = s.pendingValue;
773
775
  if (valuesDiffer(s, current, pending)) {
776
+ s.prevValue = current;
777
+ s.prevFlushId = currentFlushId;
774
778
  s.currentValue = pending;
775
779
  return true;
776
780
  }
@@ -789,6 +793,8 @@ function updateComputed(c) {
789
793
  c.flags &= ~Running;
790
794
  purgeDeps(c);
791
795
  if (valuesDiffer(c, oldValue, newValue)) {
796
+ c.prevValue = oldValue;
797
+ c.prevFlushId = currentFlushId;
792
798
  c.value = newValue;
793
799
  if (isDev4) updateComputedDevtools(c, newValue);
794
800
  return true;
@@ -802,15 +808,19 @@ function updateComputed(c) {
802
808
  }
803
809
  function runEffect(e) {
804
810
  const flags = e.flags;
805
- if (flags & Dirty) {
806
- if (e.runCleanup) {
807
- inCleanup = true;
808
- try {
809
- e.runCleanup();
810
- } finally {
811
- inCleanup = false;
812
- }
811
+ const runCleanup = () => {
812
+ if (!e.runCleanup) return;
813
+ inCleanup = true;
814
+ activeCleanupFlushId = currentFlushId;
815
+ try {
816
+ e.runCleanup();
817
+ } finally {
818
+ activeCleanupFlushId = 0;
819
+ inCleanup = false;
813
820
  }
821
+ };
822
+ if (flags & Dirty) {
823
+ runCleanup();
814
824
  ++cycle;
815
825
  if (isDev4) effectRunDevtools(e);
816
826
  e.depsTail = void 0;
@@ -828,14 +838,6 @@ function runEffect(e) {
828
838
  throw err;
829
839
  }
830
840
  } else if (flags & Pending && e.deps) {
831
- if (e.runCleanup) {
832
- inCleanup = true;
833
- try {
834
- e.runCleanup();
835
- } finally {
836
- inCleanup = false;
837
- }
838
- }
839
841
  let isDirty = false;
840
842
  try {
841
843
  isDirty = checkDirty(e.deps, e);
@@ -855,6 +857,7 @@ function runEffect(e) {
855
857
  throw err;
856
858
  }
857
859
  if (isDirty) {
860
+ runCleanup();
858
861
  ++cycle;
859
862
  if (isDev4) effectRunDevtools(e);
860
863
  e.depsTail = void 0;
@@ -900,6 +903,7 @@ function flush() {
900
903
  endFlushGuard();
901
904
  return;
902
905
  }
906
+ currentFlushId++;
903
907
  flushScheduled = false;
904
908
  let highIndex = 0;
905
909
  while (highIndex < highPriorityQueue.length) {
@@ -1004,6 +1008,12 @@ function signalOper(value) {
1004
1008
  if (subs !== void 0) shallowPropagate(subs);
1005
1009
  }
1006
1010
  }
1011
+ if (inCleanup) {
1012
+ if (this.prevFlushId === activeCleanupFlushId) {
1013
+ return this.prevValue;
1014
+ }
1015
+ return this.currentValue;
1016
+ }
1007
1017
  let sub = activeSub;
1008
1018
  while (sub !== void 0) {
1009
1019
  if (sub.flags & 3) {
@@ -1037,7 +1047,12 @@ function computed(getter, options2) {
1037
1047
  return bound;
1038
1048
  }
1039
1049
  function computedOper() {
1040
- if (inCleanup) return this.value;
1050
+ if (inCleanup) {
1051
+ if (this.prevFlushId === activeCleanupFlushId) {
1052
+ return this.prevValue;
1053
+ }
1054
+ return this.value;
1055
+ }
1041
1056
  const flags = this.flags;
1042
1057
  if (flags & Dirty) {
1043
1058
  if (updateComputed(this)) {
@@ -1834,12 +1849,35 @@ function removeNodes(nodes) {
1834
1849
  }
1835
1850
  }
1836
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
+
1837
1874
  // src/resume.ts
1838
1875
  var ssrEnabled = false;
1839
1876
  var resumableEnabled = false;
1840
1877
  var hydrating = false;
1841
1878
  var scopeCounter = 0;
1842
1879
  var scopeRegistry = /* @__PURE__ */ new Map();
1880
+ var boundaryScopes = /* @__PURE__ */ new Map();
1843
1881
  function __fictIsResumable() {
1844
1882
  return ssrEnabled || resumableEnabled;
1845
1883
  }
@@ -1864,6 +1902,16 @@ function __fictRegisterScope(ctx, host, type, props) {
1864
1902
  if (props !== void 0) {
1865
1903
  record.props = props;
1866
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
+ }
1867
1915
  scopeRegistry.set(id, record);
1868
1916
  return id;
1869
1917
  }
@@ -3005,6 +3053,7 @@ function createSuspenseToken() {
3005
3053
  }
3006
3054
  var isThenable = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
3007
3055
  function Suspense(props) {
3056
+ const streamHooks = __fictGetSSRStreamHooks();
3008
3057
  const pending = signal(0);
3009
3058
  let resolvedOnce = false;
3010
3059
  let epoch = 0;
@@ -3025,7 +3074,12 @@ function Suspense(props) {
3025
3074
  const root = createRootContext(hostRoot);
3026
3075
  const prev = pushRoot(root);
3027
3076
  let nodes = [];
3077
+ let boundaryPushed = false;
3028
3078
  try {
3079
+ if (streamBoundaryId) {
3080
+ __fictPushSSRBoundary(streamBoundaryId);
3081
+ boundaryPushed = true;
3082
+ }
3029
3083
  const output = createElement(view);
3030
3084
  nodes = toNodeArray(output);
3031
3085
  const suspendedAttempt = root.suspended || nodes.length > 0 && nodes.every((node) => node instanceof Comment && node.data === "fict:suspend");
@@ -3034,9 +3088,9 @@ function Suspense(props) {
3034
3088
  destroyRoot(root);
3035
3089
  return;
3036
3090
  }
3037
- const parentNode = marker.parentNode;
3091
+ const parentNode = endMarker.parentNode;
3038
3092
  if (parentNode) {
3039
- insertNodesBefore(parentNode, nodes, marker);
3093
+ insertNodesBefore(parentNode, nodes, endMarker);
3040
3094
  }
3041
3095
  } catch (err) {
3042
3096
  popRoot(prev);
@@ -3045,6 +3099,10 @@ function Suspense(props) {
3045
3099
  throw err;
3046
3100
  }
3047
3101
  return;
3102
+ } finally {
3103
+ if (boundaryPushed) {
3104
+ __fictPopSSRBoundary(streamBoundaryId ?? void 0);
3105
+ }
3048
3106
  }
3049
3107
  popRoot(prev);
3050
3108
  flushOnMount(root);
@@ -3055,10 +3113,21 @@ function Suspense(props) {
3055
3113
  activeNodes = nodes;
3056
3114
  };
3057
3115
  const fragment = document.createDocumentFragment();
3058
- const marker = document.createComment("fict:suspense");
3059
- 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);
3060
3120
  let cleanup;
3061
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
+ }
3062
3131
  const onResolveMaybe = () => {
3063
3132
  if (!resolvedOnce) {
3064
3133
  resolvedOnce = true;
@@ -3067,6 +3136,10 @@ function Suspense(props) {
3067
3136
  };
3068
3137
  registerSuspenseHandler((token) => {
3069
3138
  const tokenEpoch = epoch;
3139
+ if (!streamPending && streamBoundaryId && streamHooks?.boundaryPending) {
3140
+ streamPending = true;
3141
+ streamHooks.boundaryPending(streamBoundaryId);
3142
+ }
3070
3143
  pending(pending() + 1);
3071
3144
  renderView(toFallback());
3072
3145
  const thenable = token.then ? token : isThenable(token) ? token : null;
@@ -3080,6 +3153,10 @@ function Suspense(props) {
3080
3153
  pending(newPending);
3081
3154
  if (newPending === 0) {
3082
3155
  renderView(props.children ?? null);
3156
+ if (streamPending && streamBoundaryId && streamHooks?.boundaryResolved) {
3157
+ streamPending = false;
3158
+ streamHooks.boundaryResolved(streamBoundaryId);
3159
+ }
3083
3160
  onResolveMaybe();
3084
3161
  }
3085
3162
  },
@@ -3089,9 +3166,23 @@ function Suspense(props) {
3089
3166
  }
3090
3167
  const newPending = Math.max(0, pending() - 1);
3091
3168
  pending(newPending);
3092
- props.onReject?.(err);
3093
- if (!handleError(err, { source: "render" }, hostRoot)) {
3094
- 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);
3095
3186
  }
3096
3187
  }
3097
3188
  );
@@ -3111,6 +3202,10 @@ function Suspense(props) {
3111
3202
  epoch++;
3112
3203
  pending(0);
3113
3204
  renderView(props.children ?? null);
3205
+ if (streamPending && streamBoundaryId && streamHooks?.boundaryResolved) {
3206
+ streamPending = false;
3207
+ streamHooks.boundaryResolved(streamBoundaryId);
3208
+ }
3114
3209
  }
3115
3210
  });
3116
3211
  }