@solidjs/signals 2.0.0-rc.1 → 2.0.0-rc.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 (50) hide show
  1. package/dist/dev.js +1661 -361
  2. package/dist/node.cjs +1939 -1331
  3. package/dist/prod/affects.js +16 -16
  4. package/dist/prod/boundaries.js +90 -90
  5. package/dist/prod/core/action.js +3 -3
  6. package/dist/prod/core/async.js +74 -72
  7. package/dist/prod/core/constants.js +39 -1
  8. package/dist/prod/core/core.js +332 -224
  9. package/dist/prod/core/effect.js +56 -56
  10. package/dist/prod/core/external.js +4 -4
  11. package/dist/prod/core/graph.js +65 -54
  12. package/dist/prod/core/heap.js +52 -44
  13. package/dist/prod/core/invariants.js +3 -2
  14. package/dist/prod/core/lanes.js +41 -34
  15. package/dist/prod/core/optimistic.js +63 -60
  16. package/dist/prod/core/owner.js +97 -96
  17. package/dist/prod/core/scheduler.js +243 -194
  18. package/dist/prod/core/verdict.js +184 -77
  19. package/dist/prod/map.js +104 -104
  20. package/dist/prod/signals.js +1 -1
  21. package/dist/prod/store/next/optimistic.js +31 -23
  22. package/dist/prod/store/next/projection.js +3 -3
  23. package/dist/prod/store/next/reconcile.js +78 -74
  24. package/dist/prod/store/next/store.js +357 -90
  25. package/dist/prod/store/store.js +7 -7
  26. package/dist/types/core/attribution-hooks.d.ts +52 -0
  27. package/dist/types/core/attribution.d.ts +186 -0
  28. package/dist/types/core/constants.d.ts +26 -0
  29. package/dist/types/core/core.d.ts +8 -1
  30. package/dist/types/core/dev.d.ts +20 -3
  31. package/dist/types/core/graph.d.ts +1 -0
  32. package/dist/types/core/lanes.d.ts +4 -16
  33. package/dist/types/core/scheduler.d.ts +8 -0
  34. package/dist/types/core/types.d.ts +85 -41
  35. package/dist/types/store/next/projection.d.ts +0 -16
  36. package/dist/types/store/next/store.d.ts +6 -0
  37. package/dist/types/store/next/target.d.ts +18 -0
  38. package/dist/types-cjs/core/attribution-hooks.d.cts +52 -0
  39. package/dist/types-cjs/core/attribution.d.cts +186 -0
  40. package/dist/types-cjs/core/constants.d.cts +26 -0
  41. package/dist/types-cjs/core/core.d.cts +8 -1
  42. package/dist/types-cjs/core/dev.d.cts +20 -3
  43. package/dist/types-cjs/core/graph.d.cts +1 -0
  44. package/dist/types-cjs/core/lanes.d.cts +4 -16
  45. package/dist/types-cjs/core/scheduler.d.cts +8 -0
  46. package/dist/types-cjs/core/types.d.cts +85 -41
  47. package/dist/types-cjs/store/next/projection.d.cts +0 -16
  48. package/dist/types-cjs/store/next/store.d.cts +6 -0
  49. package/dist/types-cjs/store/next/target.d.cts +18 -0
  50. package/package.json +1 -1
@@ -10,7 +10,7 @@ import "../../core/effect.js";
10
10
 
11
11
  import { $TARGET, markRawIngest, isWrappable, rawValuesUsed, isRawValue, getWriteOverride } from "../store.js";
12
12
 
13
- import { adoptPB, unwrapValue, notifyFold, targetsEqual, bumpDeep, notifyKeyValue, notifyKeyDiff, notifyFoldTail, hasAccessorFlag } from "./store.js";
13
+ import { materializePB, adoptPB, unwrapValue, notifyFold, targetsEqual, bumpDeep, notifyKeyValue, notifyKeyDiff, notifyFoldTail, hasAccessorFlag } from "./store.js";
14
14
 
15
15
  import { storeNextLookup, optHooks, ownedRaw } from "./target.js";
16
16
 
@@ -35,40 +35,44 @@ import { storeNextLookup, optHooks, ownedRaw } from "./target.js";
35
35
  * members (R11). Kind changes replace wholesale (R10).
