@solidjs/signals 2.0.0-rc.17 → 2.0.0-rc.19

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 (71) hide show
  1. package/dist/dev-shared.js +426 -241
  2. package/dist/dev.attribution.js +19 -16
  3. package/dist/dev.js +768 -409
  4. package/dist/observe/boundaries.js +88 -67
  5. package/dist/observe/core/action.js +8 -0
  6. package/dist/observe/core/async.js +183 -138
  7. package/dist/observe/core/attribution.js +30 -28
  8. package/dist/observe/core/constants.js +23 -1
  9. package/dist/observe/core/core.js +185 -157
  10. package/dist/observe/core/effect.js +34 -37
  11. package/dist/observe/core/graph.js +8 -8
  12. package/dist/observe/core/heap.js +5 -5
  13. package/dist/observe/core/lanes.js +104 -84
  14. package/dist/observe/core/owner.js +17 -16
  15. package/dist/observe/core/scheduler.js +61 -47
  16. package/dist/observe/core/truth.js +6 -6
  17. package/dist/observe/core/verdict.js +15 -15
  18. package/dist/observe/deferred.js +40 -38
  19. package/dist/observe/from.js +248 -0
  20. package/dist/observe/index.js +4 -2
  21. package/dist/observe/map.js +22 -22
  22. package/dist/observe/reveal.js +5 -5
  23. package/dist/observe/signals.js +57 -15
  24. package/dist/observe/store/affects.js +1 -1
  25. package/dist/observe/store/hooks.js +3 -0
  26. package/dist/observe/store/optimistic.js +11 -11
  27. package/dist/observe/store/projection.js +34 -21
  28. package/dist/observe/store/reconcile.js +138 -122
  29. package/dist/observe/store/store.js +628 -641
  30. package/dist/observe/store/target.js +1 -5
  31. package/dist/observe/store/utils.js +7 -2
  32. package/dist/prod/boundaries.js +153 -132
  33. package/dist/prod/core/action.js +8 -0
  34. package/dist/prod/core/async.js +242 -197
  35. package/dist/prod/core/constants.js +16 -1
  36. package/dist/prod/core/core.js +166 -138
  37. package/dist/prod/core/effect.js +31 -34
  38. package/dist/prod/core/graph.js +5 -5
  39. package/dist/prod/core/heap.js +12 -12
  40. package/dist/prod/core/lanes.js +98 -78
  41. package/dist/prod/core/owner.js +15 -14
  42. package/dist/prod/core/scheduler.js +64 -50
  43. package/dist/prod/core/truth.js +6 -6
  44. package/dist/prod/core/verdict.js +17 -17
  45. package/dist/prod/deferred.js +40 -38
  46. package/dist/prod/from.js +248 -0
  47. package/dist/prod/index.js +4 -2
  48. package/dist/prod/map.js +14 -14
  49. package/dist/prod/reveal.js +8 -8
  50. package/dist/prod/signals.js +46 -4
  51. package/dist/prod/store/affects.js +1 -1
  52. package/dist/prod/store/hooks.js +3 -0
  53. package/dist/prod/store/optimistic.js +16 -16
  54. package/dist/prod/store/projection.js +22 -9
  55. package/dist/prod/store/reconcile.js +138 -122
  56. package/dist/prod/store/store.js +308 -331
  57. package/dist/prod/store/target.js +13 -17
  58. package/dist/prod/store/utils.js +2 -0
  59. package/dist/types/core/action.d.ts +8 -0
  60. package/dist/types/core/async.d.ts +12 -2
  61. package/dist/types/core/constants.d.ts +25 -0
  62. package/dist/types/core/core.d.ts +33 -4
  63. package/dist/types/core/dev.d.ts +1 -1
  64. package/dist/types/core/index.d.ts +1 -1
  65. package/dist/types/core/lanes.d.ts +5 -1
  66. package/dist/types/core/scheduler.d.ts +17 -3
  67. package/dist/types/from.d.ts +47 -0
  68. package/dist/types/index.d.ts +4 -1
  69. package/dist/types/signals.d.ts +37 -0
  70. package/dist/types/store/target.d.ts +2 -0
  71. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import { setAttributionHooks } from "./attribution-hooks.js";
