@solidjs/signals 2.0.0-rc.14 → 2.0.0-rc.16

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 (98) hide show
  1. package/dist/dev-shared.js +882 -405
  2. package/dist/dev.attribution.js +172 -66
  3. package/dist/dev.js +1529 -745
  4. package/dist/observe/affects-marks.js +86 -0
  5. package/dist/observe/affects.js +32 -80
  6. package/dist/observe/boundaries.js +202 -166
  7. package/dist/observe/core/async.js +192 -141
  8. package/dist/observe/core/attribution-queries.js +1 -1
  9. package/dist/observe/core/attribution.js +315 -214
  10. package/dist/observe/core/constants.js +23 -4
  11. package/dist/observe/core/context.js +3 -3
  12. package/dist/observe/core/core.js +532 -360
  13. package/dist/observe/core/dev.js +63 -35
  14. package/dist/observe/core/effect.js +47 -47
  15. package/dist/observe/core/error.js +5 -3
  16. package/dist/observe/core/external.js +5 -6
  17. package/dist/observe/core/graph.js +56 -42
  18. package/dist/observe/core/heap.js +33 -33
  19. package/dist/observe/core/identities.js +62 -0
  20. package/dist/observe/core/lanes.js +242 -229
  21. package/dist/observe/core/owner.js +62 -50
  22. package/dist/observe/core/scheduler.js +322 -168
  23. package/dist/observe/core/truth.js +45 -0
  24. package/dist/observe/core/verdict.js +114 -64
  25. package/dist/observe/deferred.js +184 -0
  26. package/dist/observe/index.js +7 -1
  27. package/dist/observe/map.js +339 -254
  28. package/dist/observe/reveal.js +77 -77
  29. package/dist/observe/signals.js +54 -33
  30. package/dist/observe/store/affects.js +76 -69
  31. package/dist/observe/store/edges.js +39 -0
  32. package/dist/observe/store/hooks.js +13 -0
  33. package/dist/observe/store/index.js +0 -2
  34. package/dist/observe/store/optimistic.js +82 -44
  35. package/dist/observe/store/projection.js +83 -64
  36. package/dist/observe/store/reconcile.js +32 -30
  37. package/dist/observe/store/store.js +219 -123
  38. package/dist/prod/affects-marks.js +86 -0
  39. package/dist/prod/affects.js +33 -79
  40. package/dist/prod/boundaries.js +185 -149
  41. package/dist/prod/core/async.js +176 -135
  42. package/dist/prod/core/constants.js +23 -4
  43. package/dist/prod/core/context.js +3 -3
  44. package/dist/prod/core/core.js +521 -353
  45. package/dist/prod/core/effect.js +66 -66
  46. package/dist/prod/core/error.js +5 -3
  47. package/dist/prod/core/external.js +5 -6
  48. package/dist/prod/core/graph.js +56 -42
  49. package/dist/prod/core/heap.js +38 -38
  50. package/dist/prod/core/identities.js +62 -0
  51. package/dist/prod/core/lanes.js +237 -224
  52. package/dist/prod/core/owner.js +62 -51
  53. package/dist/prod/core/scheduler.js +312 -158
  54. package/dist/prod/core/truth.js +45 -0
  55. package/dist/prod/core/verdict.js +113 -63
  56. package/dist/prod/deferred.js +182 -0
  57. package/dist/prod/index.js +7 -1
  58. package/dist/prod/map.js +366 -281
  59. package/dist/prod/reveal.js +77 -77
  60. package/dist/prod/signals.js +59 -38
  61. package/dist/prod/store/affects.js +76 -69
  62. package/dist/prod/store/edges.js +39 -0
  63. package/dist/prod/store/hooks.js +13 -0
  64. package/dist/prod/store/index.js +0 -2
  65. package/dist/prod/store/optimistic.js +121 -84
  66. package/dist/prod/store/projection.js +46 -34
  67. package/dist/prod/store/reconcile.js +32 -30
  68. package/dist/prod/store/store.js +205 -116
  69. package/dist/types/affects-marks.d.ts +14 -0
  70. package/dist/types/boundaries.d.ts +5 -1
  71. package/dist/types/core/async.d.ts +10 -0
  72. package/dist/types/core/attribution.d.ts +6 -2
  73. package/dist/types/core/constants.d.ts +18 -1
  74. package/dist/types/core/core.d.ts +77 -5
  75. package/dist/types/core/dev.d.ts +43 -13
  76. package/dist/types/core/graph.d.ts +11 -0
  77. package/dist/types/core/identities.d.ts +17 -0
  78. package/dist/types/core/index.d.ts +2 -1
  79. package/dist/types/core/lanes.d.ts +2 -4
  80. package/dist/types/core/owner.d.ts +5 -3
  81. package/dist/types/core/scheduler.d.ts +59 -34
  82. package/dist/types/core/truth.d.ts +16 -0
  83. package/dist/types/core/types.d.ts +21 -6
  84. package/dist/types/core/verdict.d.ts +32 -0
  85. package/dist/types/deferred.d.ts +28 -0
  86. package/dist/types/index.d.ts +6 -0
  87. package/dist/types/map.d.ts +2 -2
  88. package/dist/types/signals.d.ts +28 -7
  89. package/dist/types/store/affects.d.ts +11 -0
  90. package/dist/types/store/edges.d.ts +9 -0
  91. package/dist/types/store/hooks.d.ts +48 -0
  92. package/dist/types/store/index.d.ts +10 -4
  93. package/dist/types/store/optimistic.d.ts +3 -2
  94. package/dist/types/store/projection.d.ts +4 -3
  95. package/dist/types/store/store.d.ts +4 -39
  96. package/dist/types/store/target.d.ts +16 -8
  97. package/dist/types/store/types.d.ts +14 -0
  98. package/package.json +1 -1
