@solidjs/signals 2.0.0-rc.2 → 2.0.0-rc.4
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.
- package/dist/dev.js +1454 -118
- package/dist/node.cjs +2709 -1396
- package/dist/prod/affects.js +13 -12
- package/dist/prod/boundaries.js +39 -34
- package/dist/prod/core/action.js +3 -3
- package/dist/prod/core/async.js +48 -46
- package/dist/prod/core/core.js +99 -67
- package/dist/prod/core/effect.js +25 -28
- package/dist/prod/core/external.js +2 -2
- package/dist/prod/core/graph.js +85 -49
- package/dist/prod/core/heap.js +10 -10
- package/dist/prod/core/lanes.js +19 -19
- package/dist/prod/core/optimistic.js +66 -41
- package/dist/prod/core/owner.js +13 -13
- package/dist/prod/core/scheduler.js +131 -85
- package/dist/prod/core/verdict.js +36 -15
- package/dist/prod/index.js +4 -0
- package/dist/prod/map.js +101 -101
- package/dist/prod/signals.js +1 -1
- package/dist/prod/store/index.js +2 -0
- package/dist/prod/store/next/optimistic.js +65 -11
- package/dist/prod/store/next/patch-hooks.js +13 -0
- package/dist/prod/store/next/patch.js +614 -0
- package/dist/prod/store/next/projection.js +107 -45
- package/dist/prod/store/next/reconcile.js +307 -120
- package/dist/prod/store/next/store.js +321 -92
- package/dist/prod/store/next/target.js +13 -4
- package/dist/prod/store/store.js +5 -5
- package/dist/types/core/core.d.ts +15 -1
- package/dist/types/core/dev.d.ts +8 -0
- package/dist/types/core/graph.d.ts +22 -0
- package/dist/types/core/invariants.d.ts +1 -1
- package/dist/types/core/scheduler.d.ts +12 -0
- package/dist/types/store/index.d.ts +2 -0
- package/dist/types/store/next/patch-hooks.d.ts +41 -0
- package/dist/types/store/next/patch.d.ts +91 -0
- package/dist/types/store/next/reconcile.d.ts +14 -0
- package/dist/types/store/next/store.d.ts +30 -2
- package/dist/types/store/next/target.d.ts +58 -8
- package/dist/types-cjs/core/core.d.cts +15 -1
- package/dist/types-cjs/core/dev.d.cts +8 -0
- package/dist/types-cjs/core/graph.d.cts +22 -0
- package/dist/types-cjs/core/invariants.d.cts +1 -1
- package/dist/types-cjs/core/scheduler.d.cts +12 -0
- package/dist/types-cjs/store/index.d.cts +2 -0
- package/dist/types-cjs/store/next/patch-hooks.d.cts +41 -0
- package/dist/types-cjs/store/next/patch.d.cts +91 -0
- package/dist/types-cjs/store/next/reconcile.d.cts +14 -0
- package/dist/types-cjs/store/next/store.d.cts +30 -2
- package/dist/types-cjs/store/next/target.d.cts +58 -8
- package/package.json +14 -14
- package/dist/types/store/optimistic.d.ts +0 -45
- package/dist/types/store/projection.d.ts +0 -70
- package/dist/types/store/reconcile.d.ts +0 -46
- package/dist/types-cjs/store/optimistic.d.cts +0 -45
- package/dist/types-cjs/store/projection.d.cts +0 -70
- package/dist/types-cjs/store/reconcile.d.cts +0 -46
package/dist/prod/map.js
CHANGED
|
@@ -23,23 +23,23 @@ function mapArray(t, s, i) {
|
|
|
23
23
|
const r = s.length > 1;
|
|
24
24
|
const n = s;
|
|
25
25
|
const h = {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
qt: [],
|
|
26
|
+
Wt: createOwner(),
|
|
27
|
+
xt: 0,
|
|
28
|
+
Kt: t,
|
|
29
|
+
$t: [],
|
|
30
|
+
qt: n,
|
|
32
31
|
zt: [],
|
|
33
|
-
Jt:
|
|
34
|
-
Xt: e
|
|
35
|
-
Yt:
|
|
36
|
-
Zt: i?.keyed
|
|
37
|
-
ts: i?.
|
|
32
|
+
Jt: [],
|
|
33
|
+
Xt: e,
|
|
34
|
+
Yt: e || i?.keyed === false ? [] : undefined,
|
|
35
|
+
Zt: r && i?.keyed !== false ? [] : undefined,
|
|
36
|
+
ts: i?.keyed === false,
|
|
37
|
+
ss: i?.fallback
|
|
38
38
|
};
|
|
39
39
|
const o = computed(updateKeyedMap.bind(h));
|
|
40
40
|
// Untracked reads inside the internal owner resolve via _parentComputed; routing
|
|
41
41
|
// them through node lets store-proxy lookups see pending writes (not stale _value).
|
|
42
|
-
h.
|
|
42
|
+
h.Wt.Ot = o;
|
|
43
43
|
o.T &= ~CONFIG_AUTO_DISPOSE;
|
|
44
44
|
return accessor(o);
|
|
45
45
|
}
|
|
@@ -58,52 +58,52 @@ const pureOptions = {
|
|
|
58
58
|
// strong-abort ordering: removed rows now dispose AFTER the pass's new rows
|
|
59
59
|
// are created (you cannot destroy state before knowing the pass will land).
|
|
60
60
|
function updateKeyedMap() {
|
|
61
|
-
const t = this.
|
|
61
|
+
const t = this.Kt() || [], s = t.length;
|
|
62
62
|
t[$TRACK];
|
|
63
63
|
// top level tracking
|
|
64
|
-
runWithOwner(this.
|
|
64
|
+
runWithOwner(this.Wt, () => {
|
|
65
65
|
let i, e, r, n,
|
|
66
66
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
67
67
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
68
|
-
h = this.
|
|
68
|
+
h = this.Yt ? this.ts ? () => {
|
|
69
69
|
r[e] = signal(t[e], pureOptions);
|
|
70
|
-
return this
|
|
70
|
+
return this.qt(accessor(r[e]), e);
|
|
71
71
|
} : () => {
|
|
72
72
|
r[e] = signal(t[e], pureOptions);
|
|
73
73
|
n && (n[e] = signal(e, pureOptions));
|
|
74
|
-
return this
|
|
75
|
-
} : this.
|
|
74
|
+
return this.qt(accessor(r[e]), n ? accessor(n[e]) : undefined);
|
|
75
|
+
} : this.Zt ? () => {
|
|
76
76
|
const s = t[e];
|
|
77
77
|
n[e] = signal(e, pureOptions);
|
|
78
|
-
return this
|
|
78
|
+
return this.qt(s, accessor(n[e]));
|
|
79
79
|
} : () => {
|
|
80
80
|
const s = t[e];
|
|
81
|
-
return this
|
|
81
|
+
return this.qt(s);
|
|
82
82
|
};
|
|
83
83
|
// fast path for empty arrays
|
|
84
84
|
if (s === 0) {
|
|
85
|
-
if (this.
|
|
86
|
-
this.
|
|
85
|
+
if (this.xt !== 0) {
|
|
86
|
+
this.Wt.dispose(false);
|
|
87
|
+
this.Jt = [];
|
|
88
|
+
this.$t = [];
|
|
87
89
|
this.zt = [];
|
|
88
|
-
this.
|
|
89
|
-
this.qt = [];
|
|
90
|
-
this.Wt = 0;
|
|
91
|
-
this.Xt && (this.Xt = []);
|
|
90
|
+
this.xt = 0;
|
|
92
91
|
this.Yt && (this.Yt = []);
|
|
92
|
+
this.Zt && (this.Zt = []);
|
|
93
93
|
}
|
|
94
|
-
if (this.
|
|
94
|
+
if (this.ss && !this.zt[0]) {
|
|
95
95
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
96
96
|
// dispose it before re-creating
|
|
97
|
-
this.
|
|
98
|
-
this.
|
|
97
|
+
this.Jt[0]?.dispose();
|
|
98
|
+
this.zt[0] = runWithOwner(this.Jt[0] = createOwner(), this.ss);
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
// fast path for new create
|
|
102
|
-
else if (this.
|
|
102
|
+
else if (this.xt === 0) {
|
|
103
103
|
const o = new Array(s);
|
|
104
104
|
const c = new Array(s);
|
|
105
|
-
r = this.
|
|
106
|
-
n = this.
|
|
105
|
+
r = this.Yt && new Array(s);
|
|
106
|
+
n = this.Zt && new Array(s);
|
|
107
107
|
try {
|
|
108
108
|
for (e = 0; e < s; e++) o[e] = runWithOwner(c[e] = createOwner(), h);
|
|
109
109
|
} catch (t) {
|
|
@@ -111,43 +111,43 @@ function updateKeyedMap() {
|
|
|
111
111
|
throw t;
|
|
112
112
|
}
|
|
113
113
|
// commit
|
|
114
|
-
if (this.
|
|
114
|
+
if (this.Jt[0]) this.Jt[0].dispose();
|
|
115
115
|
// previous fallback
|
|
116
|
-
this.
|
|
117
|
-
this.
|
|
118
|
-
r && (this.
|
|
119
|
-
n && (this.
|
|
120
|
-
this
|
|
121
|
-
this.
|
|
116
|
+
this.zt = o;
|
|
117
|
+
this.Jt = c;
|
|
118
|
+
r && (this.Yt = r);
|
|
119
|
+
n && (this.Zt = n);
|
|
120
|
+
this.$t = t.slice(0);
|
|
121
|
+
this.xt = s;
|
|
122
122
|
} else {
|
|
123
123
|
let o, c, a, f, u, p, w, l, d;
|
|
124
124
|
// skip common prefix
|
|
125
|
-
for (o = 0, c = Math.min(this.
|
|
126
|
-
if (this.
|
|
125
|
+
for (o = 0, c = Math.min(this.xt, s); o < c && (this.$t[o] === t[o] || this.Yt && compare(this.Xt, this.$t[o], t[o])); o++) {
|
|
126
|
+
if (this.Yt) setSignal(this.Yt[o], t[o]);
|
|
127
127
|
}
|
|
128
128
|
// skip common suffix — counted only; retained entries land in one pass
|
|
129
129
|
// at commit instead of being staged and copied twice
|
|
130
|
-
for (c = this.
|
|
130
|
+
for (c = this.xt - 1, a = s - 1; c >= o && a >= o && (this.$t[c] === t[a] || this.Yt && compare(this.Xt, this.$t[c], t[a])); c--,
|
|
131
131
|
a--) ;
|
|
132
132
|
// no structural change (every position matched in place at equal
|
|
133
133
|
// length — the common post-reconcile shape): keep the same mapped
|
|
134
134
|
// array identity so downstream consumers don't re-run at all
|
|
135
|
-
if (o === s && this.
|
|
136
|
-
this
|
|
135
|
+
if (o === s && this.xt === s) {
|
|
136
|
+
this.$t = t.slice(0);
|
|
137
137
|
return;
|
|
138
138
|
}
|
|
139
|
-
const O = s - this.
|
|
139
|
+
const O = s - this.xt;
|
|
140
140
|
const m = new Array(s);
|
|
141
141
|
const _ = new Array(s);
|
|
142
|
-
r = this.
|
|
143
|
-
n = this.
|
|
142
|
+
r = this.Yt ? new Array(s) : undefined;
|
|
143
|
+
n = this.Zt ? new Array(s) : undefined;
|
|
144
144
|
// 0) prepare a map of all indices in the changed window of newItems,
|
|
145
145
|
// scanning backwards so we encounter them in natural order
|
|
146
146
|
p = new Map;
|
|
147
147
|
w = new Array(a + 1);
|
|
148
148
|
for (e = a; e >= o; e--) {
|
|
149
149
|
f = t[e];
|
|
150
|
-
u = this.
|
|
150
|
+
u = this.Xt ? this.Xt(f) : f;
|
|
151
151
|
i = p.get(u);
|
|
152
152
|
w[e] = i === undefined ? -1 : i;
|
|
153
153
|
p.set(u, e);
|
|
@@ -156,17 +156,17 @@ function updateKeyedMap() {
|
|
|
156
156
|
// in the new set; if so, stage them at their new positions; if not,
|
|
157
157
|
// queue them for disposal at commit
|
|
158
158
|
for (i = o; i <= c; i++) {
|
|
159
|
-
f = this
|
|
160
|
-
u = this.
|
|
159
|
+
f = this.$t[i];
|
|
160
|
+
u = this.Xt ? this.Xt(f) : f;
|
|
161
161
|
e = p.get(u);
|
|
162
162
|
if (e !== undefined && e !== -1) {
|
|
163
|
-
m[e] = this.
|
|
164
|
-
_[e] = this.
|
|
165
|
-
r && (r[e] = this.
|
|
166
|
-
n && (n[e] = this.
|
|
163
|
+
m[e] = this.zt[i];
|
|
164
|
+
_[e] = this.Jt[i];
|
|
165
|
+
r && (r[e] = this.Yt[i]);
|
|
166
|
+
n && (n[e] = this.Zt[i]);
|
|
167
167
|
e = w[e];
|
|
168
168
|
p.set(u, e);
|
|
169
|
-
} else (l ??= []).push(this.
|
|
169
|
+
} else (l ??= []).push(this.Jt[i]);
|
|
170
170
|
}
|
|
171
171
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
172
172
|
try {
|
|
@@ -183,38 +183,38 @@ function updateKeyedMap() {
|
|
|
183
183
|
// into the fresh arrays, swap them in (new identity for downstream
|
|
184
184
|
// change propagation), then dispose exited rows
|
|
185
185
|
for (i = 0; i < o; i++) {
|
|
186
|
-
m[i] = this.
|
|
187
|
-
_[i] = this.
|
|
188
|
-
r && (r[i] = this.
|
|
189
|
-
n && (n[i] = this.
|
|
186
|
+
m[i] = this.zt[i];
|
|
187
|
+
_[i] = this.Jt[i];
|
|
188
|
+
r && (r[i] = this.Yt[i]);
|
|
189
|
+
n && (n[i] = this.Zt[i]);
|
|
190
190
|
}
|
|
191
191
|
for (e = o; e <= a; e++) {
|
|
192
192
|
if (r) setSignal(r[e], t[e]);
|
|
193
193
|
if (n) setSignal(n[e], e);
|
|
194
194
|
}
|
|
195
195
|
for (e = a + 1; e < s; e++) {
|
|
196
|
-
m[e] = this.
|
|
197
|
-
_[e] = this.
|
|
196
|
+
m[e] = this.zt[e - O];
|
|
197
|
+
_[e] = this.Jt[e - O];
|
|
198
198
|
if (r) {
|
|
199
|
-
r[e] = this.
|
|
199
|
+
r[e] = this.Yt[e - O];
|
|
200
200
|
setSignal(r[e], t[e]);
|
|
201
201
|
}
|
|
202
202
|
if (n) {
|
|
203
|
-
n[e] = this.
|
|
203
|
+
n[e] = this.Zt[e - O];
|
|
204
204
|
if (O !== 0) setSignal(n[e], e);
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
|
-
this.
|
|
208
|
-
this.
|
|
209
|
-
r && (this.
|
|
210
|
-
n && (this.
|
|
211
|
-
this.
|
|
207
|
+
this.zt = m;
|
|
208
|
+
this.Jt = _;
|
|
209
|
+
r && (this.Yt = r);
|
|
210
|
+
n && (this.Zt = n);
|
|
211
|
+
this.xt = s;
|
|
212
212
|
// save a copy of the mapped items for the next update
|
|
213
|
-
this
|
|
213
|
+
this.$t = t.slice(0);
|
|
214
214
|
if (l) for (i = 0; i < l.length; i++) l[i].dispose();
|
|
215
215
|
}
|
|
216
216
|
});
|
|
217
|
-
return this.
|
|
217
|
+
return this.zt;
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
/**
|
|
@@ -234,21 +234,21 @@ function updateKeyedMap() {
|
|
|
234
234
|
*/ function repeat(t, s, i) {
|
|
235
235
|
const e = s;
|
|
236
236
|
const r = {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
237
|
+
Wt: createOwner(),
|
|
238
|
+
xt: 0,
|
|
239
|
+
es: 0,
|
|
240
|
+
rs: t,
|
|
241
|
+
qt: e,
|
|
242
|
+
Jt: [],
|
|
242
243
|
zt: [],
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
ts: i?.fallback
|
|
244
|
+
ns: i?.from,
|
|
245
|
+
ss: i?.fallback
|
|
246
246
|
};
|
|
247
247
|
const n = computed(updateRepeat.bind(r));
|
|
248
248
|
// Same as mapArray: untracked reads inside the internal owner resolve via
|
|
249
249
|
// _parentComputed, so async reads in row callbacks register with the node
|
|
250
250
|
// (pending tracking + post-settle retry) instead of vanishing.
|
|
251
|
-
r.
|
|
251
|
+
r.Wt.Ot = n;
|
|
252
252
|
n.T &= ~CONFIG_AUTO_DISPOSE;
|
|
253
253
|
return accessor(n);
|
|
254
254
|
}
|
|
@@ -261,55 +261,55 @@ function updateKeyedMap() {
|
|
|
261
261
|
// for the post-settle retry. The overlap math also subsumes the previous
|
|
262
262
|
// disjoint-window/front-clear/end-clear/shift special cases.
|
|
263
263
|
function updateRepeat() {
|
|
264
|
-
const t = this.
|
|
265
|
-
const s = this.
|
|
266
|
-
runWithOwner(this.
|
|
264
|
+
const t = this.rs();
|
|
265
|
+
const s = this.ns?.() || 0;
|
|
266
|
+
runWithOwner(this.Wt, () => {
|
|
267
267
|
if (t === 0) {
|
|
268
|
-
if (this.
|
|
269
|
-
this.
|
|
268
|
+
if (this.xt !== 0) {
|
|
269
|
+
this.Wt.dispose(false);
|
|
270
|
+
this.Jt = [];
|
|
270
271
|
this.zt = [];
|
|
271
|
-
this.
|
|
272
|
-
this.Wt = 0;
|
|
272
|
+
this.xt = 0;
|
|
273
273
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
274
|
-
this.
|
|
274
|
+
this.es = 0;
|
|
275
275
|
}
|
|
276
|
-
if (this.
|
|
276
|
+
if (this.ss && !this.zt[0]) {
|
|
277
277
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
278
278
|
// dispose it before re-creating
|
|
279
|
-
this.
|
|
280
|
-
this.
|
|
279
|
+
this.Jt[0]?.dispose();
|
|
280
|
+
this.zt[0] = runWithOwner(this.Jt[0] = createOwner(), this.ss);
|
|
281
281
|
}
|
|
282
282
|
return;
|
|
283
283
|
}
|
|
284
284
|
const i = s + t;
|
|
285
|
-
const e = this.
|
|
285
|
+
const e = this.es + this.xt;
|
|
286
286
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
287
287
|
// windows are disjoint or when coming from empty/fallback.
|
|
288
|
-
const r = Math.max(s, this.
|
|
288
|
+
const r = Math.max(s, this.es);
|
|
289
289
|
const n = Math.min(i, e);
|
|
290
290
|
const h = new Array(t);
|
|
291
291
|
const o = new Array(t);
|
|
292
292
|
for (let t = r; t < n; t++) {
|
|
293
|
-
o[t - s] = this.
|
|
294
|
-
h[t - s] = this.
|
|
293
|
+
o[t - s] = this.Jt[t - this.es];
|
|
294
|
+
h[t - s] = this.zt[t - this.es];
|
|
295
295
|
}
|
|
296
296
|
try {
|
|
297
297
|
for (let t = s; t < i; t++) {
|
|
298
298
|
if (t >= r && t < n) continue;
|
|
299
|
-
h[t - s] = runWithOwner(o[t - s] = createOwner(), () => this
|
|
299
|
+
h[t - s] = runWithOwner(o[t - s] = createOwner(), () => this.qt(t));
|
|
300
300
|
}
|
|
301
301
|
} catch (t) {
|
|
302
302
|
for (let t = s; t < i; t++) if ((t < r || t >= n) && o[t - s]) o[t - s].dispose();
|
|
303
303
|
throw t;
|
|
304
304
|
}
|
|
305
305
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
306
|
-
if (this.
|
|
307
|
-
this.
|
|
308
|
-
this.
|
|
309
|
-
this.
|
|
310
|
-
this.
|
|
306
|
+
if (this.xt === 0) this.Jt[0]?.dispose(); else for (let t = this.es; t < e; t++) if (t < s || t >= i) this.Jt[t - this.es].dispose();
|
|
307
|
+
this.zt = h;
|
|
308
|
+
this.Jt = o;
|
|
309
|
+
this.es = s;
|
|
310
|
+
this.xt = t;
|
|
311
311
|
});
|
|
312
|
-
return this.
|
|
312
|
+
return this.zt;
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
function compare(t, s, i) {
|
package/dist/prod/signals.js
CHANGED
|
@@ -251,7 +251,7 @@ function createEffect(e, t, n) {
|
|
|
251
251
|
// route through the inherited queue.
|
|
252
252
|
const r = getOwner();
|
|
253
253
|
const o = new MicrotaskQueue;
|
|
254
|
-
o.
|
|
254
|
+
o.ke = r.C;
|
|
255
255
|
// notify() forwards up the normal chain
|
|
256
256
|
r.C = o;
|
|
257
257
|
// A user effect rather than a bare computed: computeds are pull-based and
|
package/dist/prod/store/index.js
CHANGED
|
@@ -10,6 +10,8 @@ import "../core/effect.js";
|
|
|
10
10
|
|
|
11
11
|
import { createStoreNext, deepNext, snapshotNext } from "./next/store.js";
|
|
12
12
|
|
|
13
|
+
export { storeHasFamily, storeHasOptimisticFamily, storeIsShallow } from "./next/store.js";
|
|
14
|
+
|
|
13
15
|
import { reconcileNextState } from "./next/reconcile.js";
|
|
14
16
|
|
|
15
17
|
import { createStoreDerivedNext } from "./next/projection.js";
|
|
@@ -18,6 +18,10 @@ import { runProjectionComputedNext } from "./projection.js";
|
|
|
18
18
|
|
|
19
19
|
import { wrapNext, runAuthoritative, storeSetterNext, hasActiveOverride, unwrapValue, getNode, getHasNode, targetsEqual, getKeySetNode, bumpDeep } from "./store.js";
|
|
20
20
|
|
|
21
|
+
import { patchHooks, rowHooks } from "./patch-hooks.js";
|
|
22
|
+
|
|
23
|
+
import { buildIdentityRowOps, sameKey } from "./reconcile.js";
|
|
24
|
+
|
|
21
25
|
import { setOptHooks } from "./target.js";
|
|
22
26
|
|
|
23
27
|
/**
|
|
@@ -51,14 +55,31 @@ function installNextBlockedHalf() {
|
|
|
51
55
|
// Scheduler flush tails call _clearOptimisticStores whenever tracked
|
|
52
56
|
// stores exist; next has no layer to clear — reverts are engine-native —
|
|
53
57
|
// so the hook only empties the batch set.
|
|
54
|
-
if (!GlobalQueue.
|
|
55
|
-
GlobalQueue.
|
|
58
|
+
if (!GlobalQueue.Bt) {
|
|
59
|
+
GlobalQueue.Bt = e => {
|
|
60
|
+
// Patch channel (revert site): engine-native reverts flip node values
|
|
61
|
+
// back to committed; patched records need a forced DOM re-apply from
|
|
62
|
+
// the post-revert view. Emission only — next keeps no layer to clear.
|
|
63
|
+
for (const t of e) {
|
|
64
|
+
const e = t?.[$TARGET];
|
|
65
|
+
const n = e?.fam?.overlaid;
|
|
66
|
+
if (n !== undefined) {
|
|
67
|
+
for (const e of n) {
|
|
68
|
+
if (e.pc !== null && e.pc.p !== null) patchHooks.emitPatchOptimistic(e, null, null);
|
|
69
|
+
// Row-ops resync (family increment 2): reverts flip node values
|
|
70
|
+
// back engine-natively; a driven list must rebuild retention by
|
|
71
|
+
// row identity against the post-revert view (resolved from the
|
|
72
|
+
// target at drain — overrides are gone by then).
|
|
73
|
+
if (e.pc !== null && e.pc.ro !== null) rowHooks.emitRowOpsOptimistic(e, null, null);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
56
77
|
e.clear();
|
|
57
78
|
};
|
|
58
79
|
}
|
|
59
|
-
const e = GlobalQueue.
|
|
60
|
-
GlobalQueue.
|
|
61
|
-
for (const e of t.
|
|
80
|
+
const e = GlobalQueue.In;
|
|
81
|
+
GlobalQueue.In = t => {
|
|
82
|
+
for (const e of t.Tn) {
|
|
62
83
|
const t = e?.[$TARGET];
|
|
63
84
|
const n = t?.fam?.node;
|
|
64
85
|
// The hold exists to keep optimistic state alive until the store's own
|
|
@@ -148,6 +169,21 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
148
169
|
const n = e.fam?.node;
|
|
149
170
|
if (n?._e) globalQueue.initTransition(n._e);
|
|
150
171
|
const i = e.v;
|
|
172
|
+
// Patch channel (override-application site): the draft IS the intended
|
|
173
|
+
// visible state; prev is the view before these overrides apply. Bypasses
|
|
174
|
+
// the transition stash — optimism is visible in flight.
|
|
175
|
+
if (e.pc !== null && e.pc.p !== null) patchHooks.emitPatchOptimistic(e, t, optimisticView(e, i));
|
|
176
|
+
// Row-ops channel (family increment 2): optimistic STRUCTURE on an array
|
|
177
|
+
// rides node overrides — it never enters the reconcile walk — so a driven
|
|
178
|
+
// list must get its structural ops here, lane-timed. Identity diff of the
|
|
179
|
+
// pre-write optimistic view against the draft; aligned writes emit nothing.
|
|
180
|
+
if (e.pc !== null && e.pc.ro !== null && Array.isArray(t)) {
|
|
181
|
+
const n = optimisticView(e, i);
|
|
182
|
+
if (Array.isArray(n)) {
|
|
183
|
+
const i = buildIdentityRowOps(n, t);
|
|
184
|
+
if (i !== null) rowHooks.emitRowOpsOptimistic(e, t, i);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
151
187
|
const visible = (t, n) => {
|
|
152
188
|
const i = e.n?.[t];
|
|
153
189
|
return i !== undefined && hasActiveOverride(i) ? unwrapOverride(i.o?.De) : n;
|
|
@@ -198,7 +234,7 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
198
234
|
// and the target for landing consumption (RUL-2).
|
|
199
235
|
e.pb = null;
|
|
200
236
|
(e.fam.overlaid ??= new Set).add(e);
|
|
201
|
-
GlobalQueue.
|
|
237
|
+
GlobalQueue.An?.(e.fam.px ?? e.px);
|
|
202
238
|
}
|
|
203
239
|
|
|
204
240
|
/**
|
|
@@ -223,7 +259,7 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
223
259
|
e.T |= CONFIG_OPTIMISTIC;
|
|
224
260
|
const i = e.o;
|
|
225
261
|
if (i) {
|
|
226
|
-
i.
|
|
262
|
+
i.Nt = null;
|
|
227
263
|
i.Be = undefined;
|
|
228
264
|
}
|
|
229
265
|
e.Pe = NOT_PENDING;
|
|
@@ -264,12 +300,16 @@ function createOptimisticStoreNext(e, t, n) {
|
|
|
264
300
|
e.k.T |= CONFIG_OPTIMISTIC;
|
|
265
301
|
const t = e.k.o;
|
|
266
302
|
if (t) {
|
|
267
|
-
t.
|
|
303
|
+
t.Nt = null;
|
|
268
304
|
t.Be = undefined;
|
|
269
305
|
}
|
|
270
306
|
insertSubs(e.k, true);
|
|
271
307
|
schedule();
|
|
272
308
|
}
|
|
309
|
+
// Patch channel (override-consumption site): visible truth flipped to
|
|
310
|
+
// committed for the consumed keys — force a re-apply from the live
|
|
311
|
+
// view so the DOM leaves the override state.
|
|
312
|
+
if (e.pc !== null && e.pc.p !== null) patchHooks.emitPatchOptimistic(e, null, null);
|
|
273
313
|
}
|
|
274
314
|
t.clear();
|
|
275
315
|
});
|
|
@@ -322,7 +362,9 @@ function applyTentative(e, t, n) {
|
|
|
322
362
|
if (n) {
|
|
323
363
|
const i = n(e);
|
|
324
364
|
const o = n(t);
|
|
325
|
-
|
|
365
|
+
// SameValueZero (re-audit 3, P1-3): parity with the plain reconcile
|
|
366
|
+
// channel — NaN keys are self-equal.
|
|
367
|
+
if (i !== undefined && o !== undefined && !sameKey(i, o)) return null;
|
|
326
368
|
}
|
|
327
369
|
return r.get(unwrapValue(e)) ?? null;
|
|
328
370
|
};
|
|
@@ -337,16 +379,28 @@ function applyTentative(e, t, n) {
|
|
|
337
379
|
const t = n(r);
|
|
338
380
|
if (t !== undefined) {
|
|
339
381
|
if (i === null) {
|
|
382
|
+
// Occurrence-aware index queues (re-audit 3, P1-3): parity with
|
|
383
|
+
// the plain adoption window — duplicate keys match per
|
|
384
|
+
// occurrence, each view row consumed once.
|
|
340
385
|
i = new Map;
|
|
341
386
|
for (let t = 0; t < e.length; t++) {
|
|
342
387
|
const o = unwrapValue(e[t]);
|
|
343
388
|
if (isWrappable(o)) {
|
|
344
389
|
const e = n(o);
|
|
345
|
-
if (e
|
|
390
|
+
if (e === undefined) continue;
|
|
391
|
+
const r = i.get(e);
|
|
392
|
+
if (r === undefined) i.set(e, t); else if (Array.isArray(r)) r.push(t); else i.set(e, [ r, t ]);
|
|
346
393
|
}
|
|
347
394
|
}
|
|
348
395
|
}
|
|
349
|
-
|
|
396
|
+
const o = i.get(t);
|
|
397
|
+
if (o === undefined) s = undefined; else if (Array.isArray(o)) {
|
|
398
|
+
s = unwrapValue(e[o.shift()]);
|
|
399
|
+
if (o.length === 1) i.set(t, o[0]);
|
|
400
|
+
} else {
|
|
401
|
+
s = unwrapValue(e[o]);
|
|
402
|
+
i.delete(t);
|
|
403
|
+
}
|
|
350
404
|
} else s = unwrapValue(e[o]);
|
|
351
405
|
} else s = unwrapValue(e[o]);
|
|
352
406
|
const c = match(s, r);
|