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

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 +2268 -1734
  2. package/dist/dev.attribution.js +75 -52
  3. package/dist/dev.js +1348 -658
  4. package/dist/observe/affects-marks.js +86 -0
  5. package/dist/observe/affects.js +22 -73
  6. package/dist/observe/boundaries.js +192 -190
  7. package/dist/observe/core/async.js +177 -131
  8. package/dist/observe/core/attribution-queries.js +1 -1
  9. package/dist/observe/core/attribution.js +176 -159
  10. package/dist/observe/core/constants.js +17 -3
  11. package/dist/observe/core/context.js +5 -3
  12. package/dist/observe/core/core.js +520 -364
  13. package/dist/observe/core/dev.js +66 -38
  14. package/dist/observe/core/effect.js +50 -48
  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 +60 -44
  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 +238 -260
  21. package/dist/observe/core/owner.js +117 -79
  22. package/dist/observe/core/scheduler.js +381 -217
  23. package/dist/observe/core/truth.js +45 -0
  24. package/dist/observe/core/verdict.js +91 -50
  25. package/dist/observe/deferred.js +184 -0
  26. package/dist/observe/index.js +7 -1
  27. package/dist/observe/map.js +345 -260
  28. package/dist/observe/reveal.js +76 -76
  29. package/dist/observe/signals.js +47 -31
  30. package/dist/observe/store/affects.js +18 -18
  31. package/dist/observe/store/edges.js +39 -0
  32. package/dist/observe/store/optimistic.js +146 -100
  33. package/dist/observe/store/projection.js +68 -55
  34. package/dist/observe/store/store.js +180 -118
  35. package/dist/prod/affects-marks.js +86 -0
  36. package/dist/prod/affects.js +23 -72
  37. package/dist/prod/boundaries.js +156 -154
  38. package/dist/prod/core/async.js +173 -127
  39. package/dist/prod/core/constants.js +17 -3
  40. package/dist/prod/core/context.js +5 -3
  41. package/dist/prod/core/core.js +495 -343
  42. package/dist/prod/core/effect.js +70 -68
  43. package/dist/prod/core/error.js +5 -3
  44. package/dist/prod/core/external.js +5 -6
  45. package/dist/prod/core/graph.js +60 -44
  46. package/dist/prod/core/heap.js +38 -38
  47. package/dist/prod/core/identities.js +62 -0
  48. package/dist/prod/core/lanes.js +230 -252
  49. package/dist/prod/core/owner.js +114 -77
  50. package/dist/prod/core/scheduler.js +327 -163
  51. package/dist/prod/core/truth.js +45 -0
  52. package/dist/prod/core/verdict.js +90 -49
  53. package/dist/prod/deferred.js +182 -0
  54. package/dist/prod/index.js +7 -1
  55. package/dist/prod/map.js +360 -275
  56. package/dist/prod/reveal.js +76 -76
  57. package/dist/prod/signals.js +42 -26
  58. package/dist/prod/store/affects.js +6 -6
  59. package/dist/prod/store/edges.js +39 -0
  60. package/dist/prod/store/optimistic.js +143 -98
  61. package/dist/prod/store/projection.js +25 -19
  62. package/dist/prod/store/store.js +157 -100
  63. package/dist/types/affects-marks.d.ts +14 -0
  64. package/dist/types/boundaries.d.ts +1 -1
  65. package/dist/types/core/async.d.ts +10 -0
  66. package/dist/types/core/constants.d.ts +13 -1
  67. package/dist/types/core/core.d.ts +54 -5
  68. package/dist/types/core/dev.d.ts +51 -13
  69. package/dist/types/core/error.d.ts +9 -1
  70. package/dist/types/core/graph.d.ts +11 -0
  71. package/dist/types/core/identities.d.ts +17 -0
  72. package/dist/types/core/index.d.ts +2 -1
  73. package/dist/types/core/lanes.d.ts +2 -14
  74. package/dist/types/core/owner.d.ts +9 -3
  75. package/dist/types/core/scheduler.d.ts +70 -32
  76. package/dist/types/core/truth.d.ts +16 -0
  77. package/dist/types/core/types.d.ts +21 -0
  78. package/dist/types/core/verdict.d.ts +32 -0
  79. package/dist/types/deferred.d.ts +28 -0
  80. package/dist/types/index.d.ts +6 -0
  81. package/dist/types/map.d.ts +2 -2
  82. package/dist/types/signals.d.ts +28 -7
  83. package/dist/types/store/edges.d.ts +9 -0
  84. package/dist/types/store/index.d.ts +10 -3
  85. package/dist/types/store/optimistic.d.ts +3 -2
  86. package/dist/types/store/projection.d.ts +4 -3
  87. package/dist/types/store/store.d.ts +1 -1
  88. package/dist/types/store/target.d.ts +16 -8
  89. package/dist/types/store/types.d.ts +14 -0
  90. package/package.json +1 -1