36
36
  */ function reconcileNextState(e, t, n, o = false) {
37
37
  if (t == null) throw new Error("");
38
- const f = t?.[$TARGET];
39
- if (f === undefined || f.px !== t) throw new Error("");
40
- let l = n === null ? null : typeof n === "string" ? e => e?.[n] : n;
38
+ const l = t?.[$TARGET];
39
+ if (l === undefined || l.px !== t) throw new Error("");
40
+ // Reconcile's diff walks need a REAL pending container a prototype
41
+ // overlay (#3044) materializes to the clone path first (edge: reconcile
42
+ // inside a setter that already wrote this target).
43
+ if (l.ovl) materializePB(l);
44
+ let f = n === null ? null : typeof n === "string" ? e => e?.[n] : n;
41
45
  // §7b chained backing: a projection derive returning a LIVE store proxy
42
46
  // adopts the proxy itself as the backing — reads flow through the inner
43
47
  // store's traps, so consumers subscribe to the inner graph and updates
44
48
  // flow with no re-derive (#2941). The adoption diff still notifies THIS
45
49
  // store's existing subscribers of the swap.
46
50
  if (o && e !== t && e?.[$TARGET] !== undefined) {
47
- const t = f.pb ?? f.v;
51
+ const t = l.pb ?? l.v;
48
52
  if (t === e) return;
49
53
  // already chained to this store
50
- adoptPB(f, e);
54
+ adoptPB(l, e);
51
55
  return;
52
56
  }
53
57
  const i = unwrapValue(e);
54
- if (l) {
58
+ if (f) {
55
59
  // Root identity precondition — checked before ANY mutation, so a throwing
56
60
  // reconcile is atomic by construction (RUL-12 ruling). Projections
57
61
  // (replace=true) relax it: a root entity change merges in place — the
58
62
  // root proxy is stable for life (proj R5/R11) — and children are NOT
59
63
  // key-matched across the entity change (proj R7: keyFn drops to
60
64
  // positional so old-entity subtrees never merge into the new entity's).
61
- const e = f.pb ?? f.v;
62
- const t = l(e);
63
- if (t !== undefined && l(i) !== t) {
65
+ const e = l.pb ?? l.v;
66
+ const t = f(e);
67
+ if (t !== undefined && f(i) !== t) {
64
68
  if (!o) throw new Error("");
65
69
  // Entity change: wholesale swap. The root proxy is stable for life
66
70
  // (proj R5) but NOTHING below survives — children are never matched
67
71
  // across an entity change even when their own keys align (proj R7).
68
72
  // Displaced-raw unregistration (proj R10): the outgoing raw stops
69
73
  // resolving to this proxy; re-handed later it wraps fresh.
70
- (f.fam?.map ?? storeNextLookup).delete(f.pb ?? f.v);
71
- adoptPB(f, i);
74
+ (l.fam?.map ?? storeNextLookup).delete(l.pb ?? l.v);
75
+ adoptPB(l, i);
72
76
  return;
73
77
  }
74
78
  }
@@ -77,59 +81,59 @@ import { storeNextLookup, optHooks, ownedRaw } from "./target.js";
77
81
  // armed nodes (reverting with their transaction); committed raw is never
78
82
  // touched. Key-matched rows keep proxy identity by descending into the
79
83
  // existing child targets instead of overriding their parent slots.
80
- if (f.fam?.opt === true && !projectionWriteActive && !getWriteOverride()) {
81
- optHooks.applyTentative(f, i, l);
84
+ if (l.fam?.opt === true && !projectionWriteActive && !getWriteOverride()) {
85
+ optHooks.applyTentative(l, i, f);
82
86
  return;
83
87
  }
84
- applyAdopt(f, i, l, o);
88
+ applyAdopt(l, i, f, o);
85
89
  }
86
90
 
87
91
  function applyAdopt(e, t, n, o = false) {
88
- const f = e.pb ?? e.v;
92
+ const l = e.pb ?? e.v;
89
93
  // The sound identity skip (O7): same reference AND we never diverged it.
90
- if (t === f && !ownedRaw.has(f)) return;
91
- const l = e.fam;
94
+ if (t === l && !ownedRaw.has(l)) return;
95
+ const f = e.fam;
92
96
  // §6b (R28): the diff's previous-arrangement baseline is the LANE VIEW —
93
97
  // optimistic rows must be visible to key matching so a landing carrying the
94
98
  // same key recycles their proxies. Raw `prev` keeps the identity/ownership
95
99
  // roles above; only matching reads the view.
96
- const i = l?.opt === true ? optHooks.optimisticView(e, f) : f;
100
+ const i = f?.opt === true ? optHooks.optimisticView(e, l) : l;
97
101
  const r = Array.isArray(t);
98
102
  // Plain stores notify inline AFTER the descent (child registrations feed
99
103
  // the fold diff's identity-preservation check); projections keep deferred
100
104
  // folds (downstream holds can form later in the flush).
101
- const u = l === null;
105
+ const u = f === null;
102
106
  const s = e.s === true;
103
- const c = e.v;
107
+ const a = e.v;
104
108
  adoptPB(e, t, u);
105
109
  // Shallow adoption: records are slot values — sticky raw-mark the incoming
106
110
  // set (R41) and never descend; slot notification is the positional diff.
107
111
  if (s) markRawIngest(t);
108
112
  if (Array.isArray(i) !== r) {
109
- if (u) notifyFold(e, c, t);
113
+ if (u) notifyFold(e, a, t);
110
114
  return;
111
115
  }
112
116
  if (r) {
113
- const f = i;
117
+ const l = i;
114
118
  const r = t;
115
119
  // Fused array walk (eager mode): per-index notification rides the same
116
120
  // loop as the descent (descend first — targetsEqual needs the child's
117
121
  // re-registration, R9). Length, trailing removed indexes, and any other
118
122
  // unvisited node keys land in the counted sweep below.
119
- const a = u ? e.n : null;
123
+ const c = u ? e.n : null;
120
124
  let p = 0;
121
125
  if (n && !s) {
122
126
  // Positional-prefix fast path (legacy keyedMatch-walk parity): while
123
127
  // rows key-match in place — the steady-state polling shape — descend
124
128
  // directly with zero staging. The prevByKey map is built only for the
125
129
  // misaligned remainder, and never at all on aligned ticks.
126
- const i = f.length;
130
+ const i = l.length;
127
131
  const u = r.length;
128
132
  let s = false;
129
133
  let d = 0;
130
134
  for (const y = Math.min(i, u); d < y; d++) {
131
135
  const i = r[d];
132
- const u = f[d];
136
+ const u = l[d];
133
137
  // Routing heuristic only (aligned vs keyed remainder) — both routes
134
138
  // notify identically and descend() is the one authoritative
135
139
  // validator, so bare typeof gates suffice here; full isWrappable
@@ -137,16 +141,16 @@ function applyAdopt(e, t, n, o = false) {
137
141
  if (u !== i && !(u !== null && typeof u === "object" && i !== null && typeof i === "object" && n(u) === n(i))) break;
138
142
  // misaligned: fall to the keyed remainder below
139
143
  // Identity skip inline (FINDING-1 guard), then descend the pair.
140
- if ((u !== i || i !== null && typeof i === "object" && ownedRaw.has(i)) && i !== null && typeof i === "object") descend(unwrapValue(u), i, n, l, o);
144
+ if ((u !== i || i !== null && typeof i === "object" && ownedRaw.has(i)) && i !== null && typeof i === "object") descend(unwrapValue(u), i, n, f, o);
141
145
  if (e.dk !== null && !s && !(i !== null && typeof i === "object" ? targetsEqual(u, i) : isEqual(u, i))) {
142
146
  bumpDeep(e);
143
147
  s = true;
144
148
  }
145
- if (a !== null) {
146
- const e = a[d];
149
+ if (c !== null) {
150
+ const e = c[d];
147
151
  if (e !== undefined) {
148
152
  p++;
149
- notifyKeyValue(e, d, c[d], i, c, t);
153
+ notifyKeyValue(e, d, a[d], i, a, t);
150
154
  }
151
155
  }
152
156
  }
@@ -161,8 +165,8 @@ function applyAdopt(e, t, n, o = false) {
161
165
  if (t !== undefined) {
162
166
  if (y === null) {
163
167
  y = new Map;
164
- for (let e = 0; e < f.length; e++) {
165
- const t = unwrapValue(f[e]);
168
+ for (let e = 0; e < l.length; e++) {
169
+ const t = unwrapValue(l[e]);
166
170
  if (t !== null && typeof t === "object") {
167
171
  const e = n(t);
168
172
  if (e !== undefined && !y.has(e)) y.set(e, t);
@@ -171,48 +175,48 @@ function applyAdopt(e, t, n, o = false) {
171
175
  }
172
176
  i = y.get(t);
173
177
  } else {
174
- i = unwrapValue(f[d]);
178
+ i = unwrapValue(l[d]);
175
179
  // keyless item: positional fallback
176
180
  }
177
- descend(i, e, n, l, o);
181
+ descend(i, e, n, f, o);
178
182
  }
179
- if (a !== null) {
180
- const e = a[d];
183
+ if (c !== null) {
184
+ const e = c[d];
181
185
  if (e !== undefined) {
182
186
  p++;
183
- notifyKeyDiff(e, d, c, t, false);
187
+ notifyKeyDiff(e, d, a, t, false);
184
188
  }
185
189
  }
186
190
  }
187
191
  } else {
188
- const i = Math.min(f.length, r.length);
192
+ const i = Math.min(l.length, r.length);
189
193
  const u = r.length;
190
194
  let d = false;
191
195
  for (let y = 0; y < u; y++) {
192
196
  const u = r[y];
193
- if (!s && y < i && u !== null && typeof u === "object") descend(unwrapValue(f[y]), u, n, l, o);
194
- if (e.dk !== null && !d && !(u !== null && typeof u === "object" ? targetsEqual(f[y], u) : isEqual(f[y], u))) {
197
+ if (!s && y < i && u !== null && typeof u === "object") descend(unwrapValue(l[y]), u, n, f, o);
198
+ if (e.dk !== null && !d && !(u !== null && typeof u === "object" ? targetsEqual(l[y], u) : isEqual(l[y], u))) {
195
199
  bumpDeep(e);
196
200
  d = true;
197
201
  }
198
- if (a !== null) {
199
- const e = a[y];
202
+ if (c !== null) {
203
+ const e = c[y];
200
204
  if (e !== undefined) {
201
205
  p++;
202
- notifyKeyDiff(e, y, c, t, false);
206
+ notifyKeyDiff(e, y, a, t, false);
203
207
  }
204
208
  }
205
209
  }
206
210
  }
207
211
  if (u) {
208
- if (a !== null && p < e.nc) {
209
- for (const e of Reflect.ownKeys(a)) {
212
+ if (c !== null && p < e.nc) {
213
+ for (const e of Reflect.ownKeys(c)) {
210
214
  // visited indexes are < nextRows.length; everything else sweeps
211
215
  const n = typeof e === "string" ? +e : NaN;
212
- if (!(n >= 0 && n < r.length)) notifyKeyDiff(a[e], e, c, t, false);
216
+ if (!(n >= 0 && n < r.length)) notifyKeyDiff(c[e], e, a, t, false);
213
217
  }
214
218
  }
215
- notifyFoldTail(e, c, t);
219
+ notifyFoldTail(e, a, t);
216
220
  }
217
221
  return;
218
222
  } else {
@@ -222,9 +226,9 @@ function applyAdopt(e, t, n, o = false) {
222
226
  // slots must not notify, R9). This replaces the notifyFold re-walk that
223
227
  // doubled dbmon's diff cost. for-in covers own enumerable string keys
224
228
  // with no key-array allocation; symbols get a pass only when present.
225
- const f = u ? e.n : null;
229
+ const l = u ? e.n : null;
226
230
  let r = 0;
227
- let a = false;
231
+ let c = false;
228
232
  // The per-key body is inlined on purpose (legacy applyStateFast parity:
229
233
  // an extracted helper costs a call per key on the hottest object-diff
230
234
  // site). Reference-identical values early-continue BEFORE any other
@@ -232,51 +236,51 @@ function applyAdopt(e, t, n, o = false) {
232
236
  // backing is setter-diverged and must still diff).
233
237
  for (const u in t) {
234
238
  const p = t[u];
235
- const d = c[u];
239
+ const d = a[u];
236
240
  const y = p !== null && typeof p === "object";
237
- if (d === p && (!y || !ownedRaw.has(p)) && (f === null || f[u] === undefined || !hasAccessorFlag(f[u]))) {
238
- if (f !== null && f[u] !== undefined) r++;
241
+ if (d === p && (!y || !ownedRaw.has(p)) && (l === null || l[u] === undefined || !hasAccessorFlag(l[u]))) {
242
+ if (l !== null && l[u] !== undefined) r++;
239
243
  continue;
240
244
  }
241
- if (y && !s) descend(unwrapValue(i[u]), p, n, l, o);
245
+ if (y && !s) descend(unwrapValue(i[u]), p, n, f, o);
242
246
  // Deep-witness (dk): value changes must notify even with NO per-key
243
247
  // node — deep() subscribes one node per record. Checked after descend
244
248
  // so in-place adoptions (same logical slot) don't bump; child records
245
249
  // carry their own witness. One flag + null check when unused.
246
- if (e.dk !== null && !a && !(y ? targetsEqual(d, p) : isEqual(d, p))) {
250
+ if (e.dk !== null && !c && !(y ? targetsEqual(d, p) : isEqual(d, p))) {
247
251
  bumpDeep(e);
248
- a = true;
252
+ c = true;
249
253
  }
250
- if (f !== null) {
251
- const e = f[u];
254
+ if (l !== null) {
255
+ const e = l[u];
252
256
  if (e !== undefined) {
253
257
  r++;
254
- notifyKeyValue(e, u, d, p, c, t);
258
+ notifyKeyValue(e, u, d, p, a, t);
255
259
  }
256
260
  }
257
261
  }
258
262
  const p = Object.getOwnPropertySymbols(t);
259
263
  for (let e = 0; e < p.length; e++) {
260
264
  const u = p[e];
261
- const a = t[u];
262
- if (!s && a !== null && typeof a === "object") descend(unwrapValue(i[u]), a, n, l, o);
263
- if (f !== null) {
264
- const e = f[u];
265
+ const c = t[u];
266
+ if (!s && c !== null && typeof c === "object") descend(unwrapValue(i[u]), c, n, f, o);
267
+ if (l !== null) {
268
+ const e = l[u];
265
269
  if (e !== undefined) {
266
270
  r++;
267
- notifyKeyValue(e, u, c[u], a, c, t);
271
+ notifyKeyValue(e, u, a[u], c, a, t);
268
272
  }
269
273
  }
270
274
  }
271
275
  if (u) {
272
276
  // Deleted-key nodes (in the map but absent from incoming) — counted
273
277
  // fast-out: when every node was visited, skip the sweep entirely.
274
- if (f !== null && r < e.nc) {
275
- for (const e of Reflect.ownKeys(f)) {
276
- if (!hasOwnP.call(t, e)) notifyKeyDiff(f[e], e, c, t, false);
278
+ if (l !== null && r < e.nc) {
279
+ for (const e of Reflect.ownKeys(l)) {
280
+ if (!hasOwnP.call(t, e)) notifyKeyDiff(l[e], e, a, t, false);
277
281
  }
278
282
  }
279
- notifyFoldTail(e, c, t);
283
+ notifyFoldTail(e, a, t);
280
284
  }
281
285
  return;
282
286
  }
@@ -284,14 +288,14 @@ function applyAdopt(e, t, n, o = false) {
284
288
 
285
289
  const hasOwnP = Object.prototype.hasOwnProperty;
286
290
 
287
- function descend(e, t, n, o, f = false) {
291
+ function descend(e, t, n, o, l = false) {
288
292
  if (e === null || typeof e !== "object" || t === null || typeof t !== "object") return;
289
293
  // Lookup FIRST: a hit implies pv was wrappable and never raw-marked (only
290
294
  // wrappables acquire targets; rawValues never wrap) — one WeakMap get
291
295
  // replaces isWrappable(pv) + isRawValue(pv), and a miss prunes untracked
292
296
  // subtrees before any further checks.
293
- const l = (o?.map ?? storeNextLookup).get(e);
294
- if (l === undefined) return;
297
+ const f = (o?.map ?? storeNextLookup).get(e);
298
+ if (f === undefined) return;
295
299
  // nothing proxied below this pair
296
300
  // The NEW side still validates fully: a frozen/platform/markRaw'd incoming
297
301
  // value is a leaf for reconcile — replaced by reference, never recursed
@@ -305,10 +309,10 @@ function descend(e, t, n, o, f = false) {
305
309
  if (Array.isArray(e) !== Array.isArray(t)) return;
306
310
  if (n) {
307
311
  const o = n(e);
308
- const f = n(t);
312
+ const l = n(t);
309
313
  // Key mismatch detaches: the slot takes the new entity; the old proxy
310
314
  // keeps its (old) backing and a fresh proxy wraps the new value on read.
311
- if (o !== undefined && f !== undefined && o !== f) return;
315
+ if (o !== undefined && l !== undefined && o !== l) return;
312
316
  }
313
317
  // Reachability pruning (§6d) is MODE-dependent, both pinned:
314
318
  // - keyed matching descends only where subscriptions exist at/below (`d`) —
@@ -320,8 +324,8 @@ function descend(e, t, n, o, f = false) {
320
324
  // UNCONDITIONALLY (proj R6: the slot keeps its proxy without needing a
321
325
  // subscriber below); plain keyed reconcile detaches unobserved captures
322
326
  // (recon-snap R18 — staleness is the pinned pruning contract).
323
- if (!f && n !== null && !l.d) return;
324
- applyAdopt(l, t, n, f);
327
+ if (!l && n !== null && !f.d) return;
328
+ applyAdopt(f, t, n, l);
325
329
  }
326
330
 
327
331
  export { reconcileNextState };