@solidjs/signals 2.0.0-rc.8 → 2.0.0-rc.9

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 (90) hide show
  1. package/dist/dev-shared.js +1399 -285
  2. package/dist/dev.attribution.js +459 -307
  3. package/dist/dev.js +1864 -435
  4. package/dist/observe/affects.js +3 -1
  5. package/dist/observe/attribution.js +7 -1
  6. package/dist/observe/boundaries.js +209 -154
  7. package/dist/observe/core/action.js +18 -8
  8. package/dist/observe/core/async.js +220 -110
  9. package/dist/observe/core/attribution-costs.js +66 -0
  10. package/dist/observe/core/attribution-feedback.js +282 -0
  11. package/dist/observe/core/attribution-hooks.js +23 -1
  12. package/dist/observe/core/attribution-queries.js +28 -0
  13. package/dist/observe/core/attribution.js +262 -485
  14. package/dist/observe/core/constants.js +34 -1
  15. package/dist/observe/core/context.js +3 -3
  16. package/dist/observe/core/core.js +867 -367
  17. package/dist/observe/core/dev.js +78 -17
  18. package/dist/observe/core/effect.js +67 -51
  19. package/dist/observe/core/error-hooks.js +71 -0
  20. package/dist/observe/core/external.js +4 -4
  21. package/dist/observe/core/graph.js +37 -37
  22. package/dist/observe/core/heap.js +45 -45
  23. package/dist/observe/core/invariants.js +2 -0
  24. package/dist/observe/core/lanes.js +86 -49
  25. package/dist/observe/core/optimistic.js +242 -95
  26. package/dist/observe/core/owner.js +98 -84
  27. package/dist/observe/core/scheduler.js +543 -305
  28. package/dist/observe/core/verdict.js +247 -129
  29. package/dist/observe/index.js +7 -3
  30. package/dist/observe/map.js +126 -124
  31. package/dist/observe/signals.js +33 -17
  32. package/dist/observe/store/index.js +2 -0
  33. package/dist/observe/store/next/optimistic.js +141 -132
  34. package/dist/observe/store/next/projection.js +34 -21
  35. package/dist/observe/store/next/reconcile.js +58 -56
  36. package/dist/observe/store/next/store.js +260 -146
  37. package/dist/observe/store/store.js +5 -3
  38. package/dist/observe/store/utils.js +948 -135
  39. package/dist/prod/attribution.js +26 -17
  40. package/dist/prod/boundaries.js +128 -76
  41. package/dist/prod/core/action.js +16 -8
  42. package/dist/prod/core/async.js +251 -143
  43. package/dist/prod/core/constants.js +34 -1
  44. package/dist/prod/core/context.js +3 -3
  45. package/dist/prod/core/core.js +843 -347
  46. package/dist/prod/core/dev.js +17 -1
  47. package/dist/prod/core/effect.js +48 -34
  48. package/dist/prod/core/error-hooks.js +71 -0
  49. package/dist/prod/core/external.js +4 -4
  50. package/dist/prod/core/graph.js +37 -37
  51. package/dist/prod/core/heap.js +45 -45
  52. package/dist/prod/core/lanes.js +90 -53
  53. package/dist/prod/core/optimistic.js +247 -100
  54. package/dist/prod/core/owner.js +57 -45
  55. package/dist/prod/core/scheduler.js +543 -305
  56. package/dist/prod/core/verdict.js +245 -127
  57. package/dist/prod/index.js +7 -3
  58. package/dist/prod/map.js +112 -112
  59. package/dist/prod/signals.js +28 -12
  60. package/dist/prod/store/next/optimistic.js +135 -128
  61. package/dist/prod/store/next/projection.js +31 -20
  62. package/dist/prod/store/next/store.js +325 -252
  63. package/dist/prod/store/store.js +2 -2
  64. package/dist/prod/store/utils.js +946 -135
  65. package/dist/types/attribution.d.ts +7 -2
  66. package/dist/types/attribution.prod.d.ts +10 -1
  67. package/dist/types/boundaries.d.ts +10 -1
  68. package/dist/types/core/action.d.ts +12 -5
  69. package/dist/types/core/attribution-costs.d.ts +35 -0
  70. package/dist/types/core/attribution-feedback.d.ts +133 -0
  71. package/dist/types/core/attribution-hooks.d.ts +28 -3
  72. package/dist/types/core/attribution-queries.d.ts +10 -0
  73. package/dist/types/core/attribution.d.ts +51 -172
  74. package/dist/types/core/constants.d.ts +33 -0
  75. package/dist/types/core/core.d.ts +186 -5
  76. package/dist/types/core/dev.d.ts +129 -9
  77. package/dist/types/core/error-hooks.d.ts +71 -0
  78. package/dist/types/core/index.d.ts +3 -1
  79. package/dist/types/core/invariants.d.ts +4 -0
  80. package/dist/types/core/lanes.d.ts +31 -4
  81. package/dist/types/core/scheduler.d.ts +95 -2
  82. package/dist/types/core/types.d.ts +3 -0
  83. package/dist/types/index.d.ts +2 -2
  84. package/dist/types/signals.d.ts +8 -0
  85. package/dist/types/store/index.d.ts +2 -1
  86. package/dist/types/store/next/optimistic.d.ts +1 -1
  87. package/dist/types/store/next/store.d.ts +6 -5
  88. package/dist/types/store/next/target.d.ts +1 -1
  89. package/dist/types/store/utils.d.ts +177 -6
  90. package/package.json +1 -1