@@ -1,3 +1,5 @@
1
+ import { attrHooks } from "../core/attribution-hooks.js";
2
+
1
3
  import { CONFIG_AUTO_DISPOSE, STATUS_PENDING, STATUS_UNINITIALIZED } from "../core/constants.js";
2
4
 
3
5
  import { computed } from "../core/core.js";
@@ -10,15 +12,15 @@ import { enqueueSub } from "../core/heap.js";
10
12
 
11
13
  import { getOwner, isDisposed } from "../core/owner.js";
12
14
 
13
- import { question, setQuestion, schedule } from "../core/scheduler.js";
15
+ import { question, setQuestion, insertSubs, schedule } from "../core/scheduler.js";
14
16
 
15
17
  import { reconcileState } from "./reconcile.js";
16
18
 
17
19
  import { wrap, nameStore, storeSetter, runDirect } from "./store.js";
18
20
 
19
- import { setLookup } from "./target.js";
21
+ import { storeOwners, setLookup } from "./target.js";
20
22
 
21
- import { $TARGET, markRawIngest, setWriteOverride, isWrappable } from "./types.js";
23
+ import { $TARGET, markRawIngest, isWrappable, setWriteOverride } from "./types.js";
22
24
 
23
25
  /**
24
26
  * Store — projections (plan sec. 31, S3; INTERNALS §7/§7b).
@@ -50,22 +52,22 @@ import { $TARGET, markRawIngest, setWriteOverride, isWrappable } from "./types.j
50
52
  * set/getOwnPropertyDescriptor/defineProperty. With the store proxy as
51
53
  * target those checks re-enter the store's traps OUTSIDE the override
52
54
  * bracket, so `Object.keys(state)` in a derive continuation fired the gate.
53
- */ function wrapDraft(e, t, r, n, o, i) {
55
+ */ function wrapDraft(e, t, r, o, n, i) {
54
56
  const mutate = e => {
55
57
  if (!t()) return true;
56
58
  setWriteOverride(true);
57
59
  // A continuation's write is the flight's answer: it asks the flight's
58
60
  // question (A18 provenance — a landing beneath a newer guess is held,
59
61
  // not a correction; lanes.ts `laneWrite`).
60
- const n = question;
62
+ const o = question;
61
63
  if (i !== undefined) setQuestion(i());
62
64
  try {
63
65
  r ? r(e) : e();
64
66
  } finally {
65
67
  setWriteOverride(false);
66
- setQuestion(n);
68
+ setQuestion(o);
67
69
  }
68
- if (o) o();
70
+ if (n) n();
69
71
  return true;
70
72
  };
71
73
  const read = e => {
@@ -79,23 +81,23 @@ import { $TARGET, markRawIngest, setWriteOverride, isWrappable } from "./types.j
79
81
  const s = {
80
82
  get(s, c) {
81
83
  const u = read(() => e[c]);
82
- return !n && typeof u === "object" && u !== null && c !== $TARGET ? wrapDraft(u, t, r, false, o, i) : u;
84
+ return !o && typeof u === "object" && u !== null && c !== $TARGET ? wrapDraft(u, t, r, false, n, i) : u;
83
85
  },
84
86
  has: (t, r) => read(() => r in e),
85
- set: (t, r, n) => mutate(() => {
86
- e[r] = n;
87
+ set: (t, r, o) => mutate(() => {
88
+ e[r] = o;
87
89
  }),
88
90
  deleteProperty: (t, r) => mutate(() => {
89
91
  delete e[r];
90
92
  }),
91
93
  ownKeys: () => read(() => Reflect.ownKeys(e)),
92
94
  getOwnPropertyDescriptor(t, r) {
93
- const n = read(() => Reflect.getOwnPropertyDescriptor(e, r));
94
- if (n) n.configurable = true;
95
- return n;
95
+ const o = read(() => Reflect.getOwnPropertyDescriptor(e, r));
96
+ if (o) o.configurable = true;
97
+ return o;
96
98
  },
97
- defineProperty: (t, r, n) => mutate(() => {
98
- Reflect.defineProperty(e, r, n);
99
+ defineProperty: (t, r, o) => mutate(() => {
100
+ Reflect.defineProperty(e, r, o);
99
101
  })
100
102
  };
101
103
  const c = new Proxy(Array.isArray(e) ? [] : {}, s);
@@ -122,7 +124,7 @@ function cloneState(e, t) {
122
124
  const r = e.node;
123
125
  e.woke = true;
124
126
  forEachFamilyNode(e, e => {
125
- if (e.t === null) return;
127
+ if (e.o === null) return;
126
128
  // The leaf carries the derive's pending as a propagated copy, as a memo
127
129
  // between them would: a dependent recovering one branch stays pending
128
130
  // through a leaf it still reads (core `retryReaches`), and the landing's
@@ -139,7 +141,7 @@ function cloneState(e, t) {
139
141
  /** The derive's flight rejected: every live reader of the family
140
142
  * re-derives (its pull throws the derive's error). */ function errorFamily(e) {
141
143
  forEachFamilyNode(e, e => {
142
- if (e.t === null) return;
144
+ if (e.o === null) return;
143
145
  forEachDependent(e, e => {
144
146
  enqueueSub(e);
145
147
  });
@@ -154,7 +156,7 @@ function cloneState(e, t) {
154
156
  e.woke = false;
155
157
  const t = e.node;
156
158
  forEachFamilyNode(e, e => {
157
- if (e.t !== null) settlePendingSource(e, t);
159
+ if (e.o !== null) settlePendingSource(e, t);
158
160
  });
159
161
  }
160
162
 
@@ -162,8 +164,8 @@ function forEachFamilyNode(e, t) {
162
164
  for (const r of e.live) {
163
165
  const e = r.n;
164
166
  if (e !== null) for (const r of Reflect.ownKeys(e)) t(e[r]);
165
- const n = r.h;
166
- if (n !== null) for (const e of Reflect.ownKeys(n)) t(n[e]);
167
+ const o = r.h;
168
+ if (o !== null) for (const e of Reflect.ownKeys(o)) t(o[e]);
167
169
  if (r.k !== null) t(r.k);
168
170
  if (r.dk !== null) t(r.dk);
169
171
  }
@@ -173,7 +175,7 @@ function forEachFamilyNode(e, t) {
173
175
  * result (sync, or each async landing) through the reconcile channel.
174
176
  * Draft validity is per run (R37): live from here until the NEXT run starts
175
177
  * — a sync derive that subscribes to an external source and pushes into
176
- * the draft from the callback (#3585) is the model use. */ function runProjectionComputed(e, t, r, n, o) {
178
+ * the draft from the callback (#3585) is the model use. */ function runProjectionComputed(e, t, r, o, n) {
177
179
  const i = getOwner();
178
180
  const s = e[$TARGET];
179
181
  const c = s.fam;
@@ -183,43 +185,48 @@ function forEachFamilyNode(e, t) {
183
185
  // for the whole first flight — the derive works a detached shadow of the
184
186
  // seed so draft writes cannot tear through to readers (#2988). Every
185
187
  // commit point reconciles the shadow through the normal commit path.
186
- const a = i.De ? cloneState(s.v, s.s) : null;
188
+ const a = i.ce ? cloneState(s.v, s.s) : null;
187
189
  // The question a write of this run answers: inside a slice, the slice's
188
190
  // (the sync pass); in a continuation — the flight still registered — the
189
191
  // flight's (`handleAsync` stamped it with the action that asked).
190
- const asking = () => question || (i.m !== null && i.m.Te !== null ? i.m._e : 0);
191
- const f = wrapDraft(e, () => c.run === u && !isDisposed(i), o, s.s,
192
+ const asking = () => question || (i.T !== null && i.T.Se !== null ? i.T.Ee : 0);
193
+ const f = wrapDraft(e, () => c.run === u && !isDisposed(i), n, s.s,
192
194
  // A write after the run returned (a continuation, a callback) arms the
193
195
  // drain itself when no landing will.
194
196
  () => {
195
- if (!(i.S & STATUS_PENDING) && !i.De) schedule();
197
+ if (!(i.m & STATUS_PENDING) && !i.ce) schedule();
196
198
  }, asking);
197
199
  // The creation run commits directly (a memo's first value is its
198
200
  // `_value`); every later run — a re-derive in a flush, an async landing
199
201
  // — stages and commits with the flush like a memo's recompute.
200
202
  const d = u === 1;
201
- const pass = () => storeSetter(f, o => {
202
- l = t(a ?? o);
203
+ const pass = () => storeSetter(f, n => {
204
+ l = t(a ?? n);
203
205
  const commit = t => {
204
206
  // Shadow run: commit a detached snapshot, never the shadow itself
205
207
  // (adoption takes the value by identity — handing it the live
206
208
  // shadow would fuse the draft to the observable store).
207
209
  if (a && (t === undefined || t === a)) t = cloneState(a, s.s);
208
- if (t !== o && t !== undefined) {
210
+ if (t !== n && t !== undefined) {
209
211
  const write = () => {
210
- const n = question;
212
+ const o = question;
211
213
  setQuestion(asking());
212
214
  try {
213
215
  storeSetter(e, e => reconcileState(t, e, r, true), false);
214
216
  } finally {
215
- setQuestion(n);
217
+ setQuestion(o);
216
218
  }
217
219
  };
218
- n ? n(write, t) : write();
220
+ o ? o(write, t) : write();
219
221
  }
220
222
  // A landing (not the sync pass's own commit): the readers held
221
223
  // pending on the derive settle.
222
- if (!d || !(i.S & STATUS_UNINITIALIZED)) settleFamily(c);
224
+ if (!d || !(i.m & STATUS_UNINITIALIZED)) settleFamily(c);
225
+ // A commit is the derive's change for the readers that observed its
226
+ // flight (linked by `pullFamily`; a settled pull does not link), as
227
+ // a memo's landing is for its readers: one that caught the NotReady
228
+ // (a fallback value, not pending) re-runs too (#4070).
229
+ insertSubs(i);
223
230
  };
224
231
  const u = handleAsync(i, l, commit, (e, t) => {
225
232
  // The flight rejected: the leaves' readers learn it from here —
@@ -228,10 +235,10 @@ function forEachFamilyNode(e, t) {
228
235
  // reader re-derives and meets the error at its pull (memo parity,
229
236
  // #2897) — and the flush that runs them advances the clock, so a
230
237
  // later tracked re-read may retry (core `read`).
231
- if (d && i.S & STATUS_UNINITIALIZED) return;
238
+ if (d && i.m & STATUS_UNINITIALIZED) return;
232
239
  if (t) wakeFamily(c, e); else errorFamily(c);
233
240
  });
234
- if (!i.De) commit(u);
241
+ if (!i.ce) commit(u);
235
242
  }, false);
236
243
  try {
237
244
  d ? runDirect(pass) : pass();
@@ -248,23 +255,26 @@ function forEachFamilyNode(e, t) {
248
255
  // the wake, as for the throw. Not a sync pass that superseded one — the
249
256
  // status it reads is the dead flight's, cleared when this pass settles
250
257
  // (#3181: a reader the settle walk had just released, re-parked for good).
251
- if (i.S & STATUS_PENDING && i.m.Te !== null && !i.De && !d) wakeFamily(c, i.m?.F);
258
+ if (i.m & STATUS_PENDING && i.T.Se !== null && !i.ce && !d) wakeFamily(c, i.T?.F);
252
259
  return i;
253
260
  }
254
261
 
255
262
  function createProjectionInternal(e, t, r) {
256
- const n = r?.key === undefined ? "id" : r.key;
257
- const o = {
263
+ // Seedless (`fn` takes no draft): the root starts as an empty record. It is
264
+ // a draft like any seed, never observable before the first landing (A25).
265
+ t ||= {};
266
+ const o = r?.key === undefined ? "id" : r.key;
267
+ const n = {
258
268
  map: new WeakMap,
259
269
  node: null,
260
270
  live: new Set,
261
271
  shallow: !!r?.shallow,
262
272
  // The row key, for a child paired after the adoption (store.ts
263
273
  // `adoptChild`, #3712) as the adoption pairs them.
264
- key: typeof n === "function" ? n : n === null ? null : e => isWrappable(e) ? e[n] : undefined
274
+ key: typeof o === "function" ? o : o === null ? null : e => isWrappable(e) ? e[o] : undefined
265
275
  };
266
- const i = wrap(t, null, null, o);
267
- if (o.shallow) {
276
+ const i = wrap(t, null, null, n);
277
+ if (n.shallow) {
268
278
  i[$TARGET].s = true;
269
279
  markRawIngest(t);
270
280
  }
@@ -272,37 +282,40 @@ function createProjectionInternal(e, t, r) {
272
282
  if (r?.seedLoadingValue) s = {
273
283
  loadingValue: undefined
274
284
  };
275
- if (r?.name) {
285
+ if (attrHooks !== null)
286
+ // As createStore: the owner in scope stamps the projection's property
287
+ // nodes, so attribution places them under it (#4035).
288
+ storeOwners.set(i[$TARGET], getOwner());
289
+ if (r?.name || r?.loc) {
276
290
  s = {
277
291
  ...s,
278
- name: r.name
292
+ name: r.name,
293
+ loc: r.loc
279
294
  };
280
- nameStore(i, r.name);
295
+ nameStore(i, r.name, r.loc);
281
296
  }
282
297
  const c = computed(() => {
283
- if (!o.node) o.node = getOwner();
284
- runProjectionComputed(i, e, n);
298
+ if (!n.node) n.node = getOwner();
299
+ runProjectionComputed(i, e, o);
285
300
  }, s);
286
- c.i &= ~CONFIG_AUTO_DISPOSE;
287
- o.node = c;
301
+ c.l &= ~CONFIG_AUTO_DISPOSE;
302
+ n.node = c;
303
+ // The derive's leaves are not its dependents: a mark's repoll
304
+ // (affects-marks.ts) reaches their readers through this.
305
+ c.fam = n;
288
306
  return {
289
307
  store: i,
290
308
  node: c
291
309
  };
292
310
  }
293
311
 
294
- /**
295
- * A derived store: `fn` runs in a computed and writes its draft; readers of
296
- * the store's keys re-run only when the keys they read change (the
297
- * firewall). `fn` may be async or an async iterator; the seed is a draft,
298
- * never an observable value, until the first landing (A25).
299
- */ function createProjection(e, t, r) {
312
+ function createProjection(e, t, r) {
300
313
  return createProjectionInternal(e, t, r).store;
301
314
  }
302
315
 
303
316
  /** `createStore(fn, seed, options)`: a projection with a user setter. */ function createStoreDerived(e, t, r) {
304
- const {store: n} = createProjectionInternal(e, t, r);
305
- return [ n, e => storeSetter(n, e) ];
317
+ const {store: o} = createProjectionInternal(e, t, r);
318
+ return [ o, e => storeSetter(o, e) ];
306
319
  }
307
320
 
308
321
  export { createProjection, createStoreDerived, runProjectionComputed };