2
2
 
3
- import { NOT_PENDING, CONFIG_PLUMBING, CONFIG_OVERRIDE, CONFIG_GUESS, CONFIG_VERDICT } from "./constants.js";
3
+ import { NOT_PENDING, CONFIG_PLUMBING, CONFIG_KEY_BAG, CONFIG_OVERRIDE, CONFIG_GUESS, CONFIG_VERDICT } from "./constants.js";
4
4
 
5
5
  import { OBSERVE, liveRootOwners, emitDiagnostic, ownerPath, reportDiagnostic, isSuppressed, anyExcluded, isExcluded, GRAPH_SIZE_WARN_AT, noteFanOut } from "./dev.js";
6
6
 
@@ -670,14 +670,14 @@ const HOT_FANOUT_FIRST_MILESTONE = 5;
670
670
  const s = now();
671
671
  if (i.be === undefined || s - i.be > o.windowMs) {
672
672
  i.be = s;
673
- i.Oe = 0;
674
- i.Fe = false;
673
+ i._e = 0;
674
+ i.Oe = false;
675
675
  }
676
- i.Oe = (i.Oe ?? 0) + n;
677
- if (i.Fe || i.Oe < o.budgetMs) return;
678
- i.Fe = true;
676
+ i._e = (i._e ?? 0) + n;
677
+ if (i.Oe || i._e < o.budgetMs) return;
678
+ i.Oe = true;
679
679
  const r = t.map(e => `"${e.name}" (${e.kind})`).join(", ");