package/dist/prod/map.js CHANGED
@@ -25,23 +25,23 @@ function mapArray(t, s, i) {
25
25
  const r = s.length > 1;
26
26
  const n = s;
27
27
  const o = {
28
- ts: createOwner(),
29
- ss: 0,
30
- es: t,
31
- rs: [],
32
- ns: n,
28
+ se: createOwner(),
29
+ ts: 0,
30
+ ss: t,
31
+ es: [],
32
+ rs: n,
33
+ ns: [],
33
34
  hs: [],
34
- fs: [],
35
- xt: e,
36
- cs: e || i?.keyed === false ? [] : undefined,
37
- ls: r && i?.keyed !== false ? [] : undefined,
38
- us: i?.keyed === false,
39
- ps: i?.fallback
35
+ qt: e,
36
+ fs: e || i?.keyed === false ? [] : undefined,
37
+ cs: r && i?.keyed !== false ? [] : undefined,
38
+ ls: i?.keyed === false,
39
+ us: i?.fallback
40
40
  };
41
41
  const h = computed(updateKeyedMap.bind(o), undefined);
42
42
  // Untracked reads inside the internal owner resolve via _parentComputed; routing
43
43
  // them through node lets store-proxy lookups see pending writes (not stale _value).
44
- o.ts.bt = h;
44
+ o.se.Qt = h;
45
45
  h.T &= ~CONFIG_AUTO_DISPOSE;
46
46
  return accessor(h);
47
47
  }
@@ -51,8 +51,8 @@ const pureOptions = {
51
51
  };
52
52
 