@@ -32,124 +32,124 @@ const SEQUENTIAL_ACCESSOR = () => "sequential";
32
32
 
33
33
  const isController = t => t instanceof RevealController;
34
34
 
35
- const slotReady = t => isController(t) ? t.rs() : ready(t);
35
+ const slotReady = t => isController(t) ? t.Lt() : ready(t);
36
36
 
37
- const slotMinReady = t => isController(t) ? t.ns() : ready(t);
37
+ const slotMinReady = t => isController(t) ? t.Qt() : ready(t);
38
38
 
39
39
  /** Force a slot's state. A boundary re-derives its output when it changes;
40
40
  * a nested controller passes the state on to its own slots. Released
41
41
  * (`!gated`), a nested controller leaves its parent's ownership and runs its
42
42
  * own order; a boundary leaves when it has shown content (boundaries.ts). */ function setSlotState(t, e, s, r) {
43
43
  if (isController(t)) {
44
- t.te = s;
45
- t.oe = r;
46
- t.ls();
44
+ t.$ = s;
45
+ t.ee = r;
46
+ t.Bt();
47
47
  // Released and ready — every slot of its own has shown — it graduates,
48
48
  // as a boundary does when it shows content. Released at the frontier
49
49
  // but not ready, it stays the parent's frontier.
50
- if (!s && t.us && t._parent === e) t._parent = null;
50
+ if (!s && t.Jt && t._parent === e) t._parent = null;
51
51
  return;
52
52
  }
53
- if (t.te !== s || t.oe !== r) {
54
- t.te = s;
55
- t.oe = r;
53
+ if (t.$ !== s || t.ee !== r) {
54
+ t.$ = s;
55
+ t.ee = r;
56
56
  redraw(t);
57
57
  }
58
58
  }
59
59
 
60
60
  class RevealController {
61
- hs;
62
- cs;
63
- fs=[];
61
+ Xt;
62
+ Yt;
63
+ Zt=[];
64
64
  /** The controller gating this one, until it releases this one. */
65
65
  _parent=null;
66
66
  /** The state a parent forces on this whole group. */
67
- te=false;
68
- oe=false;
69
- us=true;
70
- ds=true;
71
- Ss=false;
67
+ $=false;
68
+ ee=false;
69
+ Jt=true;
70
+ ts=true;
71
+ es=false;
72
72
  constructor(t, e) {
73
- this.hs = t;
74
- this.cs = e;
73
+ this.Xt = t;
74
+ this.Yt = e;
75
75
  }
76
76
  /** A slot that has left this controller's ownership: a boundary that has
77
77
  * shown content, a nested group that is ready. Shown is shown — it counts
78
- * as ready whatever happens to it later (a re-arm gates nobody else). */ Rs(t) {
79
- return (isController(t) ? t._parent : t.B) !== this;
78
+ * as ready whatever happens to it later (a re-arm gates nobody else). */ ss(t) {
79
+ return (isController(t) ? t._parent : t.v) !== this;
80
80
  }
81
81
  /** The slots this controller still owns, in registration order — the
82
- * ones the order's state is forced on. */ _s(t) {
83
- for (let e = 0; e < this.fs.length; e++) {
84
- const s = this.fs[e];
85
- if (!this.Rs(s) && t(s) === false) return false;
82
+ * ones the order's state is forced on. */ rs(t) {
83
+ for (let e = 0; e < this.Zt.length; e++) {
84
+ const s = this.Zt[e];
85
+ if (!this.ss(s) && t(s) === false) return false;
86
86
  }
87
87
  return true;
88
88
  }
89
- /** Readiness is judged over every slot, done ones as ready. */ rs() {
90
- for (let t = 0; t < this.fs.length; t++) {
91
- const e = this.fs[t];
92
- if (!this.Rs(e) && !slotReady(e)) return false;
89
+ /** Readiness is judged over every slot, done ones as ready. */ Lt() {
90
+ for (let t = 0; t < this.Zt.length; t++) {
91
+ const e = this.Zt[t];
92
+ if (!this.ss(e) && !slotReady(e)) return false;
93
93
  }
94
94
  return true;
95
95
  }
96
96
  /** Something visible to show under its own order — what an enclosing
97
97
  * `together` waits for: `together` — every slot minimally ready;
98
- * `sequential` — the first slot; `natural` — any. */ ns() {
99
- const t = untrack(this.hs);
100
- const e = this.fs;
98
+ * `sequential` — the first slot; `natural` — any. */ Qt() {
99
+ const t = untrack(this.Xt);
100
+ const e = this.Zt;
101
101
  if (e.length === 0) return true;
102
- if (t === "sequential") return this.Rs(e[0]) || slotMinReady(e[0]);
102
+ if (t === "sequential") return this.ss(e[0]) || slotMinReady(e[0]);
103
103
  for (let s = 0; s < e.length; s++) {
104
- const r = this.Rs(e[s]) || slotMinReady(e[s]);
104
+ const r = this.ss(e[s]) || slotMinReady(e[s]);
105
105
  if (t === "natural" ? r : !r) return t === "natural";
106
106
  }
107
107
  return t !== "natural";
108
108
  }
109
- ae(t) {
110
- if (this.fs.includes(t)) return;
111
- this.fs.push(t);
109
+ oe(t) {
110
+ if (this.Zt.includes(t)) return;
111
+ this.Zt.push(t);
112
112
  // Gated from the start (collapsed in a collapsed sequential tail); the
113
113
  // evaluation releases what the order allows.
114
- const e = untrack(this.hs) === "sequential" && !!untrack(this.cs);
114
+ const e = untrack(this.Xt) === "sequential" && !!untrack(this.Yt);
115
115
  if (isController(t)) {
116
116
  t._parent = this;
117
- t.te = true;
118
- t.oe = e;
119
- t.ls();
117
+ t.$ = true;
118
+ t.ee = e;
119
+ t.Bt();
120
120
  } else {
121
- t.B = this;
122
- t.te = true;
123
- t.oe = e;
121
+ t.v = this;
122
+ t.$ = true;
123
+ t.ee = e;
124
124
  }
125
- untrack(() => this.ls());
125
+ untrack(() => this.Bt());
126
126
  }
127
- ue(t) {
128
- const e = this.fs.indexOf(t);
129
- if (e >= 0) this.fs.splice(e, 1);
130
- untrack(() => this.ls());
127
+ te(t) {
128
+ const e = this.Zt.indexOf(t);
129
+ if (e >= 0) this.Zt.splice(e, 1);
130
+ untrack(() => this.Bt());
131
131
  }
132
132
  /** Apply the order to the owned slots — or, gated by a parent, its state
133
- * to all of them. */ ls() {
134
- if (this.Ss) return;
135
- this.Ss = true;
136
- const t = this.us;
137
- const e = this.ds;
133
+ * to all of them. */ Bt() {
134
+ if (this.es) return;
135
+ this.es = true;
136
+ const t = this.Jt;
137
+ const e = this.ts;
138
138
  try {
139
- const t = untrack(this.hs);
140
- const e = t === "sequential" && !!untrack(this.cs);
141
- if (this.te) {
142
- this._s(t => setSlotState(t, this, true, this.oe));
139
+ const t = untrack(this.Xt);
140
+ const e = t === "sequential" && !!untrack(this.Yt);
141
+ if (this.$) {
142
+ this.rs(t => setSlotState(t, this, true, this.ee));
143
143
  } else if (t === "natural") {
144
- this._s(t => {
144
+ this.rs(t => {
145
145
  if (isController(t)) setSlotState(t, this, false, false); else setSlotState(t, this, !ready(t), false);
146
146
  });
147
147
  } else if (t === "together") {
148
- const t = this._s(slotMinReady);
149
- this._s(e => setSlotState(e, this, !t, false));
148
+ const t = this.rs(slotMinReady);
149
+ this.rs(e => setSlotState(e, this, !t, false));
150
150
  } else {
151
151
  let t = false;
152
- this._s(s => {
152
+ this.rs(s => {
153
153
  if (t) return setSlotState(s, this, true, e);
154
154
  if (slotReady(s)) return setSlotState(s, this, false, false);
155
155
  t = true;
@@ -159,11 +159,11 @@ class RevealController {
159
159
  });
160
160
  }
161
161
  } finally {
162
- this.us = this.rs();
163
- this.ds = this.ns();
164
- this.Ss = false;
162
+ this.Jt = this.Lt();
163
+ this.ts = this.Qt();
164
+ this.es = false;
165
165
  }
166
- if (this._parent !== null && (t !== this.us || e !== this.ds)) this._parent.ls();
166
+ if (this._parent !== null && (t !== this.Jt || e !== this.ts)) this._parent.Bt();
167
167
  }
168
168
  }
169
169
 
@@ -179,23 +179,23 @@ class RevealController {
179
179
  * slots behind the frontier render nothing instead of their fallbacks
180
180
  */ function createRevealOrder(t, e) {
181
181
  const s = createOwner();
182
- const r = s.U[REVEAL];
182
+ const r = s.A[REVEAL];
183
183
  const i = new RevealController(e?.order || SEQUENTIAL_ACCESSOR, e?.collapsed || FALSE_ACCESSOR);
184
- s.U = {
185
- ...s.U,
184
+ s.A = {
185
+ ...s.A,
186
186
  [REVEAL]: i
187
187
  };
188
188
  return runWithOwner(s, () => {
189
189
  const e = t();
190
190
  const s = computed(() => {
191
- i.hs();
192
- i.cs();
193
- i.ls();
191
+ i.Xt();
192
+ i.Yt();
193
+ i.Bt();
194
194
  });
195
195
  if (true) s._name = "reveal order";
196
196
  if (r) {
197
- r.ae(i);
198
- cleanup(() => r.ue(i));
197
+ r.oe(i);
198
+ cleanup(() => r.te(i));
199
199
  }
200
200
  return e;
201
201
  });
@@ -204,9 +204,9 @@ class RevealController {
204
204
  // Installed at module evaluation — present exactly when something imports
205
205
  // `createRevealOrder`; a Loading boundary without one pays a null check.
206
206
  setRevealHooks({
207
- ae: (t, e) => t.ae(e),
208
- ue: (t, e) => t.ue(e),
209
- j: t => t.ls()
207
+ oe: (t, e) => t.oe(e),
208
+ te: (t, e) => t.te(e),
209
+ P: t => t.Bt()
210
210
  });
211
211
 
212
212
  export { createRevealOrder };
@@ -1,21 +1,25 @@
1
- import { NotReadyError, unwrapStatusError, TimeoutError } from "./core/error.js";
1
+ import { TimeoutError, NotReadyError, unwrapStatusError } from "./core/error.js";
2
2
 
3
3
  import "./core/verdict.js";
4
4
 
5
- import { CONFIG_CHILDREN_FORBIDDEN, EFFECT_USER, $REFRESH, CONFIG_REDERIVE, REACTIVE_JOINED, CONFIG_AUTO_DISPOSE, CONFIG_FRESH_READ, CONFIG_AUTHORITATIVE } from "./core/constants.js";
5
+ import { CONFIG_CHILDREN_FORBIDDEN, EFFECT_USER, $REFRESH, CONFIG_AUTO_DISPOSE, CONFIG_AUTHORITATIVE, CONFIG_REDERIVE, REACTIVE_JOINED, CONFIG_FRESH_READ, CONFIG_GUESS, STATUS_PENDING, STATUS_ERROR } from "./core/constants.js";
6
6
 
7
7
  import { computed, signal, runWithOwner, setMemo, setSignal, markRefresh, read, untrack } from "./core/core.js";
8
8
 
9
9
  import { registerGraph } from "./core/dev.js";
10
10
 
11
- import { globalQueue, flushTransaction, resolveTx, passTx, staleReader, dirtyQueue, joinFuture } from "./core/scheduler.js";
11
+ import { globalQueue, flushTransaction, dirtyQueue, GlobalQueue, resolveTx, passTx, staleReader, joinFuture } from "./core/scheduler.js";
12
12
 
13
13
  import { cleanup, createRoot, getOwner, dispose } from "./core/owner.js";
14
14
 
15
+ import { signalHook } from "./core/identities.js";
16
+
15
17
  import { effect, trackedEffect } from "./core/effect.js";
16
18
 
17
19
  import { optimisticWrite } from "./core/lanes.js";
18
20
 
21
+ import { truthRead, truthConfirmed } from "./core/truth.js";
22
+
19
23
  /**
20
24
  * Low-level reactive-cleanup primitive. Registers a callback that runs when
21
25
  * the surrounding owner is disposed.
@@ -73,18 +77,19 @@ function accessor(e) {
73
77
  function createSignal(e, t) {
74
78
  if (typeof e === "function") {
75
79
  const r = computed(e, t);
76
- r.u &= ~CONFIG_AUTO_DISPOSE;
80
+ r.l &= ~CONFIG_AUTO_DISPOSE;
77
81
  return [ accessor(r), setMemo.bind(null, r) ];
78
82
  }
79
83
  const r = signal(e, t);
80
84
  registerGraph(r, getOwner());
85
+ if (signalHook !== null) signalHook(r);
81
86
  return [ accessor(r), setSignal.bind(null, r) ];
82
87
  }
83
88
 
84
89
  function createOptimistic(e, t) {
85
90
  if (typeof e === "function") {
86
91
  const r = computed(e, t);
87
- r.u &= ~CONFIG_AUTO_DISPOSE;
92
+ r.l &= ~CONFIG_AUTO_DISPOSE;
88
93
  return [ accessor(r), optimisticWrite.bind(null, r) ];
89
94
  }
90
95
  const r = signal(e, t);
@@ -162,7 +167,7 @@ function createMemo(e, t) {
162
167
  * );
163
168
  * ```
164
169
  *
165
- * @description https://docs.solidjs.com/reference/basic-reactivity/create-effect
170
+ * @description https://v2.solidjs.com/reference/solid-js/reactivity/create-effect
166
171
  */ function createEffect(e, t, r) {
167
172
  effect(e, t.effect || t, t.error, {
168
173
  user: true,
@@ -197,7 +202,7 @@ function createMemo(e, t) {
197
202
  * }
198
203
  * ```
199
204
  *
200
- * @description https://docs.solidjs.com/reference/secondary-primitives/create-render-effect
205
+ * @description https://v2.solidjs.com/reference/solid-js/advanced/specialized-reactivity/create-render-effect
201
206
  */ function createRenderEffect(e, t, r) {
202
207
  effect(e, t, undefined, r);
203
208
  }
@@ -245,7 +250,7 @@ function createMemo(e, t) {
245
250
  * });
246
251
  * ```
247
252
  *
248
- * @description https://docs.solidjs.com/reference/secondary-primitives/create-tracked-effect
253
+ * @description https://v2.solidjs.com/reference/solid-js/advanced/specialized-reactivity/create-tracked-effect
249
254
  */ function createTrackedEffect(e, t) {
250
255
  trackedEffect(e, t);
251
256
  }
@@ -274,7 +279,7 @@ function createMemo(e, t) {
274
279
  * setCount(1); // logs once, reaction re-armed for next change
275
280
  * ```
276
281
  *
277
- * @description https://docs.solidjs.com/reference/secondary-primitives/create-reaction
282
+ * @description https://v2.solidjs.com/reference/solid-js/advanced/specialized-reactivity/create-reaction
278
283
  */ function createReaction(e, t) {
279
284
  let r = undefined;
280
285
  cleanup(() => r?.());
@@ -324,31 +329,41 @@ function createMemo(e, t) {
324
329
  * - a mainline reader whose pass read a frame another transaction holds
325
330
  * joined it (L2, born held — A29) and delivers at that commit: the
326
331
  * committed view, never a foreign hold's unrevealed frame. */ function watch(e, t, r, n = 0, o, c = flushTransaction) {
332
+ if (n & CONFIG_AUTHORITATIVE) {
333
+ GlobalQueue.rn = truthRead;
334
+ GlobalQueue.tn = truthConfirmed;
335
+ }
327
336
  // `config` is on the node for its first pass too (the pass runs inside
328
337
  // `computed()`): `until`'s predicate is authoritative from its first read,
329
338
  // or an already-displayed guess would satisfy it in a later slice. (REDERIVE
330
339
  // after: the first pass's own error is the promise's rejection.)
331
- computed(() => {
332
- let n;
340
+ computed(() => {
341
+ let i, u = false;
333
342
  try {
334
- n = e();
343
+ i = e();
335
344
  } catch (e) {
336
345
  if (e instanceof NotReadyError) throw e;
337
- queueMicrotask(() => r(unwrapStatusError(e)));
338
- return;
346
+ // An error is an answer (D-41): delivered by the same frame rule.
347
+ i = unwrapStatusError(e);
348
+ u = true;
339
349
  }
340
- const i = getOwner();
350
+ const s = getOwner();
351
+ // A truth reader waits out a `createDeferred` flight its value derives
352
+ // from, which serves everyone else the stale answer (D-40).
353
+ const f = n & CONFIG_AUTHORITATIVE && GlobalQueue.er?.(s);
354
+ if (f) throw new NotReadyError(f);
341
355
  // (Outside a flush a mainline pass joins through `passTx`.)
342
- const u = flushTransaction ?? passTx;
343
- if (i.R & REACTIVE_JOINED && u !== null && (c === null || resolveTx(c) !== resolveTx(u))) {
344
- staleReader(i, resolveTx(u));
356
+ const a = flushTransaction ?? passTx;
357
+ if (s.R & REACTIVE_JOINED && a !== null && (c === null || resolveTx(c) !== resolveTx(a))) {
358
+ staleReader(s, resolveTx(a));
345
359
  return;
346
360
  }
347
- o?.(n);
348
- queueMicrotask(() => t(n));
361
+ if (u) return void queueMicrotask(() => r(i));
362
+ o?.(i);
363
+ queueMicrotask(() => t(i));
349
364
  }, {
350
- dt: n
351
- }).u |= CONFIG_REDERIVE;
365
+ St: n
366
+ }).l |= CONFIG_REDERIVE;
352
367
  }
353
368
 
354
369
  /**
@@ -434,23 +449,29 @@ function createMemo(e, t) {
434
449
  const r = flushTransaction;
435
450
  const n = new Promise((n, o) => {
436
451
  queueMicrotask(() => {
437
- // No createRoot: the microtask has no ambient owner, so the watcher is
438
- // naturally detached, and settle disposes the node directly (dev keeps
439
- // a root husk purely to stay quiet about the missing owner). The
440
- // capture runs inside the watcher's own pass, where the ambient owner
441
- // IS the watcher — exactly what dispose() takes.
452
+ // The root is load-bearing: an ownerless computed is auto-disposing,
453
+ // and the settle walk releases an unobserved one instead of re-running
454
+ // it, so the waiter would never see the refetch land (#3888). Settle
455
+ // disposes the waiter directly; the capture runs inside the watcher's
456
+ // own pass, where the ambient owner IS the watcher — exactly what
457
+ // dispose() takes.
442
458
  let c = null;
443
459
  const make = () => watch(() => {
444
460
  if (c === null) c = getOwner();
445
- return read(t);
461
+ // Authoritative: the truth beneath a guess (`until`'s view). A
462
+ // guessed node's own re-ask is not answered by it (#3895): park
463
+ // on that flight, or reject with its error.
464
+ const e = read(t);
465
+ if (t.l & CONFIG_GUESS && t.m & (STATUS_PENDING | STATUS_ERROR)) throw t.T?.F;
466
+ return e;
446
467
  }, t => {
447
468
  n(typeof e === "function" ? t : e);
448
469
  dispose(c);
449
470
  }, e => {
450
471
  o(e);
451
472
  dispose(c);
452
- }, CONFIG_FRESH_READ, undefined, r);
453
- make();
473
+ }, CONFIG_FRESH_READ | CONFIG_AUTHORITATIVE, undefined, r);
474
+ createRoot(make);
454
475
  });
455
476
  });
456
477
  // Fire-and-forget refresh must not turn a failed refetch into an unhandled
@@ -519,7 +540,7 @@ function createMemo(e, t) {
519
540
  // The flip, inside the pass of the flush carrying it: the flush
520
541
  // joins the action's transaction, and what it staged is held and
521
542
  // revealed with the action.
522
- if (e && c !== null && globalQueue.ee && resolveTx(c).tt !== 0) joinFuture(c);
543
+ if (e && c !== null && globalQueue.q && resolveTx(c).tt !== 0) joinFuture(c);
523
544
  });
524
545
  if (t?.timeout !== undefined) u = setTimeout(() => settle(() => n(new TimeoutError)), t.timeout);
525
546
  if (o !== undefined) {
@@ -627,7 +648,7 @@ function createMemo(e, t) {
627
648
  * on owner disposal
628
649
  */ function onSettled(e) {
629
650
  const t = getOwner();
630
- t && !(t.u & CONFIG_CHILDREN_FORBIDDEN) ? trackedEffect(() => untrack(e), {
651
+ t && !(t.l & CONFIG_CHILDREN_FORBIDDEN) ? trackedEffect(() => untrack(e), {
631
652
  name: "onSettled"
632
653
  }) : globalQueue.enqueue(EFFECT_USER, function fire() {
633
654
  // Settled means derived. A settle that reverts optimism (or replays
@@ -637,7 +658,7 @@ function createMemo(e, t) {
637
658
  // still holding the optimistic value — reads do not pull (#3411). Fall
638
659
  // to the next pass while the heap has work; `run` swapped the queue,
639
660
  // so this lands there, and `enqueue` keeps the drain alive.
640
- if (dirtyQueue.Kt >= dirtyQueue.ut) return globalQueue.enqueue(EFFECT_USER, fire);
661
+ if (dirtyQueue.jt >= dirtyQueue.st) return globalQueue.enqueue(EFFECT_USER, fire);
641
662
  // Unowned, out-of-band fire (no owner, or a children-forbidden one this
642
663
  // one-shot must not bind to): a returned cleanup has no lifecycle to
643
664
  // attach to. Reject it in dev; in production the return is simply
@@ -1,10 +1,10 @@
1
- import { GlobalQueue } from "../core/scheduler.js";
1
+ import { GlobalQueue, releaseMarksHook } from "../core/scheduler.js";
2
2
 
3
- import { installAffectsHooks, getNode, optHooks } from "./store.js";
3
+ import { optHooks, installAffectsHooks } from "./hooks.js";
4
4
 
5
5
  import { lookupTarget, $OWNER } from "./target.js";
6
6
 
7
- import { isWrappable, $TARGET } from "./types.js";
7
+ import { $TARGET } from "./types.js";
8
8
 
9
9
  /**
10
10
  * Store — the store half of `affects()` (plan sec. 29, plan sec. 37; A24 (4), #2882,
@@ -23,113 +23,120 @@ import { isWrappable, $TARGET } from "./types.js";
23
23
  * the verdict. A mark declared on a draft (inside a setter) or over an
24
24
  * optimistic family walks the view the writer sees.
25
25
  *
26
- * Installed by `store/index.ts`: a program with stores carries it; one
27
- * without pays nothing (affects.ts asks `GlobalQueue._storeMarks`).
26
+ * Imported by `affects()`, which installs it on its first store target
27
+ * (#3891, after #3912): a program with stores that never declares a mark
28
+ * carries none of it. It never imports store.ts — the engine's top level —
29
+ * so a program declaring marks without stores carries this module alone:
30
+ * the store's nodes and its wrappability test come through `GlobalQueue`
31
+ * (`_storeNode`, `_storeWrappable`), and node birth and the untracked traps
32
+ * reach back through `affectsHooks` (hooks.ts).
28
33
  */
29
34
  /** The keyless mark's carrier key: a leaf of the record no read serves. */ const $AFFECTS = Symbol(0);
30
35
 
31
36
  const scopes = new Map;
32
37
 
38
+ function scopeOf(e, o) {
39
+ let n = scopes.get(e);
40
+ if (n === undefined) scopes.set(e, n = {
41
+ eo: new Set,
42
+ oo: [],
43
+ Vt: o
44
+ });
45
+ return n;
46
+ }
47
+
33
48
  /** The nodes an `affects(store[, key])` declaration marks (affects.ts
34
- * registers each). */ function storeMarks(e, n) {
35
- if (n === undefined) {
36
- const n = getNode(e, $AFFECTS);
37
- let o = scopes.get(n);
38
- if (o === undefined) scopes.set(n, o = {
39
- scope: new Set,
40
- inherited: []
41
- });
42
- const t = [ n ];
43
- walk(e.px, o, t, e.fam, new Set);
44
- return t;
49
+ * registers each). */ function storeMarks(e, o) {
50
+ const n = GlobalQueue.no(e, o === undefined ? $AFFECTS : o);
51
+ const t = scopeOf(n, o);
52
+ if (o === undefined) {
53
+ const o = [ n ];
54
+ walk(e.px, t, o, e.fam, new Set);
55
+ return o;
45
56
  }
46
- const o = e.n?.[n] ?? getNode(e, n);
47
- let t = scopes.get(o);
48
- if (t === undefined) scopes.set(o, t = {
49
- scope: new Set,
50
- inherited: [],
51
- key: n
52
- });
53
- t.scope.add(e.v);
54
- if (e.pb !== null) t.scope.add(e.pb);
55
- return [ o ];
57
+ t.eo.add(e.v);
58
+ if (e.pb !== null) t.eo.add(e.pb);
59
+ return [ n ];
56
60
  }
57
61
 
58
62
  /** The identities reachable from `value` into the scope (the draft's and
59
63
  * the committed backing both, when a draft is open; an optimistic family's
60
64
  * view), every live node under each record into `found`. Untracked by
61
- * construction: raws, never traps. */ function walk(e, n, o, t, s) {
62
- if (!isWrappable(e)) return;
65
+ * construction: raws, never traps. */ function walk(e, o, n, t, s) {
66
+ if (!GlobalQueue.so(e)) return;
63
67
  const f = e[$TARGET] ?? lookupTarget(e, t);
64
- let i = f !== undefined ? f.pb ?? f.v : e;
65
- if (s.has(i)) return;
66
- s.add(i);
67
- n.scope.add(i);
68
+ let r = f !== undefined ? f.pb ?? f.v : e;
69
+ if (s.has(r)) return;
70
+ s.add(r);
71
+ o.eo.add(r);
68
72
  if (f !== undefined) {
69
- if (f.pb !== null) n.scope.add(f.v);
73
+ if (f.pb !== null) o.eo.add(f.v);
70
74
  // The writer's view: the tick's own unflushed guesses are in motion too.
71
- if (f.fam?.opt === true) i = optHooks.view(f, i, true);
75
+ if (f.fam?.opt === true) r = optHooks.view(f, r, true);
72
76
  const e = f.n;
73
- if (e !== null) for (const n of Reflect.ownKeys(e))
77
+ if (e !== null) for (const o of Reflect.ownKeys(e))
74
78
  // Another mark's carrier is its own channel: counting it here would
75
79
  // extend that scope's lifetime to this declaration's.
76
- if (n !== $AFFECTS) o.push(e[n]);
80
+ if (o !== $AFFECTS) n.push(e[o]);
77
81
  const s = f.h;
78
- if (s !== null) for (const e of Reflect.ownKeys(s)) o.push(s[e]);
79
- if (f.k !== null) o.push(f.k);
80
- if (f.dk !== null) o.push(f.dk);
82
+ if (s !== null) for (const e of Reflect.ownKeys(s)) n.push(s[e]);
83
+ if (f.k !== null) n.push(f.k);
84
+ if (f.dk !== null) n.push(f.dk);
81
85
  t = f.fam ?? t;
82
86
  }
83
- for (const e of Reflect.ownKeys(i)) {
84
- if (e === $OWNER) continue;
85
- const f = Object.getOwnPropertyDescriptor(i, e);
86
- if (f === undefined || f.get !== undefined) continue;
87
- walk(f.value, n, o, t, s);
87
+ for (const e of Reflect.ownKeys(r)) if (e !== $OWNER) {
88
+ const f = Object.getOwnPropertyDescriptor(r, e);
89
+ if (f.get === undefined) walk(f.value, o, n, t, s);
88
90
  }
89
91
  }
90
92
 
91
93
  /** A live scope covering `t`'s identity (keyed: for `key`). Chained
92
94
  * backings (§7b): a view's backing is another store's proxy — marks cover
93
- * the BASE raw, so every identity along the chain is checked. */ function covering(e, n, o) {
95
+ * the BASE raw, so every identity along the chain is checked. */ function covering(e, o, n) {
94
96
  for (const [t, s] of scopes) {
95
- if (t === o || s.key !== undefined && s.key !== n) continue;
96
- for (let n = e.v; ;) {
97
- if (s.scope.has(n)) return t;
98
- const e = n?.[$TARGET];
97
+ if (t === n || s.Vt !== undefined && s.Vt !== o) continue;
98
+ for (let o = e.v; ;) {
99
+ if (s.eo.has(o)) return t;
100
+ const e = o?.[$TARGET];
99
101
  if (e === undefined) break;
100
- const o = e.pb ?? e.v;
101
- if (o === n) break;
102
- n = o;
102
+ const n = e.pb ?? e.v;
103
+ if (n === o) break;
104
+ o = n;
103
105
  }
104
106
  }
105
107
  return null;
106
108
  }
107
109
 
108
- installAffectsHooks({
110
+ /** The store's side: node birth and the untracked traps call it (store.ts,
111
+ * through `affectsHooks`) — with no live mark too: an empty scope map is
112
+ * no work. */ const hooks = {
109
113
  // A node born on a record a live mark covers inherits it (released with
110
114
  // the carrier's last registration).
111
- born(e, n, o) {
112
- if (o === $AFFECTS) return;
113
- const t = covering(e, o, n);
114
- if (t === null) return;
115
- GlobalQueue.h(n);
116
- scopes.get(t).inherited.push(n);
115
+ fo(e, o, n) {
116
+ if (scopes.size === 0 || n === $AFFECTS) return;
117
+ const t = covering(e, n, o);
118
+ if (!t) return;
119
+ GlobalQueue.N(o);
120
+ scopes.get(t).oo.push(o);
117
121
  },
118
122
  // An untracked probe (`isPending(() => s.x)` with no observer) reading a
119
123
  // record a live mark covers: no node carries the mark for it — the
120
124
  // verdict is told directly.
121
- witness(e, n) {
122
- const o = e.n?.[$AFFECTS];
123
- if (o !== undefined && o.m !== null && o.m.T !== 0 || covering(e, n) !== null) GlobalQueue.Bt();
125
+ ro(e, o) {
126
+ if (e.n?.[$AFFECTS]?.T?.I || covering(e, o)) GlobalQueue.bt();
124
127
  }
125
- });
128
+ };
126
129
 
127
- GlobalQueue.O = storeMarks;
130
+ /** `affects()` calls it before a store-targeted declaration (idempotent). */ function installStoreAffects() {
131
+ installAffectsHooks(hooks);
132
+ }
128
133
 
129
134
  /** The carrier's last mark released (affects.ts): its scope dies, and the
130
- * nodes that inherited the mark release theirs. */ GlobalQueue.N = e => {
131
- const n = scopes.get(e);
132
- if (n === undefined) return;
135
+ * nodes that inherited the mark release theirs. */ function releaseMarkScope(e) {
136
+ const o = scopes.get(e);
137
+ if (o === undefined) return;
133
138
  scopes.delete(e);
134
- GlobalQueue.A(n.inherited);
135
- };
139
+ releaseMarksHook(o.oo);
140
+ }
141
+
142
+ export { installStoreAffects, releaseMarkScope, storeMarks };