@solidjs/signals 2.0.0-rc.2 → 2.0.0-rc.20

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 (198) hide show
  1. package/dist/dev-shared.js +6505 -0
  2. package/dist/dev.attribution.js +3484 -0
  3. package/dist/dev.js +10227 -9508
  4. package/dist/observe/affects-marks.js +86 -0
  5. package/dist/observe/affects.js +112 -0
  6. package/dist/observe/attribution.js +7 -0
  7. package/dist/observe/boundaries.js +696 -0
  8. package/dist/observe/core/action.js +182 -0
  9. package/dist/observe/core/async.js +824 -0
  10. package/dist/observe/core/attribution-costs.js +66 -0
  11. package/dist/observe/core/attribution-feedback.js +280 -0
  12. package/dist/observe/core/attribution-hooks.js +83 -0
  13. package/dist/observe/core/attribution-queries.js +43 -0
  14. package/dist/observe/core/attribution.js +3079 -0
  15. package/dist/observe/core/constants.js +269 -0
  16. package/dist/observe/core/context.js +63 -0
  17. package/dist/observe/core/copies.js +10 -0
  18. package/dist/observe/core/core.js +1707 -0
  19. package/dist/observe/core/dev.js +394 -0
  20. package/dist/observe/core/effect.js +193 -0
  21. package/dist/observe/core/error-hooks.js +71 -0
  22. package/dist/observe/core/error.js +82 -0
  23. package/dist/observe/core/external.js +97 -0
  24. package/dist/observe/core/graph.js +162 -0
  25. package/dist/observe/core/heap.js +124 -0
  26. package/dist/observe/core/identities.js +62 -0
  27. package/dist/observe/core/invariants.js +12 -0
  28. package/dist/observe/core/lanes.js +972 -0
  29. package/dist/observe/core/owner.js +371 -0
  30. package/dist/observe/core/scheduler.js +1157 -0
  31. package/dist/observe/core/truth.js +47 -0
  32. package/dist/observe/core/verdict.js +470 -0
  33. package/dist/observe/deferred.js +186 -0
  34. package/dist/observe/flatten.js +79 -0
  35. package/dist/observe/from.js +248 -0
  36. package/dist/observe/index.js +71 -0
  37. package/dist/observe/map.js +593 -0
  38. package/dist/observe/reveal.js +212 -0
  39. package/dist/observe/signals.js +717 -0
  40. package/dist/observe/store/affects.js +142 -0
  41. package/dist/observe/store/edges.js +39 -0
  42. package/dist/observe/store/hooks.js +16 -0
  43. package/dist/observe/store/index.js +47 -0
  44. package/dist/observe/store/optimistic.js +713 -0
  45. package/dist/observe/store/projection.js +345 -0
  46. package/dist/observe/store/reconcile.js +281 -0
  47. package/dist/observe/store/store.js +2127 -0
  48. package/dist/observe/store/storePath.js +103 -0
  49. package/dist/observe/store/target.js +46 -0
  50. package/dist/observe/store/types.js +83 -0
  51. package/dist/observe/store/utils.js +1063 -0
  52. package/dist/prod/affects-marks.js +86 -0
  53. package/dist/prod/affects.js +98 -112
  54. package/dist/prod/attribution.js +45 -0
  55. package/dist/prod/boundaries.js +578 -468
  56. package/dist/prod/core/action.js +92 -59
  57. package/dist/prod/core/async.js +522 -336
  58. package/dist/prod/core/attribution-hooks.js +3 -0
  59. package/dist/prod/core/constants.js +168 -44
  60. package/dist/prod/core/context.js +12 -16
  61. package/dist/prod/core/copies.js +10 -0
  62. package/dist/prod/core/core.js +1345 -627
  63. package/dist/prod/core/dev.js +123 -1
  64. package/dist/prod/core/effect.js +113 -80
  65. package/dist/prod/core/error-hooks.js +71 -0
  66. package/dist/prod/core/error.js +18 -4
  67. package/dist/prod/core/external.js +6 -7
  68. package/dist/prod/core/graph.js +119 -72
  69. package/dist/prod/core/heap.js +85 -109
  70. package/dist/prod/core/identities.js +62 -0
  71. package/dist/prod/core/invariants.js +1 -32
  72. package/dist/prod/core/lanes.js +931 -132
  73. package/dist/prod/core/owner.js +192 -129
  74. package/dist/prod/core/scheduler.js +948 -642
  75. package/dist/prod/core/truth.js +47 -0
  76. package/dist/prod/core/verdict.js +409 -420
  77. package/dist/prod/deferred.js +184 -0
  78. package/dist/prod/flatten.js +77 -0
  79. package/dist/prod/from.js +248 -0
  80. package/dist/prod/index.js +40 -16
  81. package/dist/prod/map.js +481 -211
  82. package/dist/prod/reveal.js +212 -0
  83. package/dist/prod/signals.js +401 -84
  84. package/dist/prod/store/affects.js +142 -0
  85. package/dist/prod/store/edges.js +39 -0
  86. package/dist/prod/store/hooks.js +16 -0
  87. package/dist/prod/store/index.js +27 -18
  88. package/dist/prod/store/optimistic.js +707 -0
  89. package/dist/prod/store/projection.js +331 -0
  90. package/dist/prod/store/reconcile.js +281 -0
  91. package/dist/prod/store/store.js +1952 -267
  92. package/dist/prod/store/storePath.js +1 -1
  93. package/dist/prod/store/target.js +43 -0
  94. package/dist/prod/store/types.js +83 -0
  95. package/dist/prod/store/utils.js +997 -138
  96. package/dist/types/affects-marks.d.ts +14 -0
  97. package/dist/types/affects.d.ts +12 -30
  98. package/dist/types/attribution.d.ts +19 -0
  99. package/dist/types/attribution.prod.d.ts +22 -0
  100. package/dist/types/boundaries.d.ts +99 -124
  101. package/dist/types/carved.d.ts +1 -0
  102. package/dist/types/core/action.d.ts +23 -9
  103. package/dist/types/core/async.d.ts +34 -6
  104. package/dist/types/core/attribution-costs.d.ts +35 -0
  105. package/dist/types/core/attribution-feedback.d.ts +133 -0
  106. package/dist/types/core/attribution-hooks.d.ts +307 -8
  107. package/dist/types/core/attribution-queries.d.ts +24 -0
  108. package/dist/types/core/attribution.d.ts +802 -72
  109. package/dist/types/core/constants.d.ts +195 -38
  110. package/dist/types/core/copies.d.ts +54 -0
  111. package/dist/types/core/core.d.ts +295 -65
  112. package/dist/types/core/dev.d.ts +509 -22
  113. package/dist/types/core/effect.d.ts +1 -1
  114. package/dist/types/core/error-hooks.d.ts +71 -0
  115. package/dist/types/core/error.d.ts +18 -1
  116. package/dist/types/core/graph.d.ts +40 -1
  117. package/dist/types/core/heap.d.ts +5 -5
  118. package/dist/types/core/identities.d.ts +17 -0
  119. package/dist/types/core/index.d.ts +11 -7
  120. package/dist/types/core/invariants.d.ts +1 -26
  121. package/dist/types/core/lanes.d.ts +74 -43
  122. package/dist/types/core/owner.d.ts +27 -9
  123. package/dist/types/core/scheduler.d.ts +353 -102
  124. package/dist/types/core/truth.d.ts +18 -0
  125. package/dist/types/core/types.d.ts +97 -71
  126. package/dist/types/core/verdict.d.ts +35 -0
  127. package/dist/types/deferred.d.ts +28 -0
  128. package/dist/types/flatten.d.ts +8 -0
  129. package/dist/types/from.d.ts +47 -0
  130. package/dist/types/index.d.ts +33 -7
  131. package/dist/types/map.d.ts +4 -2
  132. package/dist/types/reveal.d.ts +19 -0
  133. package/dist/types/signals.d.ts +196 -45
  134. package/dist/types/store/affects.d.ts +12 -0
  135. package/dist/types/store/edges.d.ts +9 -0
  136. package/dist/types/store/hooks.d.ts +62 -0
  137. package/dist/types/store/index.d.ts +42 -15
  138. package/dist/types/store/optimistic.d.ts +24 -45
  139. package/dist/types/store/projection.d.ts +17 -68
  140. package/dist/types/store/reconcile.d.ts +3 -46
  141. package/dist/types/store/store.d.ts +133 -136
  142. package/dist/types/store/storePath.d.ts +1 -1
  143. package/dist/types/store/target.d.ts +166 -0
  144. package/dist/types/store/types.d.ts +105 -0
  145. package/dist/types/store/utils.d.ts +188 -0
  146. package/package.json +31 -26
  147. package/dist/node.cjs +0 -8745
  148. package/dist/prod/core/optimistic.js +0 -265
  149. package/dist/prod/store/next/optimistic.js +0 -385
  150. package/dist/prod/store/next/projection.js +0 -172
  151. package/dist/prod/store/next/reconcile.js +0 -331
  152. package/dist/prod/store/next/store.js +0 -1499
  153. package/dist/prod/store/next/target.js +0 -20
  154. package/dist/types/core/optimistic.d.ts +0 -6
  155. package/dist/types/store/next/optimistic.d.ts +0 -20
  156. package/dist/types/store/next/projection.d.ts +0 -8
  157. package/dist/types/store/next/reconcile.d.ts +0 -3
  158. package/dist/types/store/next/store.d.ts +0 -77
  159. package/dist/types/store/next/target.d.ts +0 -117
  160. package/dist/types-cjs/affects.d.cts +0 -47
  161. package/dist/types-cjs/boundaries.d.cts +0 -175
  162. package/dist/types-cjs/core/action.d.cts +0 -64
  163. package/dist/types-cjs/core/async.d.cts +0 -21
  164. package/dist/types-cjs/core/attribution-hooks.d.cts +0 -52
  165. package/dist/types-cjs/core/attribution.d.cts +0 -186
  166. package/dist/types-cjs/core/constants.d.cts +0 -97
  167. package/dist/types-cjs/core/context.d.cts +0 -36
  168. package/dist/types-cjs/core/core.d.cts +0 -163
  169. package/dist/types-cjs/core/dev.d.cts +0 -81
  170. package/dist/types-cjs/core/effect.d.cts +0 -30
  171. package/dist/types-cjs/core/error.d.cts +0 -47
  172. package/dist/types-cjs/core/external.d.cts +0 -15
  173. package/dist/types-cjs/core/graph.d.cts +0 -6
  174. package/dist/types-cjs/core/heap.d.cts +0 -22
  175. package/dist/types-cjs/core/index.d.cts +0 -13
  176. package/dist/types-cjs/core/invariants.d.cts +0 -59
  177. package/dist/types-cjs/core/lanes.d.cts +0 -44
  178. package/dist/types-cjs/core/optimistic.d.cts +0 -6
  179. package/dist/types-cjs/core/owner.d.cts +0 -124
  180. package/dist/types-cjs/core/scheduler.d.cts +0 -180
  181. package/dist/types-cjs/core/types.d.cts +0 -192
  182. package/dist/types-cjs/core/verdict.d.cts +0 -2
  183. package/dist/types-cjs/index.d.cts +0 -10
  184. package/dist/types-cjs/map.d.cts +0 -69
  185. package/dist/types-cjs/package.json +0 -3
  186. package/dist/types-cjs/signals.d.cts +0 -624
  187. package/dist/types-cjs/store/index.d.cts +0 -19
  188. package/dist/types-cjs/store/next/optimistic.d.cts +0 -20
  189. package/dist/types-cjs/store/next/projection.d.cts +0 -8
  190. package/dist/types-cjs/store/next/reconcile.d.cts +0 -3
  191. package/dist/types-cjs/store/next/store.d.cts +0 -77
  192. package/dist/types-cjs/store/next/target.d.cts +0 -117
  193. package/dist/types-cjs/store/optimistic.d.cts +0 -45
  194. package/dist/types-cjs/store/projection.d.cts +0 -70
  195. package/dist/types-cjs/store/reconcile.d.cts +0 -46
  196. package/dist/types-cjs/store/store.d.cts +0 -138
  197. package/dist/types-cjs/store/storePath.d.cts +0 -58
  198. package/dist/types-cjs/store/utils.d.cts +0 -74