53
53
  function trySmallMove(t, s, i, e) {
54
- const r = t.rs;
55
- const n = t.ss - 1;
54
+ const r = t.es;
55
+ const n = t.ts - 1;
56
56
  const o = [];
57
57
  const h = [];
58
58
  const f = [];
@@ -124,7 +124,7 @@ function trySmallMove(t, s, i, e) {
124
124
  * body. Pairs displaced sources with destinations (an unmatched destination
125
125
  * is a replacement/insertion → general path), then commits: slice() the live
126
126
  * arrays, copy shifted runs, patch displaced pairs, dispose leftovers. */ function commitSmallMove(t, s, i, e, r, n) {
127
- const o = t.rs;
127
+ const o = t.es;
128
128
  let h;
129
129
  let f;
130
130
  let c;
@@ -159,8 +159,8 @@ function trySmallMove(t, s, i, e) {
159
159
  for (let e = 0, r = n[s + 2]; e < r; e++) if (t.has(o[i + e])) return false;
160
160
  }
161
161
  }
162
- const a = t.hs;
163
- const l = t.fs;
162
+ const a = t.ns;
163
+ const l = t.hs;
164
164
  const u = a.slice(0, i);
165
165
  const p = l.slice(0, i);
166
166
  for (let t = 0; t < n.length; t += 3) {
@@ -179,10 +179,10 @@ function trySmallMove(t, s, i, e) {
179
179
  u[t] = a[s];
180
180
  p[t] = l[s];
181
181
  }
182
- t.hs = u;
183
- t.fs = p;
184
- t.ss = i;
185
- t.rs = s.slice(0);
182
+ t.ns = u;
183
+ t.hs = p;
184
+ t.ts = i;
185
+ t.es = s.slice(0);
186
186
  // Dispose unmatched sources LAST (general-path ordering).
187
187
  for (h = 0; h < e.length; h++) {
188
188
  if (c === undefined || !c[h]) l[e[h]].dispose();
@@ -191,52 +191,52 @@ function trySmallMove(t, s, i, e) {
191
191
  }
192
192
 
193
193
  function updateKeyedMap() {
194
- const t = this.es() || [], s = t.length;
194
+ const t = this.ss() || [], s = t.length;
195
195
  t[$TRACK];
196
196
  // top level tracking
197
- runWithOwner(this.ts, () => {
197
+ runWithOwner(this.se, () => {
198
198
  let i, e, r, n,
199
199
  // Mappers write freshly-created row/index signals into the STAGE
200
200
  // arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
201
- o = this.cs ? this.us ? () => {
201
+ o = this.fs ? this.ls ? () => {
202
202
  r[e] = signal(t[e], pureOptions);
203
- return this.ns(accessor(r[e]), e);
203
+ return this.rs(accessor(r[e]), e);
204
204
  } : () => {
205
205
  r[e] = signal(t[e], pureOptions);
206
206
  n && (n[e] = signal(e, pureOptions));
207
- return this.ns(accessor(r[e]), n ? accessor(n[e]) : undefined);
208
- } : this.ls ? () => {
207
+ return this.rs(accessor(r[e]), n ? accessor(n[e]) : undefined);
208
+ } : this.cs ? () => {
209
209
  const s = t[e];
210
210
  n[e] = signal(e, pureOptions);
211
- return this.ns(s, accessor(n[e]));
211
+ return this.rs(s, accessor(n[e]));
212
212
  } : () => {
213
213
  const s = t[e];
214
- return this.ns(s);
214
+ return this.rs(s);
215
215
  };
216
216
  // fast path for empty arrays
217
217
  if (s === 0) {
218
- if (this.ss !== 0) {
219
- this.ts.dispose(false);
220
- this.fs = [];
221
- this.rs = [];
218
+ if (this.ts !== 0) {
219
+ this.se.dispose(false);
222
220
  this.hs = [];
223
- this.ss = 0;
221
+ this.es = [];
222
+ this.ns = [];
223
+ this.ts = 0;
224
+ this.fs && (this.fs = []);
224
225
  this.cs && (this.cs = []);
225
- this.ls && (this.ls = []);
226
226
  }
227
- if (this.ps && !this.hs[0]) {
227
+ if (this.us && !this.ns[0]) {
228
228
  // an aborted fallback attempt leaves an owner without a mapping;
229
229
  // dispose it before re-creating
230
- this.fs[0]?.dispose();
231
- this.hs[0] = runWithOwner(this.fs[0] = createOwner(), this.ps);
230
+ this.hs[0]?.dispose();
231
+ this.ns[0] = runWithOwner(this.hs[0] = createOwner(), this.us);
232
232
  }
233
233
  }
234
234
  // fast path for new create
235
- else if (this.ss === 0) {
235
+ else if (this.ts === 0) {
236
236
  const h = new Array(s);
237
237
  const f = new Array(s);
238
- r = this.cs && new Array(s);
239
- n = this.ls && new Array(s);
238
+ r = this.fs && new Array(s);
239
+ n = this.cs && new Array(s);
240
240
  try {
241
241
  for (e = 0; e < s; e++) h[e] = runWithOwner(f[e] = createOwner(), o);
242
242
  } catch (t) {
@@ -244,32 +244,32 @@ function updateKeyedMap() {
244
244
  throw t;
245
245
  }
246
246
  // commit
247
- if (this.fs[0]) this.fs[0].dispose();
247
+ if (this.hs[0]) this.hs[0].dispose();
248
248
  // previous fallback
249
- this.hs = h;
250
- this.fs = f;
251
- r && (this.cs = r);
252
- n && (this.ls = n);
253
- this.rs = t.slice(0);
254
- this.ss = s;
249
+ this.ns = h;
250
+ this.hs = f;
251
+ r && (this.fs = r);
252
+ n && (this.cs = n);
253
+ this.es = t.slice(0);
254
+ this.ts = s;
255
255
  } else {
256
256
  let h, f, c, a, l, u, p, d, w,
257
257
  // Dev (attribution engine installed): the items behind the exited and
258
258
  // entered rows, for the list-identity census.
259
259
  m, O;
260
260
  // skip common prefix
261
- for (h = 0, f = Math.min(this.ss, s); h < f && (this.rs[h] === t[h] || this.cs && compare(this.xt, this.rs[h], t[h])); h++) {
262
- if (this.cs) setSignal(this.cs[h], t[h]);
261
+ for (h = 0, f = Math.min(this.ts, s); h < f && (this.es[h] === t[h] || this.fs && compare(this.qt, this.es[h], t[h])); h++) {
262
+ if (this.fs) setSignal(this.fs[h], t[h]);
263
263
  }
264
264
  // skip common suffix — counted only; retained entries land in one pass
265
265
  // at commit instead of being staged and copied twice
266
- for (f = this.ss - 1, c = s - 1; f >= h && c >= h && (this.rs[f] === t[c] || this.cs && compare(this.xt, this.rs[f], t[c])); f--,
266
+ for (f = this.ts - 1, c = s - 1; f >= h && c >= h && (this.es[f] === t[c] || this.fs && compare(this.qt, this.es[f], t[c])); f--,
267
267
  c--) ;
268
268
  // no structural change (every position matched in place at equal
269
269
  // length — the common post-reconcile shape): keep the same mapped
270
270
  // array identity so downstream consumers don't re-run at all
271
- if (h === s && this.ss === s) {
272
- this.rs = t.slice(0);
271
+ if (h === s && this.ts === s) {
272
+ this.es = t.slice(0);
273
273
  return;
274
274
  }
275
275
  // SMALL-MOVE FAST PATH: extracted to its own function — inlining it
@@ -279,7 +279,7 @@ function updateKeyedMap() {
279
279
  // (plain removals, tail edits), the general path is window-
280
280
  // proportional and cheap — the fast path would only re-walk what the
281
281
  // trims proved.
282
- if (s <= this.ss && f - h > 64 && this.cs === undefined && this.ls === undefined) {
282
+ if (s <= this.ts && f - h > 64 && this.fs === undefined && this.cs === undefined) {
283
283
  // PROBE before the scan: a small move keeps a mid-window item within
284
284
  // ±32 of its old position; a REPLACE (all fresh items — the shape
285
285
  // every page's first structural pass usually is) has it nowhere.
@@ -289,21 +289,21 @@ function updateKeyedMap() {
289
289
  const e = t[i];
290
290
  const r = Math.min(f, i + 32);
291
291
  let n = Math.max(h, i - 32);
292
- while (n <= r && this.rs[n] !== e) n++;
292
+ while (n <= r && this.es[n] !== e) n++;
293
293
  if (n <= r && trySmallMove(this, t, s, h)) return;
294
294
  }
295
- const _ = s - this.ss;
295
+ const _ = s - this.ts;
296
296
  const y = new Array(s);
297
297
  const A = new Array(s);
298
- r = this.cs ? new Array(s) : undefined;
299
- n = this.ls ? new Array(s) : undefined;
298
+ r = this.fs ? new Array(s) : undefined;
299
+ n = this.cs ? new Array(s) : undefined;
300
300
  // 0) prepare a map of all indices in the changed window of newItems,
301
301
  // scanning backwards so we encounter them in natural order
302
302
  u = new Map;
303
303
  p = new Array(c + 1);
304
304
  for (e = c; e >= h; e--) {
305
305
  a = t[e];
306
- l = this.xt ? this.xt(a) : a;
306
+ l = this.qt ? this.qt(a) : a;
307
307
  i = u.get(l);
308
308
  p[e] = i === undefined ? -1 : i;
309
309
  u.set(l, e);
@@ -312,18 +312,18 @@ function updateKeyedMap() {
312
312
  // in the new set; if so, stage them at their new positions; if not,
313
313
  // queue them for disposal at commit
314
314
  for (i = h; i <= f; i++) {
315
- a = this.rs[i];
316
- l = this.xt ? this.xt(a) : a;
315
+ a = this.es[i];
316
+ l = this.qt ? this.qt(a) : a;
317
317
  e = u.get(l);
318
318
  if (e !== undefined && e !== -1) {
319
- y[e] = this.hs[i];
320
- A[e] = this.fs[i];
321
- r && (r[e] = this.cs[i]);
322
- n && (n[e] = this.ls[i]);
319
+ y[e] = this.ns[i];
320
+ A[e] = this.hs[i];
321
+ r && (r[e] = this.fs[i]);
322
+ n && (n[e] = this.cs[i]);
323
323
  e = p[e];
324
324
  u.set(l, e);
325
325
  } else {
326
- (d ??= []).push(this.fs[i]);
326
+ (d ??= []).push(this.hs[i]);
327
327
  if (false && attrHooks !== null) ;
328
328
  }
329
329
  }
@@ -343,39 +343,39 @@ function updateKeyedMap() {
343
343
  // into the fresh arrays, swap them in (new identity for downstream
344
344
  // change propagation), then dispose exited rows
345
345
  for (i = 0; i < h; i++) {
346
- y[i] = this.hs[i];
347
- A[i] = this.fs[i];
348
- r && (r[i] = this.cs[i]);
349
- n && (n[i] = this.ls[i]);
346
+ y[i] = this.ns[i];
347
+ A[i] = this.hs[i];
348
+ r && (r[i] = this.fs[i]);
349
+ n && (n[i] = this.cs[i]);
350
350
  }
351
351
  for (e = h; e <= c; e++) {
352
352
  if (r) setSignal(r[e], t[e]);
353
353
  if (n) setSignal(n[e], e);
354
354
  }
355
355
  for (e = c + 1; e < s; e++) {
356
- y[e] = this.hs[e - _];
357
- A[e] = this.fs[e - _];
356
+ y[e] = this.ns[e - _];
357
+ A[e] = this.hs[e - _];
358
358
  if (r) {
359
- r[e] = this.cs[e - _];
359
+ r[e] = this.fs[e - _];
360
360
  setSignal(r[e], t[e]);
361
361
  }
362
362
  if (n) {
363
- n[e] = this.ls[e - _];
363
+ n[e] = this.cs[e - _];
364
364
  if (_ !== 0) setSignal(n[e], e);
365
365
  }
366
366
  }
367
- this.hs = y;
368
- this.fs = A;
369
- r && (this.cs = r);
370
- n && (this.ls = n);
371
- this.ss = s;
367
+ this.ns = y;
368
+ this.hs = A;
369
+ r && (this.fs = r);
370
+ n && (this.cs = n);
371
+ this.ts = s;
372
372
  // save a copy of the mapped items for the next update
373
- this.rs = t.slice(0);
373
+ this.es = t.slice(0);
374
374
  if (d) for (i = 0; i < d.length; i++) d[i].dispose();
375
375
  if (false && attrHooks !== null && m !== undefined && O !== undefined) ;
376
376
  }
377
377
  });
378
- return this.hs;
378
+ return this.ns;
379
379
  }
380
380
 
381
381
  /**
@@ -395,21 +395,21 @@ function updateKeyedMap() {
395
395
  */ function repeat(t, s, i) {
396
396
  const e = s;
397
397
  const r = {
398
- ts: createOwner(),
399
- ss: 0,
400
- ds: 0,
401
- ws: t,
402
- ns: e,
403
- fs: [],
398
+ se: createOwner(),
399
+ ts: 0,
400
+ ps: 0,
401
+ ds: t,
402
+ rs: e,
404
403
  hs: [],
405
- Os: i?.from,
406
- ps: i?.fallback
404
+ ns: [],
405
+ ws: i?.from,
406
+ us: i?.fallback
407
407
  };
408
408
  const n = computed(updateRepeat.bind(r));
409
409
  // Same as mapArray: untracked reads inside the internal owner resolve via
410
410
  // _parentComputed, so async reads in row callbacks register with the node
411
411
  // (pending tracking + post-settle retry) instead of vanishing.
412
- r.ts.bt = n;
412
+ r.se.Qt = n;
413
413
  n.T &= ~CONFIG_AUTO_DISPOSE;
414
414
  return accessor(n);
415
415
  }
@@ -422,55 +422,55 @@ function updateKeyedMap() {
422
422
  // for the post-settle retry. The overlap math also subsumes the previous
423
423
  // disjoint-window/front-clear/end-clear/shift special cases.
424
424
  function updateRepeat() {
425
- const t = this.ws();
426
- const s = this.Os?.() || 0;
427
- runWithOwner(this.ts, () => {
425
+ const t = this.ds();
426
+ const s = this.ws?.() || 0;
427
+ runWithOwner(this.se, () => {
428
428
  if (t === 0) {
429
- if (this.ss !== 0) {
430
- this.ts.dispose(false);
431
- this.fs = [];
429
+ if (this.ts !== 0) {
430
+ this.se.dispose(false);
432
431
  this.hs = [];
433
- this.ss = 0;
432
+ this.ns = [];
433
+ this.ts = 0;
434
434
  // Reset offset to match the cleared data (#2767, repro 2).
435
- this.ds = 0;
435
+ this.ps = 0;
436
436
  }
437
- if (this.ps && !this.hs[0]) {
437
+ if (this.us && !this.ns[0]) {
438
438
  // an aborted fallback attempt leaves an owner without a mapping;
439
439
  // dispose it before re-creating
440
- this.fs[0]?.dispose();
441
- this.hs[0] = runWithOwner(this.fs[0] = createOwner(), this.ps);
440
+ this.hs[0]?.dispose();
441
+ this.ns[0] = runWithOwner(this.hs[0] = createOwner(), this.us);
442
442
  }
443
443
  return;
444
444
  }
445
445
  const i = s + t;
446
- const e = this.ds + this.ss;
446
+ const e = this.ps + this.ts;
447
447
  // Retained overlap [keepStart, keepEnd) in global indexes; empty when the
448
448
  // windows are disjoint or when coming from empty/fallback.
449
- const r = Math.max(s, this.ds);
449
+ const r = Math.max(s, this.ps);
450
450
  const n = Math.min(i, e);
451
451
  const o = new Array(t);
452
452
  const h = new Array(t);
453
453
  for (let t = r; t < n; t++) {
454
- h[t - s] = this.fs[t - this.ds];
455
- o[t - s] = this.hs[t - this.ds];
454
+ h[t - s] = this.hs[t - this.ps];
455
+ o[t - s] = this.ns[t - this.ps];
456
456
  }
457
457
  try {
458
458
  for (let t = s; t < i; t++) {
459
459
  if (t >= r && t < n) continue;
460
- o[t - s] = runWithOwner(h[t - s] = createOwner(), () => this.ns(t));
460
+ o[t - s] = runWithOwner(h[t - s] = createOwner(), () => this.rs(t));
461
461
  }
462
462
  } catch (t) {
463
463
  for (let t = s; t < i; t++) if ((t < r || t >= n) && h[t - s]) h[t - s].dispose();
464
464
  throw t;
465
465
  }
466
466
  // commit: dispose the previous fallback or the rows leaving the window
467
- if (this.ss === 0) this.fs[0]?.dispose(); else for (let t = this.ds; t < e; t++) if (t < s || t >= i) this.fs[t - this.ds].dispose();
468
- this.hs = o;
469
- this.fs = h;
470
- this.ds = s;
471
- this.ss = t;
467
+ if (this.ts === 0) this.hs[0]?.dispose(); else for (let t = this.ps; t < e; t++) if (t < s || t >= i) this.hs[t - this.ps].dispose();
468
+ this.ns = o;
469
+ this.hs = h;
470
+ this.ps = s;
471
+ this.ts = t;
472
472
  });
473
- return this.hs;
473
+ return this.ns;
474
474
  }
475
475
 
476
476
  function compare(t, s, i) {
@@ -4,7 +4,7 @@ import { computed, optimisticComputed, setSignal, optimisticSignal, runWithOwner
4
4
 
5
5
  import { cleanup, createRoot, getOwner, dispose, getObserver } from "./core/owner.js";
6
6
 
7
- import { globalQueue, Queue, entangleConfirmingTransitions, activeTransition } from "./core/scheduler.js";
7
+ import { globalQueue, dirtyQueue, Queue, entangleConfirmingTransitions, activeTransition } from "./core/scheduler.js";
8
8
 
9
9
  import { CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, EFFECT_USER, $REFRESH, CONFIG_DIRECT_COMMIT, CONFIG_AUTHORITATIVE_READ, CONFIG_FRESH_READ } from "./core/constants.js";
10
10
 
@@ -327,7 +327,7 @@ function createMemo(e, t) {
327
327
  // route through the inherited queue.
328
328
  const i = getOwner();
329
329
  const o = new MicrotaskQueue;
330
- o.qe = i.C;
330
+ o._parent = i.C;
331
331
  // notify() forwards up the normal chain
332
332
  i.C = o;
333
333
  // A user effect rather than a bare computed: computeds are pull-based and
@@ -349,7 +349,7 @@ function createMemo(e, t) {
349
349
  // stale mainline value and resolves with old data.
350
350
  {
351
351
  user: true,
352
- Pt: CONFIG_DIRECT_COMMIT
352
+ kt: CONFIG_DIRECT_COMMIT
353
353
  });
354
354
  });
355
355
  });
@@ -442,7 +442,7 @@ function createMemo(e, t) {
442
442
  if (i === null) {
443
443
  i = getOwner();
444
444
  const e = new MicrotaskQueue;
445
- e.qe = i.C;
445
+ e._parent = i.C;
446
446
  i.C = e;
447
447
  }
448
448
  return read(t);
@@ -454,7 +454,7 @@ function createMemo(e, t) {
454
454
  dispose(i);
455
455
  }, {
456
456
  user: true,
457
- Pt: CONFIG_DIRECT_COMMIT | CONFIG_AUTHORITATIVE_READ | CONFIG_FRESH_READ
457
+ kt: CONFIG_DIRECT_COMMIT | CONFIG_AUTHORITATIVE_READ | CONFIG_FRESH_READ
458
458
  });
459
459
  make();
460
460
  });
@@ -505,12 +505,20 @@ function createMemo(e, t) {
505
505
  *
506
506
  * Must be called *outside* a tracking scope.
507
507
  *
508
+ * Inside an action, call it from a step: after an `await`, put a bare `yield`
509
+ * before `yield until(...)`. The runtime cannot hook an async generator's
510
+ * `await` continuation, so the `until(...)` expression — which CREATES the
511
+ * predicate's reader — would otherwise run outside the transaction; created
512
+ * there it is born held (A29) and replays only at the commit its own promise
513
+ * holds open (#3482). See {@link action}.
514
+ *
508
515
  * @example
509
516
  * ```ts
510
517
  * const send = action(async function* (text: string) {
511
518
  * const clientId = crypto.randomUUID();
512
519
  * setMessages(m => { m.push({ clientId, text, pending: true }); }); // optimistic
513
520
  * await socket.send({ clientId, text }); // fire-and-forget transport
521
+ * yield; // re-enter the transaction after the await
514
522
  * // Hold until the live source echoes the write (authoritative view —
515
523
  * // the optimistic row above cannot satisfy this):
516
524
  * yield until(() => messages.some(m => m.clientId === clientId), { timeout: 10_000 });
@@ -537,10 +545,10 @@ function createMemo(e, t) {
537
545
  // microtask so the promise can settle while the transaction the caller
538
546
  // yielded it into is still open — that transaction being open is the
539
547
  // entire point of the hold.
540
- const s = getOwner();
541
- const u = new MicrotaskQueue;
542
- u.qe = s.C;
543
- s.C = u;
548
+ const u = getOwner();
549
+ const s = new MicrotaskQueue;
550
+ s._parent = u.C;
551
+ u.C = s;
544
552
  let f;
545
553
  let a;
546
554
  const settle = e => {
@@ -569,7 +577,7 @@ function createMemo(e, t) {
569
577
  // the hold itself is keeping uncommitted.
570
578
  {
571
579
  user: true,
572
- Pt: CONFIG_AUTHORITATIVE_READ | CONFIG_DIRECT_COMMIT
580
+ kt: CONFIG_AUTHORITATIVE_READ | CONFIG_DIRECT_COMMIT
573
581
  });
574
582
  if (t?.timeout !== undefined) f = setTimeout(() => settle(() => i(new TimeoutError)), t.timeout);
575
583
  if (o !== undefined) {
@@ -691,12 +699,20 @@ function createOptimistic(e, t) {
691
699
  * on owner disposal
692
700
  */ function onSettled(e) {
693
701
  const t = getOwner();
694
- t && !(t.T & CONFIG_CHILDREN_FORBIDDEN) ? trackedEffect(() => untrack(e), undefined) : globalQueue.enqueue(EFFECT_USER, () => {
702
+ t && !(t.T & CONFIG_CHILDREN_FORBIDDEN) ? trackedEffect(() => untrack(e), undefined) : globalQueue.enqueue(EFFECT_USER, function fire() {
703
+ // Settled means derived. A settle that reverts optimism (or replays
704
+ // gated reads) only enqueues the affected subscribers; the pass after
705
+ // the commit re-derives them. Fired in the commit pass, the callback
706
+ // read the optimistic source already reverted beside a sync memo of it
707
+ // still holding the optimistic value — reads do not pull (#3411). Fall
708
+ // to the next pass while the heap has work; `run` swapped the queue,
709
+ // so this lands there, and `enqueue` keeps the drain alive.
710
+ if (dirtyQueue.EE >= dirtyQueue.et) return globalQueue.enqueue(EFFECT_USER, fire);
695
711
  // Unowned, out-of-band fire (no owner, or a children-forbidden one this
696
712
  // one-shot must not bind to): a returned cleanup has no lifecycle to
697
713
  // attach to. Reject it in dev; in production the return is simply
698
714
  // dropped — never bound to an unrelated owner or run eagerly.
699
- e();
715
+ e();
700
716
  });
701
717
  }
702
718