680
- const a = `[HOT_SCOPE_TIME] ${nodeKind(e)} "${nodeName(e)}" spent ` + `${i.Oe.toFixed(1)}ms of compute inside one ${o.windowMs}ms window ` + `(budget ${o.budgetMs}ms). Latest cause: ${r || "(untracked pull)"}`;
680
+ const a = `[HOT_SCOPE_TIME] ${nodeKind(e)} "${nodeName(e)}" spent ` + `${i._e.toFixed(1)}ms of compute inside one ${o.windowMs}ms window ` + `(budget ${o.budgetMs}ms). Latest cause: ${r || "(untracked pull)"}`;
681
681
  reportDiagnostic(emitDiagnostic({
682
682
  code: "HOT_SCOPE_TIME",
683
683
  kind: "perf",
@@ -685,7 +685,7 @@ const HOT_FANOUT_FIRST_MILESTONE = 5;
685
685
  message: a,
686
686
  nodeName: nodeName(e),
687
687
  data: {
688
- spentMs: i.Oe,
688
+ spentMs: i._e,
689
689
  budgetMs: o.budgetMs,
690
690
  windowMs: o.windowMs,
691
691
  causes: t.map(e => e.name)
@@ -710,8 +710,8 @@ const HOT_FANOUT_FIRST_MILESTONE = 5;
710
710
  // This runs on every re-run: fields on the node (one property read each,
711
711
  // like hotRuns) and the run's own `at` — no clock read, no map lookup.
712
712
  const a = e;
713
- if (a._e === undefined || n - a._e > r.windowMs) {
714
- a._e = n;
713
+ if (a.Fe === undefined || n - a.Fe > r.windowMs) {
714
+ a.Fe = n;
715
715
  a.Ae = 0;
716
716
  a.Re = 0;
717
717
  a.Le = 0;
@@ -907,6 +907,8 @@ function shallowEquivalent(e, n) {
907
907
  // typeof guard: an explicit `unstableMemos: undefined` in enable() options
908
908
  // clobbers the default through the spread — treat any non-number as off.
909
909
  if (typeof o !== "number") return;
910
+ // merge()'s function-source memo: a key bag no user configures (#4256).
911
+ if (e.l & CONFIG_KEY_BAG) return;
910
912
  const i = e;
911
913
  if (n === t || // paranoia: changed runs should never hit this
912
914
  !isPlainShape(n) || !isPlainShape(t) || !shallowEquivalent(n, t)) {
@@ -1069,7 +1071,7 @@ const copyReported = new WeakSet;
1069
1071
  // An apply half that takes no argument cannot be copying its compute
1070
1072
  // output: a match is coincidence (`createEffect(open, () =>
1071
1073
  // setFlipped(measure()))`).
1072
- if (s !== undefined && t !== undefined && t === s.node.Ie && (s.node.Ge?.length ?? 1)) {
1074
+ if (s !== undefined && t !== undefined && t === s.node.le && (s.node.Ge?.length ?? 1)) {
1073
1075
  copyWrites.add(n);
1074
1076
  o.Ue = o.qe === r ? (o.Ue ?? 0) + 1 : 1;
1075
1077
  o.qe = r;
@@ -1078,7 +1080,7 @@ const copyReported = new WeakSet;
1078
1080
  }
1079
1081
 
1080
1082
  /** The effect's source whose current value the compute output is, if any (the prop-to-state port). */ function passthroughSource(e) {
1081
- for (let n = e.C; n !== null; n = n.G) if (n.S.Ie === e.Ie) return nodeName(n.S);
1083
+ for (let n = e.C; n !== null; n = n.G) if (n.S.le === e.le) return nodeName(n.S);
1082
1084
  return undefined;
1083
1085
  }
1084
1086
 
@@ -1452,8 +1454,8 @@ function checkWaterfall(e, n, t) {
1452
1454
  }
1453
1455
  if (i < 2) return;
1454
1456
  const r = e;
1455
- if ((r.xe ?? 0) >= i) return;
1456
- r.xe = i;
1457
+ if ((r.Ke ?? 0) >= i) return;
1458
+ r.Ke = i;
1457
1459
  const a = [ ...n.slice(n.length - (i - 1)), {
1458
1460
  name: nodeName(e),
1459
1461
  ms: t
@@ -1516,7 +1518,7 @@ function acknowledge(e, n, t, o) {
1516
1518
  const t = {
1517
1519
  left: HOLD_CENSUS_CAP
1518
1520
  };
1519
- const o = GlobalQueue.Ke?.(e);
1521
+ const o = GlobalQueue.xe?.(e);
1520
1522
  if (o !== undefined) for (const e of o) acknowledge(n, "optimistic", nodeName(e), reachesEffect(e, t));
1521
1523
  if (e.I !== null) for (const o of e.I) acknowledge(n, "affects", nodeName(o), reachesEffect(o, t));
1522
1524
  }
@@ -1632,7 +1634,7 @@ function trackHoldSettled(e) {
1632
1634
  let i;
1633
1635
  let s;
1634
1636
  let r = -Infinity;
1635
- for (const n of e.je) {
1637
+ for (const n of e.Ye) {
1636
1638
  if (typeof n.X === "function" || isCompanion(n)) continue;
1637
1639
  const e = n.ge;
1638
1640
  if (e === undefined || e.kind !== "write") continue;
@@ -1661,7 +1663,7 @@ function trackHoldSettled(e) {
1661
1663
  return;
1662
1664
  }
1663
1665
  censusRegistrations(e, n);
1664
- censusCompanions([ ...e.je, ...n.blockers ], n);
1666
+ censusCompanions([ ...e.Ye, ...n.blockers ], n);
1665
1667
  const a = now();
1666
1668
  // The hold began no later than its first parked flush; an interaction stamp
1667
1669
  // reaches further back (dispatch). A node rewritten mid-hold keeps only its
@@ -1822,7 +1824,7 @@ function checkLongHold(e, n) {
1822
1824
  if (!options.optimisticReverts || isCompanion(e)) return;
1823
1825
  // Method call, as every commit path does: store slot nodes share one
1824
1826
  // comparator that reads `this._host` (#3687).
1825
- const i = e.Ye;
1827
+ const i = e.je;
1826
1828
  if (i && i.call(e, n, t)) return;
1827
1829
  const s = nodeName(e);
1828
1830
  // The two values are user data: quoted only under `values: "full"`; the
@@ -2283,7 +2285,7 @@ function closeNavigation(e) {
2283
2285
 
2284
2286
  /** holdStart: `t`'s staged writes are parked — their navigations settle with `t`. */ function markNavigationsHeld(e) {
2285
2287
  if (openNavs.size === 0) return;
2286
- for (const n of e.je) {
2288
+ for (const n of e.Ye) {
2287
2289
  const e = n.ge?.origin;
2288
2290
  if (e?.kind !== "navigation") continue;
2289
2291
  const t = navStates.get(e);
@@ -2293,7 +2295,7 @@ function closeNavigation(e) {
2293
2295
 
2294
2296
  /** transitionSettled: `t` commits — the navigations whose writes it staged are done. */ function settleNavigations(e, n) {
2295
2297
  if (openNavs.size === 0) return;
2296
- for (const t of e.je) {
2298
+ for (const t of e.Ye) {
2297
2299
  const e = t.ge?.origin;
2298
2300
  if (e?.kind !== "navigation") continue;
2299
2301
  const o = navStates.get(e);
@@ -2615,7 +2617,7 @@ function openInteraction(e, n, t) {
2615
2617
 
2616
2618
  /** holdStart: `t` parked writes — the interactions that performed them wait for `t`. */ function markInteractionsHeld(e) {
2617
2619
  if (openInteractions.size === 0) return;
2618
- for (const n of e.je) {
2620
+ for (const n of e.Ye) {
2619
2621
  const t = openInteractionOf(n.ge?.origin);
2620
2622
  if (t !== undefined) {
2621
2623
  t.heldIn.add(e);
@@ -2703,7 +2705,7 @@ const engineHooks = {
2703
2705
  prevDeps: n || !wantsRerun() ? null : captureDeps(e),
2704
2706
  // Mirror recompute's own prev-value resolution: an earlier run in the
2705
2707
  // same flush may still be holding in _pendingValue.
2706
- prevValue: e.ue !== NOT_PENDING ? e.ue : e.Ie,
2708
+ prevValue: e.ie !== NOT_PENDING ? e.ie : e.le,
2707
2709
  // A create run inherits the interaction of whatever is building it: the
2708
2710
  // enclosing recompute (a parent's fn creating children) or, at the top
2709
2711
  // of the recompute stack, the effect callback / handler frame.
@@ -2730,7 +2732,7 @@ const engineHooks = {
2730
2732
  // exempt — a side-effect-only compute's work IS its effect phase, and
2731
2733
  // identity of `undefined` proves nothing.
2732
2734
  if (t && r.causes !== null && e.i) {
2733
- const n = e.ue !== NOT_PENDING ? e.ue : e.Ie;
2735
+ const n = e.ie !== NOT_PENDING ? e.ie : e.le;
2734
2736
  if (n !== undefined && n === r.prevValue) t = false;
2735
2737
  }
2736
2738
  // Unstable-output check: memos only, non-create, plain runs with a
@@ -2738,12 +2740,12 @@ const engineHooks = {
2738
2740
  // plain-flush memo commits and in `_value` for direct ones. Overlay runs
2739
2741
  // are excluded — an optimistic re-derive legitimately produces fresh
2740
2742
  // equivalents while the lane settles.
2741
- if (r.causes !== null && t && !o && !i && !e.i) checkUnstableOutput(e, r.prevValue, e.ue !== NOT_PENDING ? e.ue : e.Ie);
2743
+ if (r.causes !== null && t && !o && !i && !e.i) checkUnstableOutput(e, r.prevValue, e.ie !== NOT_PENDING ? e.ie : e.le);
2742
2744
  // The same exemption for memos: a run that committed `undefined` did its
2743
2745
  // work as a side effect (a projection's draft writes or reconcile, a
2744
2746
  // write from inside a memo), so core's `undefined === undefined` gate
2745
2747
  // proves nothing. Reported as changed, so no consumer counts it as waste.
2746
- if (!t && (e.ue !== NOT_PENDING ? e.ue : e.Ie) === undefined) t = true;
2748
+ if (!t && (e.ie !== NOT_PENDING ? e.ie : e.le) === undefined) t = true;
2747
2749
  if (r.causes !== null) recordRerun(e, r, {
2748
2750
  selfMs: c,
2749
2751
  totalMs: a
@@ -2786,8 +2788,8 @@ const engineHooks = {
2786
2788
  },
2787
2789
  asyncStart(e) {
2788
2790
  asyncStartSeq = e.ge?.seq ?? 0;
2789
- asyncStartTime = e.ie;
2790
- asyncStartValue = e.Ie;
2791
+ asyncStartTime = e.ae;
2792
+ asyncStartValue = e.le;
2791
2793
  },
2792
2794
  asyncEnd(e, n, t, o) {
2793
2795
  if (o) {
@@ -2797,7 +2799,7 @@ const engineHooks = {
2797
2799
  // (or `_time`, for a same-reference commit under `equals: false`), and
2798
2800
  // a transition hold parks the value in `_pendingValue`. A landing the
2799
2801
  // equality gate swallowed moves none of them and must leave no stamp.
2800
- const o = e.Ie !== asyncStartValue || e.ie !== asyncStartTime || e.ue === t;
2802
+ const o = e.le !== asyncStartValue || e.ae !== asyncStartTime || e.ie === t;
2801
2803
  if (o) stampWrite(e, "async", n === undefined ? NO_VALUES : n, t);
2802
2804
  // Flight over either way — an equality-swallowed landing still spent
2803
2805
  // the wall time (finalizeFlight only chains through a fresh stamp).
@@ -203,6 +203,22 @@ const CONFIG_HAS_SNAPSHOT = 1 << 9;
203
203
  * owns stay fully observed.
204
204
  * Set from the internal `_plumbing` option at creation; never set in prod. */ const CONFIG_PLUMBING = 1 << 25;
205
205
 
206
+ /** Observe tiers only: the memo `merge()` creates for a function source — a
207
+ * key bag readers consume key by key, built by the framework (a compiled
208
+ * component spread) with options no user can reach. The attribution engine's
209
+ * UNSTABLE_MEMO_OUTPUT skips it: a fresh-but-equal bag is the idiom
210
+ * (`{...(on() ? { a } : {})}`), and the advice (`equals`) cannot be applied
211
+ * (#4256). Set through `_extraConfig` by observe builds only. */ const CONFIG_KEY_BAG = 1 << 28;
212
+
213
+ /** The frame (rule 3, D-3): a render effect (set at creation, as
214
+ * `EFFECT_RENDER << 23` — keep the two in step), and a boundary's tree and
215
+ * output (boundaries.ts) — structure between the content and the render
216
+ * effect that shows it, not a user derivation of the content. Outside a
217
+ * hold's own flush it reads that hold's values as committed and is
218
+ * re-derived at its landing, and a re-pass of it publishes mainline: it
219
+ * joins nothing, so two mounts under one boundary made in separate flushes
220
+ * keep their holds apart (D-4, S-5 rows 1′–3′, #4283). */ const CONFIG_FRAME = 1 << 23;
221
+
206
222
  const STATUS_NONE = 0;
207
223
 
208
224
  const STATUS_PENDING = 1 << 0;
@@ -211,6 +227,10 @@ const STATUS_ERROR = 1 << 1;
211
227
 
212
228
  const STATUS_UNINITIALIZED = 1 << 2;
213
229
 
230
+ /** An error that answered a node's first read (no value has ever landed):
231
+ * the error, not UNINITIALIZED, is its status while shown, but a re-ask
232
+ * makes it uninitialized-pending again — it still has no value (#4244). */ const STATUS_NO_VALUE = 1 << 3;
233
+
214
234
  /** `catchHook`'s answer when the catcher is a boundary re-armed by
215
235
  * `on` (truthy, as any catch): what it collects is its own, not the hold's. */ const CAUGHT_REARMED = 2;
216
236
 
@@ -236,4 +256,6 @@ const defaultContext = {};
236
256
  * @internal
237
257
  */ const $REFRESH = Symbol("refresh");
238
258
 
239
- export { $REFRESH, CAUGHT_REARMED, CONFIG_AUTHORITATIVE, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRESH_READ, CONFIG_GUESS, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, CONFIG_HELD_FRAME, CONFIG_INPUTS_PUBLISHED, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_LAGS, CONFIG_MANUAL_WRITE, CONFIG_NO_SNAPSHOT, CONFIG_OVERRIDE, CONFIG_OWNED_WRITE, CONFIG_PLUMBING, CONFIG_PROMOTED, CONFIG_REDERIVE, CONFIG_SLOT_NODE, CONFIG_STAGED, CONFIG_STAGED_ERROR, CONFIG_SYNC, CONFIG_TRANSPARENT, CONFIG_VERDICT, EFFECT_RENDER, EFFECT_TRACKED, EFFECT_USER, NOT_PENDING, NO_SNAPSHOT, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_DISPOSED, REACTIVE_FRAME_READ, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_JOINED, REACTIVE_LANE_DIRTY, REACTIVE_LANE_READ, REACTIVE_LAZY, REACTIVE_MANUAL_WRITE, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_PROBED, REACTIVE_PROBE_UNANSWERED, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, REACTIVE_SCREEN_READ, REACTIVE_SNAPSHOT_STALE, REACTIVE_STAGED_READ, REACTIVE_ZOMBIE, STATUS_ERROR, STATUS_NONE, STATUS_PENDING, STATUS_UNINITIALIZED, SUPPORTS_PROXY, defaultContext };
259
+ const NewSet = Set;
260
+
261
+ export { $REFRESH, CAUGHT_REARMED, CONFIG_AUTHORITATIVE, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRAME, CONFIG_FRESH_READ, CONFIG_GUESS, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, CONFIG_HELD_FRAME, CONFIG_INPUTS_PUBLISHED, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_KEY_BAG, CONFIG_LAGS, CONFIG_MANUAL_WRITE, CONFIG_NO_SNAPSHOT, CONFIG_OVERRIDE, CONFIG_OWNED_WRITE, CONFIG_PLUMBING, CONFIG_PROMOTED, CONFIG_REDERIVE, CONFIG_SLOT_NODE, CONFIG_STAGED, CONFIG_STAGED_ERROR, CONFIG_SYNC, CONFIG_TRANSPARENT, CONFIG_VERDICT, EFFECT_RENDER, EFFECT_TRACKED, EFFECT_USER, NOT_PENDING, NO_SNAPSHOT, NewSet, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_DISPOSED, REACTIVE_FRAME_READ, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_JOINED, REACTIVE_LANE_DIRTY, REACTIVE_LANE_READ, REACTIVE_LAZY, REACTIVE_MANUAL_WRITE, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_PROBED, REACTIVE_PROBE_UNANSWERED, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, REACTIVE_SCREEN_READ, REACTIVE_SNAPSHOT_STALE, REACTIVE_STAGED_READ, REACTIVE_ZOMBIE, STATUS_ERROR, STATUS_NONE, STATUS_NO_VALUE, STATUS_PENDING, STATUS_UNINITIALIZED, SUPPORTS_PROXY, defaultContext };