@@ -0,0 +1,345 @@
1
+ import { attrHooks } from "../core/attribution-hooks.js";
2
+
3
+ import { CONFIG_AUTO_DISPOSE, STATUS_PENDING, STATUS_ERROR, STATUS_UNINITIALIZED } from "../core/constants.js";
4
+
5
+ import { computed } from "../core/core.js";
6
+
7
+ import { NotReadyError } from "../core/error.js";
8
+
9
+ import { handleAsync, addPendingSource, propagateStatus, forEachDependent, settlePendingSource } from "../core/async.js";
10
+
11
+ import { enqueueSub } from "../core/heap.js";
12
+
13
+ import { getOwner, isDisposed } from "../core/owner.js";
14
+
15
+ import { question, setQuestion, insertSubs, schedule } from "../core/scheduler.js";
16
+
17
+ import { optHooks } from "./hooks.js";
18
+
19
+ import { reconcileState } from "./reconcile.js";
20
+
21
+ import { wrap, nameStore, storeSetter, runDirect } from "./store.js";
22
+
23
+ import { storeOwners, setLookup } from "./target.js";
24
+
25
+ import { $TARGET, markRawIngest, isWrappable, setWriteOverride } from "./types.js";
26
+
27
+ /**
28
+ * Store — projections (plan sec. 31, S3; INTERNALS §7/§7b).
29
+ *
30
+ * A projection is a computed store: the derive runs inside a computed — the
31
+ * **firewall** — whose pass writes the store through a draft; its output is
32
+ * adopted through the reconcile channel (replace-mode root: entity changes
33
+ * merge in place, the root proxy is stable for life). Children wrap into
34
+ * the projection's own FAMILY (writes land here, never in a source family).
35
+ *
36
+ * The firewall exists so writes from inside a computation are safe (the
37
+ * derive owns its leaves); the price is the ordering obligation: before any
38
+ * value is served through the projection, the derive is brought up to date
39
+ * — **without** the reader subscribing to it (that is the propagation
40
+ * barrier). The store's traps do that pull (`pullFamily`, store.ts): core's
41
+ * `read()` of the firewall with no link — freshness, the status gate
42
+ * (uninitialized / pending / errored) and the reader's height, by the
43
+ * rules a memo's read follows. No per-leaf back-pointer, nothing in core.
44
+ */
45
+ /**
46
+ * Wrap a store proxy as a projection DRAFT: every operation carries the write
47
+ * override (the derive is the author — its ops must not hit the status gate,
48
+ * even in a continuation after an `await`/`yield` where the sync write scope
49
+ * has closed).
50
+ *
51
+ * FAKE TARGET, not the store proxy itself (#3060): after a proxy trap
52
+ * returns, the engine runs spec invariant validation against the proxy's
53
+ * TARGET — [[OwnPropertyKeys]] after ownKeys, [[GetOwnProperty]] after
54
+ * set/getOwnPropertyDescriptor/defineProperty. With the store proxy as
55
+ * target those checks re-enter the store's traps OUTSIDE the override
56
+ * bracket, so `Object.keys(state)` in a derive continuation fired the gate.
57
+ */ function wrapDraft(e, t, r, o, n, i) {
58
+ const mutate = e => {
59
+ if (!t()) return true;
60
+ setWriteOverride(true);
61
+ // A continuation's write is the flight's answer: it asks the flight's
62
+ // question (A18 provenance — a landing beneath a newer guess is held,
63
+ // not a correction; lanes.ts `laneWrite`).
64
+ const o = question;
65
+ if (i !== undefined) setQuestion(i());
66
+ try {
67
+ r ? r(e) : e();
68
+ } finally {
69
+ setWriteOverride(false);
70
+ setQuestion(o);
71
+ }
72
+ if (n) n();
73
+ return true;
74
+ };
75
+ const read = e => {
76
+ setWriteOverride(true);
77
+ try {
78
+ return e();
79
+ } finally {
80
+ setWriteOverride(false);
81
+ }
82
+ };
83
+ const s = {
84
+ get(s, c) {
85
+ const a = read(() => e[c]);
86
+ return !o && typeof a === "object" && a !== null && c !== $TARGET ? wrapDraft(a, t, r, false, n, i) : a;
87
+ },
88
+ has: (t, r) => read(() => r in e),
89
+ set: (t, r, o) => mutate(() => {
90
+ e[r] = o;
91
+ }),
92
+ deleteProperty: (t, r) => mutate(() => {
93
+ delete e[r];
94
+ }),
95
+ ownKeys: () => read(() => Reflect.ownKeys(e)),
96
+ getOwnPropertyDescriptor(t, r) {
97
+ const o = read(() => Reflect.getOwnPropertyDescriptor(e, r));
98
+ if (o) o.configurable = true;
99
+ return o;
100
+ },
101
+ defineProperty: (t, r, o) => mutate(() => {
102
+ Reflect.defineProperty(e, r, o);
103
+ })
104
+ };
105
+ const c = new Proxy(Array.isArray(e) ? [] : {}, s);
106
+ // The wrapper stands for its store proxy wherever the derive's result
107
+ // carries it (`wrap`, `unwrapValue`, reconcile's slot matching).
108
+ const a = e[$TARGET];
109
+ if (a !== undefined) setLookup(c, a);
110
+ return c;
111
+ }
112
+
113
+ function cloneState(e, t) {
114
+ return t ? Array.isArray(e) ? e.slice() : {
115
+ ...e
116
+ } : JSON.parse(JSON.stringify(e));
117
+ }
118
+
119
+ /** The derive's pass went pending (a new question in flight): every reader
120
+ * of a leaf learns it as a reader of the derive would (A9: any leaf reports
121
+ * the firewall's refetch) — core's own rule for a dependency going pending
122
+ * (`notifyStatus`): a verdict or re-derive reader re-runs, any other is
123
+ * pending derivatively on the derive (its readers hold; it re-runs at the
124
+ * landing). The leaves do not subscribe to the derive, so the family does
125
+ * the walk. */ function wakeFamily(e) {
126
+ const t = e.node;
127
+ // Pending on the derive itself, whatever source took it there (an upstream
128
+ // memo's flight reaches it as a NotReady of that memo, #4271): the leaves
129
+ // are not that source's dependents, so only the family's settle — which
130
+ // retires the derive (`settleFamily`) — reaches the readers parked here. A
131
+ // reader the landing leaves unchanged does not re-run to clear it (#4305).
132
+ const r = new NotReadyError(t);
133
+ e.woke = true;
134
+ optHooks?.ask(e);
135
+ forEachFamilyNode(e, e => {
136
+ if (e.o === null) return;
137
+ // The leaf carries the derive's pending as a propagated copy, as a memo
138
+ // between them would: a dependent recovering one branch stays pending
139
+ // through a leaf it still reads (core `retryReaches`), and the landing's
140
+ // walk retires the copy first (`settleFamily` → `settlePendingSource`).
141
+ addPendingSource(e, t);
142
+ // Its readers: core's propagation from the leaf — a verdict or re-derive
143
+ // reader re-runs, any other is pending derivatively on the derive and
144
+ // queued for the frame (held with it: the frame waits on the flight
145
+ // through them, `blocked`).
146
+ propagateStatus(e, STATUS_PENDING, r);
147
+ });
148
+ }
149
+
150
+ /** The derive's flight rejected: every live reader of the family
151
+ * re-derives (its pull throws the derive's error). */ function errorFamily(e) {
152
+ forEachFamilyNode(e, e => {
153
+ if (e.o === null) return;
154
+ forEachDependent(e, e => {
155
+ enqueueSub(e);
156
+ });
157
+ });
158
+ schedule();
159
+ }
160
+
161
+ /** The flight landed: the readers the wake left pending on the derive
162
+ * settle — core's walk, from each leaf (the leaves are not the derive's
163
+ * dependents, so its own settle walk does not reach them). */ function settleFamily(e) {
164
+ if (!e.woke) return;
165
+ e.woke = false;
166
+ const t = e.node;
167
+ forEachFamilyNode(e, e => {
168
+ if (e.o !== null) settlePendingSource(e, t);
169
+ });
170
+ // The landing is the derive's change for a reader parked on the derive
171
+ // itself, whatever status the landing pass began from (an errored derive
172
+ // re-asked: a reader that met the error has no leaf to learn it from).
173
+ insertSubs(t);
174
+ }
175
+
176
+ /** A source's status reached the derive by propagation (core
177
+ * `propagateStatus`), its pass not re-run: the family learns it as from the
178
+ * pass's own throw. */ function familyStatus(e) {
179
+ if (e & STATUS_PENDING) wakeFamily(this); else if (e & STATUS_ERROR) errorFamily(this);
180
+ }
181
+
182
+ function forEachFamilyNode(e, t) {
183
+ for (const r of e.live) {
184
+ const e = r.n;
185
+ if (e !== null) for (const r of Reflect.ownKeys(e)) t(e[r]);
186
+ const o = r.h;
187
+ if (o !== null) for (const e of Reflect.ownKeys(o)) t(o[e]);
188
+ if (r.k !== null) t(r.k);
189
+ if (r.dk !== null) t(r.dk);
190
+ }
191
+ }
192
+
193
+ /** The derive's pass: run `fn` against a draft of the store; commit its
194
+ * result (sync, or each async landing) through the reconcile channel.
195
+ * Draft validity is per run (R37): live from here until the NEXT run starts
196
+ * — a sync derive that subscribes to an external source and pushes into
197
+ * the draft from the callback (#3585) is the model use. */ function runProjectionComputed(e, t, r, o, n) {
198
+ const i = getOwner();
199
+ const s = e[$TARGET];
200
+ const c = s.fam;
201
+ const a = c.run = (c.run || 0) + 1;
202
+ let u;
203
+ // Open loading window (seedLoadingValue): the observable store IS commit #0
204
+ // for the whole first flight — the derive works a detached shadow of the
205
+ // seed so draft writes cannot tear through to readers (#2988). Every
206
+ // commit point reconciles the shadow through the normal commit path.
207
+ const l = i.ce ? cloneState(s.v, s.s) : null;
208
+ // The question a write of this run answers: inside a slice, the slice's
209
+ // (the sync pass); in a continuation — the flight still registered — the
210
+ // flight's (`handleAsync` stamped it with the action that asked).
211
+ const asking = () => question || (i.T !== null && i.T.Ee !== null ? i.T.Ie : 0);
212
+ const f = wrapDraft(e, () => c.run === a && !isDisposed(i), n, s.s,
213
+ // A write after the run returned (a continuation, a callback) arms the
214
+ // drain itself when no landing will.
215
+ () => {
216
+ if (!(i.m & STATUS_PENDING) && !i.ce) schedule();
217
+ }, asking);
218
+ // The creation run commits directly (a memo's first value is its
219
+ // `_value`); every later run — a re-derive in a flush, an async landing
220
+ // — stages and commits with the flush like a memo's recompute.
221
+ const d = a === 1;
222
+ const pass = () => storeSetter(f, n => {
223
+ u = t(l ?? n);
224
+ const commit = (t, a = 1) => {
225
+ // Shadow run: commit a detached snapshot, never the shadow itself
226
+ // (adoption takes the value by identity — handing it the live
227
+ // shadow would fuse the draft to the observable store).
228
+ if (l && (t === undefined || t === l)) t = cloneState(l, s.s);
229
+ if (t !== n && t !== undefined) {
230
+ const write = () => {
231
+ const o = question;
232
+ setQuestion(asking());
233
+ try {
234
+ storeSetter(e, e => reconcileState(t, e, r, true), false);
235
+ } finally {
236
+ setQuestion(o);
237
+ }
238
+ };
239
+ o ? o(write, t) : write();
240
+ }
241
+ // A landing (not the sync pass's own commit): the readers held
242
+ // pending on the derive settle.
243
+ if (!d || !(i.m & STATUS_UNINITIALIZED)) settleFamily(c);
244
+ // A commit is the derive's change for the readers that observed its
245
+ // flight (linked by `pullFamily`; a settled pull does not link), as
246
+ // a memo's landing is for its readers: one that caught the NotReady
247
+ // (a fallback value, not pending) re-runs too (#4070). A pass of a
248
+ // settled derive has none (`wake` 0): a link left is a stale one a
249
+ // held frame keeps (A30), from a reader that re-ran since. Woken by
250
+ // every pass, a reader feeding a key the pass peeks at looped (#4342).
251
+ if (a) insertSubs(i);
252
+ };
253
+ const a = handleAsync(i, u, commit, (e, t) => {
254
+ // The flight rejected: the leaves' readers learn it from here —
255
+ // they do not subscribe to the derive. Pending again (a NotReady
256
+ // rejection): the wake, as for the pass. Errored: every live
257
+ // reader re-derives and meets the error at its pull (memo parity,
258
+ // #2897) — and the flush that runs them advances the clock, so a
259
+ // later tracked re-read may retry (core `read`).
260
+ if (d && i.m & STATUS_UNINITIALIZED) return;
261
+ if (t) wakeFamily(c); else errorFamily(c);
262
+ });
263
+ // (The status is the one before this pass: `recompute` sets it after.)
264
+ if (!i.ce) commit(a, i.m & (STATUS_PENDING | STATUS_ERROR));
265
+ }, false);
266
+ try {
267
+ d ? runDirect(pass) : pass();
268
+ } catch (e) {
269
+ // A flight went up (NotReady out of the pass — the derive's own, with
270
+ // the derive as its source): the leaves' readers learn it from here —
271
+ // they do not subscribe to the derive.
272
+ // A synchronous error the same way (#3956: a rerun that finds the
273
+ // entry failed throws): every live reader re-derives and meets it.
274
+ if (!d) e instanceof NotReadyError ? wakeFamily(c) : errorFamily(c);
275
+ throw e;
276
+ }
277
+ // A pass that returned with a flight up (an iterator's sync first yield):
278
+ // the wake, as for the throw. Not a sync pass that superseded one — the
279
+ // status it reads is the dead flight's, cleared when this pass settles
280
+ // (#3181: a reader the settle walk had just released, re-parked for good).
281
+ if (i.m & STATUS_PENDING && i.T.Ee !== null && !i.ce && !d) wakeFamily(c);
282
+ return i;
283
+ }
284
+
285
+ function createProjectionInternal(e, t, r) {
286
+ // Seedless (`fn` takes no draft): the root starts as an empty record. It is
287
+ // a draft like any seed, never observable before the first landing (A25).
288
+ t ||= {};
289
+ const o = r?.key === undefined ? "id" : r.key;
290
+ const n = {
291
+ map: new WeakMap,
292
+ node: null,
293
+ live: new Set,
294
+ st: familyStatus,
295
+ shallow: !!r?.shallow,
296
+ // The row key, for a child paired after the adoption (store.ts
297
+ // `adoptChild`, #3712) as the adoption pairs them.
298
+ key: typeof o === "function" ? o : o === null ? null : e => isWrappable(e) ? e[o] : undefined
299
+ };
300
+ const i = wrap(t, null, null, n);
301
+ if (n.shallow) {
302
+ i[$TARGET].s = true;
303
+ markRawIngest(t);
304
+ }
305
+ let s;
306
+ if (r?.seedLoadingValue) s = {
307
+ loadingValue: undefined
308
+ };
309
+ if (attrHooks !== null)
310
+ // As createStore: the owner in scope stamps the projection's property
311
+ // nodes, so attribution places them under it (#4035).
312
+ storeOwners.set(i[$TARGET], getOwner());
313
+ if (r?.name || r?.loc) {
314
+ s = {
315
+ ...s,
316
+ name: r.name,
317
+ loc: r.loc
318
+ };
319
+ nameStore(i, r.name, r.loc);
320
+ }
321
+ const c = computed(() => {
322
+ if (!n.node) n.node = getOwner();
323
+ runProjectionComputed(i, e, o);
324
+ }, s);
325
+ c.l &= ~CONFIG_AUTO_DISPOSE;
326
+ n.node = c;
327
+ // The derive's leaves are not its dependents: a mark's repoll
328
+ // (affects-marks.ts) reaches their readers through this.
329
+ c.fam = n;
330
+ return {
331
+ store: i,
332
+ node: c
333
+ };
334
+ }
335
+
336
+ function createProjection(e, t, r) {
337
+ return createProjectionInternal(e, t, r).store;
338
+ }
339
+
340
+ /** `createStore(fn, seed, options)`: a projection with a user setter. */ function createStoreDerived(e, t, r) {
341
+ const {store: o} = createProjectionInternal(e, t, r);
342
+ return [ o, e => storeSetter(o, e) ];
343
+ }
344
+
345
+ export { createProjection, createStoreDerived, runProjectionComputed };
@@ -0,0 +1,281 @@
1
+ import { isEqual } from "../core/core.js";
2
+
3
+ import { isOwned, $OWNER, storeLookup, lookupTarget } from "./target.js";
4
+
5
+ import { userWriting, unwrapValue, adoptPB, sameKey, materializePB, notifyFold, sameRow, targetsEqual, bumpDeep, notifyKeyValue, notifyKeyDiff, notifyFoldTail, hasAccessorFlag } from "./store.js";
6
+
7
+ import { optHooks } from "./hooks.js";
8
+
9
+ import { $TARGET, markRawIngest, isWrappable, rawValuesUsed, isRawValue } from "./types.js";
10
+
11
+ /**
12
+ * Store — reconcile: the immutable-diff adoption channel (INTERNALS §3).
13
+ *
14
+ * Reconcile never merge-writes into backing objects: it adopts `incoming`
15
+ * as the backing at every proxied level (an internal pointer swap at the
16
+ * fold — no clones, no user-object mutation), value-notifies only where
17
+ * nodes exist, and descends into a changed child pair only where a target
18
+ * with nodes or the sticky descendants flag exists below (§6d: diff the
19
+ * listened path, not every cell). Reference-equal unowned pairs skip
20
+ * outright (an owned backing is setter-diverged and must diff).
21
+ *
22
+ * Keyed arrays: the aligned prefix is walked positionally; from the first
23
+ * misalignment rows match by key (surviving rows keep their proxy
24
+ * identity), unkeyed items fall back to position.
25
+ */ function reconcileState(e, n, t, o = false) {
26
+ if (n == null) throw new Error("");
27
+ const f = n[$TARGET];
28
+ if (f?.px !== n) throw new Error("");
29
+ const i = t === null ? null : typeof t === "string" ? e => e?.[t] : t;
30
+ // A user's reconcile on an optimistic family (S4): not an adoption of
31
+ // truth but an optimistic edit — the keyed diff is written into the draft
32
+ // (a matched row keeps its proxy, its changed leaves become its guesses),
33
+ // and the setter's exit turns the draft into guesses like any.
34
+ if (optHooks && userWriting() && f.fam?.opt === true) {
35
+ optHooks.reconcile(n, unwrapValue(e), i);
36
+ return;
37
+ }
38
+ // Replace-mode root handed another store's proxy: chain to it (§7b).
39
+ if (o && e !== n && e?.[$TARGET] !== undefined) {
40
+ const n = f.pb ?? f.v;
41
+ if (n === e) return;
42
+ // already chained to this store
43
+ adoptPB(f, e);
44
+ return;
45
+ }
46
+ const l = unwrapValue(e);
47
+ if (i) {
48
+ const e = f.pb ?? f.v;
49
+ const n = i(e);
50
+ if (n !== undefined && !sameKey(i(l), n)) {
51
+ if (!o) throw new Error("");
52
+ // A different entity at the root: the old backing is disowned (wraps
53
+ // fresh if re-handed) and the new one adopted whole.
54
+ if (isOwned(e)) delete e[$OWNER]; else (f.fam?.map ?? storeLookup).delete(e);
55
+ adoptPB(f, l);
56
+ return;
57
+ }
58
+ }
59
+ applyAdopt(f, l, i, o);
60
+ }
61
+
62
+ /** Adopt `incoming` at `t` and notify its nodes — one leaf write per
63
+ * changed observed key, the structural nodes once — descending into
64
+ * changed child pairs that are proxied below. */ function applyAdopt(e, n, t, o = false) {
65
+ // The diff base is the view the nodes were last told (#3296). A nested
66
+ // overlay draft (`Object.create(v)`, #3044) reads a key the draft deleted
67
+ // as present through its prototype; materialized first — `adoptPB` does
68
+ // so anyway, after the base was taken — so a deletion the draft made is
69
+ // a deletion here (#3743: the presence and value diffs both read `old`).
70
+ const f = e.ovl ? materializePB(e) : e.pb ?? e.v;
71
+ if (n === f && !isOwned(f)) return;
72
+ // Q-D: a landing on an optimistic family is reconciled against the VIEW
73
+ // — key matching from the arrangement the guesses made (R28), so a row
74
+ // the guess added keeps its proxy when the server returns it.
75
+ const i = optHooks && e.fam?.opt === true ? optHooks.view(e, f) : f;
76
+ const l = Array.isArray(n);
77
+ const r = e.s === true;
78
+ adoptPB(e, n, false);
79
+ if (r) markRawIngest(n);
80
+ // The deep witness is bumped once per adoption (none to bump: done).
81
+ let u = e.dk === null;
82
+ // A live chained base (a store proxy, §7b) reads the inner store's
83
+ // current frame, not what the nodes were last told — nothing to diff
84
+ // against: the fold writes every node (#4361).
85
+ if (Array.isArray(i) !== l || f[$TARGET]) {
86
+ notifyFold(e, f, n);
87
+ return;
88
+ }
89
+ if (l) {
90
+ const l = e.n;
91
+ let s = 0;
92
+ if (t && !r) {
93
+ const r = i.length;
94
+ const a = n.length;
95
+ let c = 0;
96
+ // Aligned prefix: same row (by reference or key) at the same index.
97
+ for (const d = Math.min(r, a); c < d; c++) {
98
+ const r = n[c];
99
+ const a = i[c];
100
+ if (a !== r && !sameRow(a, r, t)) break;
101
+ // misaligned: fall to the keyed remainder below
102
+ if (r !== null && typeof r === "object" && (a !== r || isOwned(r))) descend(unwrapValue(a), r, t, o, e, c);
103
+ if (!u && !(r !== null && typeof r === "object" ? targetsEqual(a, r) : isEqual(a, r))) {
104
+ bumpDeep(e);
105
+ u = true;
106
+ }
107
+ if (l !== null) {
108
+ const e = l[c];
109
+ if (e !== undefined) {
110
+ s++;
111
+ notifyKeyValue(e, c, f[c], r, f, n);
112
+ }
113
+ }
114
+ }
115
+ if (!u && c < n.length) bumpDeep(e);
116
+ const d = c;
117
+ // misalignment point (== nlen on aligned ticks)
118
+ let p = null;
119
+ for (;c < n.length; c++) {
120
+ const r = n[c];
121
+ if (r !== null && typeof r === "object") {
122
+ const n = t(r);
123
+ let f;
124
+ if (n !== undefined) {
125
+ if (p === null) {
126
+ p = new Map;
127
+ for (let e = d; e < i.length; e++) {
128
+ const n = unwrapValue(i[e]);
129
+ if (n !== null && typeof n === "object") {
130
+ const o = t(n);
131
+ if (o === undefined) continue;
132
+ const f = p.get(o);
133
+ if (f === undefined) p.set(o, e); else if (Array.isArray(f)) f.push(e); else p.set(o, [ f, e ]);
134
+ }
135
+ }
136
+ }
137
+ const e = p.get(n);
138
+ if (e === undefined) f = undefined; else if (Array.isArray(e)) {
139
+ f = unwrapValue(i[e.shift()]);
140
+ if (e.length === 1) p.set(n, e[0]);
141
+ } else {
142
+ f = unwrapValue(i[e]);
143
+ p.delete(n);
144
+ }
145
+ } else {
146
+ f = unwrapValue(i[c]);
147
+ // keyless item: positional fallback
148
+ }
149
+ descend(f, r, t, o, e, c);
150
+ }
151
+ if (l !== null) {
152
+ const e = l[c];
153
+ if (e !== undefined) {
154
+ s++;
155
+ notifyKeyDiff(e, c, f, n, false);
156
+ }
157
+ }
158
+ }
159
+ } else {
160
+ const a = Math.min(i.length, n.length);
161
+ const c = n.length;
162
+ for (let d = 0; d < c; d++) {
163
+ const c = n[d];
164
+ if (!r && d < a && c !== null && typeof c === "object") descend(unwrapValue(i[d]), c, t, o, e, d);
165
+ if (!u && !(c !== null && typeof c === "object" ? targetsEqual(i[d], c) : isEqual(i[d], c))) {
166
+ bumpDeep(e);
167
+ u = true;
168
+ }
169
+ if (l !== null) {
170
+ const e = l[d];
171
+ if (e !== undefined) {
172
+ s++;
173
+ notifyKeyDiff(e, d, f, n, false);
174
+ }
175
+ }
176
+ }
177
+ }
178
+ // Indices past the new length (and `length` itself) still have nodes.
179
+ if (l !== null && s < e.nc) {
180
+ for (const e of Reflect.ownKeys(l)) {
181
+ const t = typeof e === "string" ? +e : NaN;
182
+ if (!(t >= 0 && t < n.length)) notifyKeyDiff(l[e], e, f, n, false);
183
+ }
184
+ }
185
+ notifyFoldTail(e, f, n);
186
+ return;
187
+ }
188
+ const s = e.n;
189
+ let a = 0;
190
+ for (const l in n) {
191
+ const c = n[l];
192
+ let d = f[l];
193
+ // A key under a guess is judged against the guess too (D-34): a truth
194
+ // equal to the value the guess covered still answers it.
195
+ if (optHooks && d === c && i !== f) d = i[l];
196
+ const p = c !== null && typeof c === "object";
197
+ if (d === c && (!p || !isOwned(c)) && (s === null || s[l] === undefined || !hasAccessorFlag(s[l]))) {
198
+ if (s?.[l] !== undefined) a++;
199
+ continue;
200
+ }
201
+ if (p && !r) descend(unwrapValue(i[l]), c, t, o, e, l);
202
+ if (!u && !(p ? targetsEqual(d, c) : isEqual(d, c))) {
203
+ bumpDeep(e);
204
+ u = true;
205
+ }
206
+ if (s !== null) {
207
+ const e = s[l];
208
+ if (e !== undefined) {
209
+ a++;
210
+ notifyKeyValue(e, l, d, c, f, n);
211
+ }
212
+ }
213
+ }
214
+ const c = Object.getOwnPropertySymbols(n);
215
+ for (let i = 0; i < c.length; i++) {
216
+ const l = c[i];
217
+ if (l === $OWNER) continue;
218
+ const u = n[l];
219
+ if (!r && u !== null && typeof u === "object") descend(unwrapValue(f[l]), u, t, o, e, l);
220
+ if (s !== null) {
221
+ const e = s[l];
222
+ if (e !== undefined) {
223
+ a++;
224
+ notifyKeyValue(e, l, f[l], u, f, n);
225
+ }
226
+ }
227
+ }
228
+ // Keys the incoming object no longer has still have nodes.
229
+ if (s !== null && a < e.nc) {
230
+ for (const e of Reflect.ownKeys(s)) {
231
+ if (!hasOwnP.call(n, e)) notifyKeyDiff(s[e], e, f, n, false);
232
+ }
233
+ }
234
+ notifyFoldTail(e, f, n);
235
+ }
236
+
237
+ const hasOwnP = Object.prototype.hasOwnProperty;
238
+
239
+ /** Descend into a changed child pair — only where something is proxied
240
+ * below (§6d), never into a raw-marked leaf, never across array/object or a
241
+ * key mismatch (that is a replacement, handled by the parent's slot).
242
+ *
243
+ * A raw in both frames (the same objects swapped, reordered or shifted,
244
+ * #4001) must not leave two slots on one row. A raw already a live row keeps
245
+ * it at the slot it moved to; a row's `pk` follows the slot it sits at (a
246
+ * move or a pairing writes it), so a row whose raw is at that slot of the
247
+ * incoming frame is spoken for and not paired again here; a raw still
248
+ * resolving to a row that moved on drops the lookup (it wraps fresh, or is
249
+ * paired here). One lookup of `nv` on the common path, no allocation. */ function descend(e, n, t, o, f, i) {
250
+ // `nv` is an object at every call site.
251
+ if (e === null || typeof e !== "object") return;
252
+ const l = f.fam;
253
+ n = unwrapValue(n);
254
+ let r = lookupTarget(e, l);
255
+ const u = lookupTarget(n, l);
256
+ if (r !== undefined && r.pk !== i) {
257
+ if (r.pk != i && f.v[r.pk] === r.v) r = undefined; else if (r.u === f) r.pk = i;
258
+ }
259
+ if (u !== undefined && u !== r) {
260
+ if (u.v === n) {
261
+ if (u.u === f) u.pk = i;
262
+ return;
263
+ }
264
+ (l?.map ?? storeLookup).delete(n);
265
+ }
266
+ if (r === undefined) return;
267
+ // nothing proxied below this pair
268
+ if (!isWrappable(n)) return;
269
+ if (rawValuesUsed && isRawValue(n)) return;
270
+ if (Array.isArray(e) !== Array.isArray(n)) return;
271
+ // An array slot was paired by key already (or both rows are keyless).
272
+ if (typeof i !== "number" && t) {
273
+ const o = t(e);
274
+ const f = t(n);
275
+ if (o !== undefined && f !== undefined && !sameKey(o, f)) return;
276
+ }
277
+ if (!o && t !== null && !r.d) return;
278
+ applyAdopt(r, n, t, o);
279
+ }
280
+
281
+ export { reconcileState };