@solidjs/signals 2.0.0-rc.16 → 2.0.0-rc.18
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-shared.js +1972 -1751
- package/dist/dev.attribution.js +16 -16
- package/dist/dev.js +672 -319
- package/dist/observe/boundaries.js +2 -2
- package/dist/observe/core/async.js +151 -116
- package/dist/observe/core/constants.js +3 -1
- package/dist/observe/core/context.js +2 -0
- package/dist/observe/core/core.js +51 -35
- package/dist/observe/core/effect.js +29 -30
- package/dist/observe/core/graph.js +13 -11
- package/dist/observe/core/lanes.js +25 -14
- package/dist/observe/core/owner.js +77 -51
- package/dist/observe/core/scheduler.js +202 -175
- package/dist/observe/core/verdict.js +5 -2
- package/dist/observe/deferred.js +16 -13
- package/dist/observe/from.js +248 -0
- package/dist/observe/index.js +2 -0
- package/dist/observe/map.js +2 -2
- package/dist/observe/signals.js +6 -1
- package/dist/observe/store/affects.js +13 -13
- package/dist/observe/store/optimistic.js +112 -71
- package/dist/observe/store/reconcile.js +137 -121
- package/dist/observe/store/store.js +612 -626
- package/dist/observe/store/target.js +1 -5
- package/dist/prod/boundaries.js +2 -2
- package/dist/prod/core/async.js +211 -176
- package/dist/prod/core/constants.js +3 -1
- package/dist/prod/core/context.js +2 -0
- package/dist/prod/core/core.js +63 -47
- package/dist/prod/core/effect.js +24 -25
- package/dist/prod/core/graph.js +12 -10
- package/dist/prod/core/heap.js +1 -1
- package/dist/prod/core/lanes.js +39 -28
- package/dist/prod/core/owner.js +70 -44
- package/dist/prod/core/scheduler.js +78 -51
- package/dist/prod/core/truth.js +4 -4
- package/dist/prod/core/verdict.js +11 -8
- package/dist/prod/deferred.js +17 -14
- package/dist/prod/from.js +248 -0
- package/dist/prod/index.js +2 -0
- package/dist/prod/map.js +2 -2
- package/dist/prod/signals.js +18 -13
- package/dist/prod/store/optimistic.js +112 -71
- package/dist/prod/store/reconcile.js +137 -121
- package/dist/prod/store/store.js +109 -121
- package/dist/prod/store/target.js +13 -17
- package/dist/types/core/async.d.ts +12 -2
- package/dist/types/core/constants.d.ts +5 -0
- package/dist/types/core/core.d.ts +29 -6
- package/dist/types/core/dev.d.ts +9 -1
- package/dist/types/core/error.d.ts +9 -1
- package/dist/types/core/owner.d.ts +4 -0
- package/dist/types/core/scheduler.d.ts +38 -7
- package/dist/types/from.d.ts +47 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/dev.js
CHANGED
|
@@ -64,121 +64,128 @@ import {
|
|
|
64
64
|
a8 as link,
|
|
65
65
|
a9 as pullComputed,
|
|
66
66
|
aa as strictRead,
|
|
67
|
-
ab as
|
|
68
|
-
ac as
|
|
69
|
-
ad as
|
|
70
|
-
ae as
|
|
71
|
-
af as
|
|
72
|
-
ag as
|
|
73
|
-
ah as
|
|
74
|
-
ai as
|
|
75
|
-
aj as
|
|
76
|
-
ak as
|
|
77
|
-
al as
|
|
78
|
-
am as
|
|
79
|
-
an as
|
|
80
|
-
ao as
|
|
81
|
-
ap as
|
|
82
|
-
aq as
|
|
83
|
-
ar as
|
|
84
|
-
as as
|
|
85
|
-
at as
|
|
86
|
-
au as
|
|
87
|
-
av as
|
|
88
|
-
aw as
|
|
89
|
-
ax as
|
|
90
|
-
ay as
|
|
91
|
-
az as
|
|
92
|
-
aA as
|
|
93
|
-
aB as
|
|
94
|
-
aC as
|
|
95
|
-
aD as
|
|
96
|
-
aE as
|
|
97
|
-
aF as
|
|
98
|
-
aG as
|
|
99
|
-
aH as
|
|
100
|
-
aI as
|
|
101
|
-
aJ as
|
|
102
|
-
aK as
|
|
103
|
-
aL as
|
|
104
|
-
aM as
|
|
105
|
-
aN as
|
|
106
|
-
aO as
|
|
107
|
-
aP as
|
|
108
|
-
aQ as
|
|
109
|
-
aR as
|
|
110
|
-
aS as
|
|
111
|
-
aT as
|
|
112
|
-
aU as
|
|
113
|
-
aV as
|
|
114
|
-
aW as
|
|
115
|
-
aX as
|
|
116
|
-
aY as
|
|
117
|
-
aZ as
|
|
118
|
-
a_ as
|
|
119
|
-
a$ as
|
|
120
|
-
b0 as
|
|
121
|
-
b1 as
|
|
122
|
-
b2 as
|
|
123
|
-
b3 as
|
|
124
|
-
b4 as
|
|
125
|
-
b5 as
|
|
126
|
-
b6 as
|
|
127
|
-
b7 as
|
|
128
|
-
b8 as
|
|
129
|
-
b9 as
|
|
130
|
-
ba as
|
|
131
|
-
bb as
|
|
132
|
-
bc as
|
|
133
|
-
bd as
|
|
134
|
-
be as
|
|
135
|
-
bf as
|
|
136
|
-
bg as
|
|
137
|
-
bh as
|
|
138
|
-
bi as
|
|
139
|
-
bj as
|
|
140
|
-
bk as
|
|
141
|
-
bl as
|
|
142
|
-
bm as
|
|
143
|
-
bn as
|
|
144
|
-
bo as
|
|
145
|
-
bp as
|
|
146
|
-
bq as
|
|
147
|
-
br as
|
|
148
|
-
bs as
|
|
149
|
-
bt as
|
|
150
|
-
bu as
|
|
151
|
-
bv as
|
|
152
|
-
bw as
|
|
153
|
-
bx as
|
|
154
|
-
by as
|
|
155
|
-
bz as
|
|
156
|
-
bA as
|
|
157
|
-
bB as
|
|
158
|
-
bC as
|
|
159
|
-
bD as
|
|
160
|
-
bE as
|
|
161
|
-
bF as
|
|
162
|
-
bG as
|
|
163
|
-
bH as
|
|
164
|
-
bI as
|
|
165
|
-
bJ as
|
|
166
|
-
bK as
|
|
167
|
-
bL as
|
|
168
|
-
bM as
|
|
169
|
-
bN as
|
|
67
|
+
ab as strictReadActive,
|
|
68
|
+
ac as warnStrictReadUntracked,
|
|
69
|
+
ad as staleReader,
|
|
70
|
+
ae as globalQueue,
|
|
71
|
+
af as joinPass,
|
|
72
|
+
ag as markLateLinker,
|
|
73
|
+
ah as spectating,
|
|
74
|
+
ai as unflushedValue,
|
|
75
|
+
aj as CONFIG_STAGED_ERROR,
|
|
76
|
+
ak as stagedReaders,
|
|
77
|
+
al as bornInto,
|
|
78
|
+
am as enterAction,
|
|
79
|
+
an as setEffectCallback,
|
|
80
|
+
ao as exitAction,
|
|
81
|
+
ap as isThenable,
|
|
82
|
+
aq as actionDepth,
|
|
83
|
+
ar as flush,
|
|
84
|
+
as as setQuestion,
|
|
85
|
+
at as emitDiagnostic,
|
|
86
|
+
au as enterCallback,
|
|
87
|
+
av as exitCallback,
|
|
88
|
+
aw as getOwner,
|
|
89
|
+
ax as inEffectCallback,
|
|
90
|
+
ay as effectCallbackEvent,
|
|
91
|
+
az as setExternalHooks,
|
|
92
|
+
aA as signal,
|
|
93
|
+
aB as setSignal,
|
|
94
|
+
aC as cleanup,
|
|
95
|
+
aD as read,
|
|
96
|
+
aE as DEV$1,
|
|
97
|
+
aF as CONFIG_TRANSPARENT,
|
|
98
|
+
aG as NoOwnerError,
|
|
99
|
+
aH as ContextNotFoundError,
|
|
100
|
+
aI as createEffectNode,
|
|
101
|
+
aJ as recompute,
|
|
102
|
+
aK as EFFECT_USER,
|
|
103
|
+
aL as reportDiagnostic,
|
|
104
|
+
aM as computed,
|
|
105
|
+
aN as staleValues,
|
|
106
|
+
aO as CONFIG_AUTO_DISPOSE,
|
|
107
|
+
aP as EFFECT_TRACKED,
|
|
108
|
+
aQ as heldRunHook,
|
|
109
|
+
aR as unwrapStatusError,
|
|
110
|
+
aS as setStrictRead,
|
|
111
|
+
aT as queueEvent,
|
|
112
|
+
aU as StatusError,
|
|
113
|
+
aV as trimStaleDeps,
|
|
114
|
+
aW as haltReactivityAt,
|
|
115
|
+
aX as strictReadEvent,
|
|
116
|
+
aY as setTrackedQueueCallback,
|
|
117
|
+
aZ as setEffectStatusNotify,
|
|
118
|
+
a_ as _hitUnhandledAsync,
|
|
119
|
+
a$ as resetUnhandledAsync,
|
|
120
|
+
b0 as ROOT_ERROR_HOOK,
|
|
121
|
+
b1 as registerGraph,
|
|
122
|
+
b2 as runWithOwner,
|
|
123
|
+
b3 as setMemo,
|
|
124
|
+
b4 as $REFRESH,
|
|
125
|
+
b5 as markRefresh,
|
|
126
|
+
b6 as createRoot,
|
|
127
|
+
b7 as getObserver,
|
|
128
|
+
b8 as dispose,
|
|
129
|
+
b9 as TimeoutError,
|
|
130
|
+
ba as untrack,
|
|
131
|
+
bb as dirtyQueue,
|
|
132
|
+
bc as CONFIG_REDERIVE,
|
|
133
|
+
bd as passTx,
|
|
134
|
+
be as CONFIG_FRESH_READ,
|
|
135
|
+
bf as createOwner,
|
|
136
|
+
bg as writeHook,
|
|
137
|
+
bh as REACTIVE_WRITE_IN_OWNED_SCOPE_SIGNAL_MESSAGE,
|
|
138
|
+
bi as ownedScopeWriteMessage,
|
|
139
|
+
bj as isEqual,
|
|
140
|
+
bk as CONFIG_MANUAL_WRITE,
|
|
141
|
+
bl as snapshotCaptureActive,
|
|
142
|
+
bm as captureWriteSnapshot,
|
|
143
|
+
bn as notePromotedWrite,
|
|
144
|
+
bo as slotSignal,
|
|
145
|
+
bp as stagedScreen,
|
|
146
|
+
bq as CONFIG_PROMOTED,
|
|
147
|
+
br as setSlotUnobserved,
|
|
148
|
+
bs as installStoreHooks,
|
|
149
|
+
bt as joinPassTx,
|
|
150
|
+
bu as asyncTailFlights,
|
|
151
|
+
bv as untrackDepth,
|
|
152
|
+
bw as checkPostAwaitRead,
|
|
153
|
+
bx as disposalDepth,
|
|
154
|
+
by as insertIntoHeap,
|
|
155
|
+
bz as isDisposed,
|
|
156
|
+
bA as handleAsync,
|
|
157
|
+
bB as addPendingSource,
|
|
158
|
+
bC as propagateStatus,
|
|
159
|
+
bD as forEachDependent,
|
|
160
|
+
bE as settlePendingSource,
|
|
161
|
+
bF as joinPassAt,
|
|
162
|
+
bG as notifyEpoch,
|
|
163
|
+
bH as SUPPORTS_PROXY,
|
|
164
|
+
bI as releaseMarksHook,
|
|
165
|
+
bJ as installMarkHooks,
|
|
166
|
+
bK as CONFIG_LAGS,
|
|
167
|
+
bL as REACTIVE_REASK,
|
|
168
|
+
bM as onSupersede,
|
|
169
|
+
bN as haltReactivity,
|
|
170
|
+
bO as heldUnder,
|
|
171
|
+
bP as unhold,
|
|
172
|
+
bQ as laneStageHook,
|
|
173
|
+
bR as REACTIVE_ZOMBIE,
|
|
174
|
+
bS as installBoundaryHooks,
|
|
175
|
+
bT as CAUGHT_REARMED,
|
|
176
|
+
bU as OBSERVE$1
|
|
170
177
|
} from "./dev-shared.js";
|
|
171
178
|
export {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
179
|
+
bV as clearSnapshots,
|
|
180
|
+
bW as enforceLoadingBoundary,
|
|
181
|
+
bX as getNextChildId,
|
|
182
|
+
bY as markSnapshotScope,
|
|
183
|
+
bZ as peekNextChildId,
|
|
184
|
+
b_ as releaseSnapshotScope,
|
|
185
|
+
b$ as resetErrorHalt,
|
|
186
|
+
c0 as setConsoleFooter,
|
|
187
|
+
c1 as setSnapshotCapture,
|
|
188
|
+
c2 as setWriteHook
|
|
182
189
|
} from "./dev-shared.js";
|
|
183
190
|
|
|
184
191
|
// Truth reads (`until`, `refresh`; CONFIG_AUTHORITATIVE) over lane nodes.
|
|
@@ -696,12 +703,21 @@ function dissolveLane(l, into, except) {
|
|
|
696
703
|
* member throws like any. */
|
|
697
704
|
function laneRead(c, el) {
|
|
698
705
|
const guess = el._config & CONFIG_GUESS;
|
|
706
|
+
const l = txOf(el);
|
|
707
|
+
// A lane a correction folded under (D-34): store/optimistic.ts reads it.
|
|
708
|
+
// Before the authoritative arm: an `until` outside the lane reads the
|
|
709
|
+
// same truth there, and joins the hold it folded into — its posture over
|
|
710
|
+
// a foreign hold (D-31), which the truth read alone would not take.
|
|
711
|
+
const folded = c !== null && l.folded;
|
|
712
|
+
if (folded) {
|
|
713
|
+
const v = folded(c, el);
|
|
714
|
+
if (v !== NOT_PENDING) return v;
|
|
715
|
+
}
|
|
699
716
|
if (c !== null && c._config & CONFIG_AUTHORITATIVE) return GlobalQueue._truth(el);
|
|
700
717
|
const status = el._statusFlags;
|
|
701
718
|
// An errored member's lane value predates its error; the error is the answer (#4106).
|
|
702
719
|
if (!guess && status & STATUS_ERROR) return NOT_PENDING;
|
|
703
720
|
if (c === null) return laneValueOf(el);
|
|
704
|
-
const l = txOf(el);
|
|
705
721
|
if (!tracking || c._config & CONFIG_CHILDREN_FORBIDDEN) {
|
|
706
722
|
// An untracked read inside lane work derives from the lane like a
|
|
707
723
|
// tracked one, minus the subscription — `untrack` is about
|
|
@@ -869,10 +885,12 @@ function laneWrite(el, v) {
|
|
|
869
885
|
// question is the one being asked (`question`: a slice's, a derive's
|
|
870
886
|
// continuation's — the flight's); unstamped writes and mainline are
|
|
871
887
|
// current.
|
|
872
|
-
|
|
888
|
+
// A store re-bases a keyed arrangement guess over an older truth, and
|
|
889
|
+
// folds a current one beneath it (D-34): true.
|
|
890
|
+
const older = stale(el, question);
|
|
891
|
+
if (GlobalQueue._laneRebase?.(el, v, older) || older) {
|
|
873
892
|
el._pendingValue = v;
|
|
874
893
|
el._config |= CONFIG_HELD;
|
|
875
|
-
GlobalQueue._laneRebase?.(el, v);
|
|
876
894
|
schedule();
|
|
877
895
|
return v;
|
|
878
896
|
}
|
|
@@ -1325,6 +1343,9 @@ function verdictValue(el, c) {
|
|
|
1325
1343
|
(!el._equals || !el._equals(el._x._lane, el._pendingValue))))
|
|
1326
1344
|
)
|
|
1327
1345
|
probeFound = true;
|
|
1346
|
+
// A lane a correction folded under (D-34): `latest()` shows the hold's
|
|
1347
|
+
// world whole — the truth beneath each guess, else what it covered.
|
|
1348
|
+
if (latestActive && l.folded) return l.folded(null, el);
|
|
1328
1349
|
return el._x._lane;
|
|
1329
1350
|
}
|
|
1330
1351
|
if (probing && flying) probeFound = true;
|
|
@@ -1334,7 +1355,7 @@ function verdictValue(el, c) {
|
|
|
1334
1355
|
// verdict read as on any untracked read; the pending throw they add for a
|
|
1335
1356
|
// plain read does not apply — a verdict read is a sanctioned read of a
|
|
1336
1357
|
// pending node (an uninitialized one still throws NotReady below).
|
|
1337
|
-
if (strictRead)
|
|
1358
|
+
if (strictRead && strictReadActive())
|
|
1338
1359
|
warnStrictReadUntracked(strictRead, {
|
|
1339
1360
|
ownerId: c?.id,
|
|
1340
1361
|
ownerName: c?._name,
|
|
@@ -1567,21 +1588,23 @@ function action(genFn) {
|
|
|
1567
1588
|
// it may have been called from — a root created in it (`until`,
|
|
1568
1589
|
// `resolve`) is deliberate (PRIMITIVE_IN_EFFECT_CALLBACK is off).
|
|
1569
1590
|
let effectCallback = false;
|
|
1591
|
+
let effectEvent;
|
|
1570
1592
|
{
|
|
1571
1593
|
enterCallback();
|
|
1572
1594
|
effectCallback = inEffectCallback;
|
|
1595
|
+
effectEvent = effectCallbackEvent;
|
|
1573
1596
|
setEffectCallback(false);
|
|
1574
1597
|
}
|
|
1575
1598
|
try {
|
|
1576
1599
|
r = err ? it.throw(v) : it.next(v);
|
|
1577
1600
|
} catch (e) {
|
|
1578
1601
|
exitAction();
|
|
1579
|
-
(exitCallback(), setEffectCallback(effectCallback));
|
|
1602
|
+
(exitCallback(), setEffectCallback(effectCallback, effectEvent));
|
|
1580
1603
|
if (attrHooks !== null) attrHooks.actionStepEnd(it);
|
|
1581
1604
|
return done(undefined, e, true);
|
|
1582
1605
|
}
|
|
1583
1606
|
exitAction();
|
|
1584
|
-
(exitCallback(), setEffectCallback(effectCallback));
|
|
1607
|
+
(exitCallback(), setEffectCallback(effectCallback, effectEvent));
|
|
1585
1608
|
if (attrHooks !== null) attrHooks.actionStepEnd(it);
|
|
1586
1609
|
// A rejected iterator result (async generators) means the error already
|
|
1587
1610
|
// escaped the generator body — it is completed, and throwing back in
|
|
@@ -1776,6 +1799,10 @@ function setReadWatch(watch) {
|
|
|
1776
1799
|
* via a `setContext` call.
|
|
1777
1800
|
*/
|
|
1778
1801
|
function createContext(defaultValue, description) {
|
|
1802
|
+
// Dev: an explicit `undefined` default is still no default (`undefined`
|
|
1803
|
+
// means "not provided"); remembered so a failed read can say so (#4181).
|
|
1804
|
+
if (arguments.length && defaultValue === undefined)
|
|
1805
|
+
return { id: Symbol(description), defaultValue, _undefinedDefault: true };
|
|
1779
1806
|
return { id: Symbol(description), defaultValue };
|
|
1780
1807
|
}
|
|
1781
1808
|
/**
|
|
@@ -1796,7 +1823,9 @@ function getContext(context, owner = getOwner()) {
|
|
|
1796
1823
|
let value = owner._context[context.id];
|
|
1797
1824
|
if (value === undefined) value = context.defaultValue;
|
|
1798
1825
|
if (value === undefined) {
|
|
1799
|
-
|
|
1826
|
+
// Dev names the context and why it has no value: no provider, or a
|
|
1827
|
+
// provider that passed `undefined` (the key is set, to `undefined`).
|
|
1828
|
+
throw new ContextNotFoundError(context, context.id in owner._context);
|
|
1800
1829
|
}
|
|
1801
1830
|
return value;
|
|
1802
1831
|
}
|
|
@@ -1865,10 +1894,9 @@ function effect(compute, effect, error, options) {
|
|
|
1865
1894
|
);
|
|
1866
1895
|
}
|
|
1867
1896
|
}
|
|
1868
|
-
function notifyEffectStatus(
|
|
1869
|
-
|
|
1870
|
-
const
|
|
1871
|
-
const actualError = error !== undefined ? error : this._x?._error;
|
|
1897
|
+
function notifyEffectStatus() {
|
|
1898
|
+
const actualStatus = this._statusFlags;
|
|
1899
|
+
const actualError = this._x?._error;
|
|
1872
1900
|
if (actualStatus & STATUS_ERROR) {
|
|
1873
1901
|
globalQueue.notify(this, STATUS_PENDING, 0);
|
|
1874
1902
|
if (this._type === EFFECT_USER) {
|
|
@@ -1876,19 +1904,22 @@ function notifyEffectStatus(status, error) {
|
|
|
1876
1904
|
// queue it like the effect function. It runs in the same imperative,
|
|
1877
1905
|
// writable scope and throws escalate the same way. No payload is queued — the node already carries `_statusFlags`/`_error`,
|
|
1878
1906
|
// and the runner dispatches on them, so a recovery before the effect
|
|
1879
|
-
// phase takes the success arm instead.
|
|
1880
|
-
//
|
|
1881
|
-
// re-propagates unblocked at commit.
|
|
1907
|
+
// phase takes the success arm instead. (Re-read: the boundary
|
|
1908
|
+
// notify above can run a redraw.)
|
|
1882
1909
|
if (this._statusFlags & STATUS_ERROR) {
|
|
1883
1910
|
this._modified = true;
|
|
1884
1911
|
globalQueue.enqueue(this._type, (this._boundRunEffect ??= runEffect.bind(null, this)));
|
|
1885
1912
|
}
|
|
1886
1913
|
return;
|
|
1887
1914
|
}
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1915
|
+
// Dev locates the halt at the node that threw: the StatusError's
|
|
1916
|
+
// source, upstream of this effect when a computed failed.
|
|
1917
|
+
escalate(
|
|
1918
|
+
this,
|
|
1919
|
+
unwrapStatusError(actualError),
|
|
1920
|
+
actualError,
|
|
1921
|
+
actualError instanceof StatusError ? actualError.source : this
|
|
1922
|
+
);
|
|
1892
1923
|
} else if (this._type === EFFECT_RENDER) {
|
|
1893
1924
|
globalQueue.notify(this, STATUS_PENDING | STATUS_ERROR, actualStatus, actualError);
|
|
1894
1925
|
if (_hitUnhandledAsync && resetUnhandledAsync()) {
|
|
@@ -1917,6 +1948,14 @@ function notifyEffectStatus(status, error) {
|
|
|
1917
1948
|
}
|
|
1918
1949
|
}
|
|
1919
1950
|
}
|
|
1951
|
+
/** An effect's error no boundary takes halts the system (boundary-or-halt):
|
|
1952
|
+
* halted with `cause`, `thrown` rethrown; dev locates it at `subject`. */
|
|
1953
|
+
function escalate(node, cause, thrown = cause, subject = node) {
|
|
1954
|
+
if (!globalQueue.notify(node, STATUS_ERROR, STATUS_ERROR)) {
|
|
1955
|
+
haltReactivityAt(cause, subject);
|
|
1956
|
+
throw thrown;
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1920
1959
|
function runEffect(node, type) {
|
|
1921
1960
|
if (!node._modified || node._flags & REACTIVE_DISPOSED) return;
|
|
1922
1961
|
// A queued run behind a fallback (boundaries.ts) waits for the reveal: a
|
|
@@ -1951,10 +1990,7 @@ function runEffect(node, type) {
|
|
|
1951
1990
|
})
|
|
1952
1991
|
: console.error(err);
|
|
1953
1992
|
} catch (error) {
|
|
1954
|
-
|
|
1955
|
-
haltReactivity(error);
|
|
1956
|
-
throw error;
|
|
1957
|
-
}
|
|
1993
|
+
escalate(node, error);
|
|
1958
1994
|
}
|
|
1959
1995
|
return;
|
|
1960
1996
|
}
|
|
@@ -1962,9 +1998,13 @@ function runEffect(node, type) {
|
|
|
1962
1998
|
// the compute pass that produced `_value` was clean, so its tail still goes.
|
|
1963
1999
|
const cleanPass = node._x?._error == null;
|
|
1964
2000
|
let prevStrictRead = false;
|
|
2001
|
+
let prevStrictReadEvent;
|
|
1965
2002
|
{
|
|
1966
|
-
|
|
1967
|
-
|
|
2003
|
+
prevStrictReadEvent = strictReadEvent;
|
|
2004
|
+
// A run outside a queue (a render effect's first run at creation) records
|
|
2005
|
+
// no event: its callback is the compiler's DOM writes.
|
|
2006
|
+
prevStrictRead = setStrictRead("an effect callback", queueEvent);
|
|
2007
|
+
setEffectCallback(true, queueEvent);
|
|
1968
2008
|
enterCallback();
|
|
1969
2009
|
}
|
|
1970
2010
|
// Observe tier, like its `effectRunEnd` twin below: the frame the engine
|
|
@@ -1987,13 +2027,10 @@ function runEffect(node, type) {
|
|
|
1987
2027
|
} catch (error) {
|
|
1988
2028
|
ext(node)._error = new StatusError(node, error);
|
|
1989
2029
|
node._statusFlags |= STATUS_ERROR;
|
|
1990
|
-
|
|
1991
|
-
haltReactivity(error);
|
|
1992
|
-
throw error;
|
|
1993
|
-
}
|
|
2030
|
+
escalate(node, error);
|
|
1994
2031
|
} finally {
|
|
1995
2032
|
{
|
|
1996
|
-
setStrictRead(prevStrictRead);
|
|
2033
|
+
setStrictRead(prevStrictRead, prevStrictReadEvent);
|
|
1997
2034
|
setEffectCallback(false);
|
|
1998
2035
|
exitCallback();
|
|
1999
2036
|
}
|
|
@@ -2183,9 +2220,6 @@ function lookupTarget(raw, fam) {
|
|
|
2183
2220
|
const owner = raw[$OWNER];
|
|
2184
2221
|
return owner !== undefined && owner.fam === fam ? owner : (fam?.map ?? storeLookup).get(raw);
|
|
2185
2222
|
}
|
|
2186
|
-
function devAssertNeverUserMutation(target) {
|
|
2187
|
-
return;
|
|
2188
|
-
}
|
|
2189
2223
|
/** Sticky descendants flag up the parent chain (§6d): adoption descends
|
|
2190
2224
|
* into a changed child pair only where a target with nodes exists below. */
|
|
2191
2225
|
function markDescendants(target) {
|
|
@@ -2617,7 +2651,12 @@ function createReaction(effectFn, options) {
|
|
|
2617
2651
|
}
|
|
2618
2652
|
runWithOwner(owner, () => {
|
|
2619
2653
|
effect(
|
|
2620
|
-
() =>
|
|
2654
|
+
() => {
|
|
2655
|
+
const node = getOwner();
|
|
2656
|
+
arm = node;
|
|
2657
|
+
tracking();
|
|
2658
|
+
return node;
|
|
2659
|
+
},
|
|
2621
2660
|
node => {
|
|
2622
2661
|
arm = undefined;
|
|
2623
2662
|
cl?.();
|
|
@@ -3355,7 +3394,7 @@ function updateKeyedMap() {
|
|
|
3355
3394
|
this._rows && (this._rows = []);
|
|
3356
3395
|
this._indexes && (this._indexes = []);
|
|
3357
3396
|
}
|
|
3358
|
-
if (this._fallback && !this._mappings
|
|
3397
|
+
if (this._fallback && !this._mappings.length) {
|
|
3359
3398
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
3360
3399
|
// dispose it before re-creating
|
|
3361
3400
|
this._nodes[0]?.dispose();
|
|
@@ -3636,7 +3675,7 @@ function updateRepeat() {
|
|
|
3636
3675
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
3637
3676
|
this._offset = 0;
|
|
3638
3677
|
}
|
|
3639
|
-
if (this._fallback && !this._mappings
|
|
3678
|
+
if (this._fallback && !this._mappings.length) {
|
|
3640
3679
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
3641
3680
|
// dispose it before re-creating
|
|
3642
3681
|
this._nodes[0]?.dispose();
|
|
@@ -3803,7 +3842,7 @@ function wrap(value, parent = null, parentKey = null, fam = parent?.fam ?? null)
|
|
|
3803
3842
|
const existing = lookupTarget(value, fam);
|
|
3804
3843
|
if (existing !== undefined) return existing.px;
|
|
3805
3844
|
const t = value[$TARGET];
|
|
3806
|
-
if (t
|
|
3845
|
+
if (t?.px === value) {
|
|
3807
3846
|
// Foreign-family proxies re-wrap into THIS family (writes stay isolated);
|
|
3808
3847
|
// same-family and plain-store proxies pass through.
|
|
3809
3848
|
if (fam === null || t.fam === fam) return value;
|
|
@@ -3875,7 +3914,7 @@ function asBacking(v) {
|
|
|
3875
3914
|
* pending backing is never "equal" to the committed one); a lane value is
|
|
3876
3915
|
* an arrangement (`LaneView`), judged by the optimistic machinery. */
|
|
3877
3916
|
const containerEquals = function (a, b) {
|
|
3878
|
-
return a === b ||
|
|
3917
|
+
return a === b || !!optHooks?.arrangement(this._host, a, b);
|
|
3879
3918
|
};
|
|
3880
3919
|
function sameLogicalSlot(target, a, b) {
|
|
3881
3920
|
if (a === null || typeof a !== "object" || b === null || typeof b !== "object") return false;
|
|
@@ -3892,10 +3931,10 @@ function releaseSlot(node) {
|
|
|
3892
3931
|
if (t.k === node) t.k = null;
|
|
3893
3932
|
} else if (key === $DEEP) {
|
|
3894
3933
|
if (t.dk === node) t.dk = null;
|
|
3895
|
-
} else if (t.n
|
|
3934
|
+
} else if (t.n?.[key] === node) {
|
|
3896
3935
|
delete t.n[key];
|
|
3897
3936
|
t.nc--;
|
|
3898
|
-
} else if (t.h
|
|
3937
|
+
} else if (t.h?.[key] === node) delete t.h[key];
|
|
3899
3938
|
// The family's index keeps only targets that still carry a node.
|
|
3900
3939
|
if (
|
|
3901
3940
|
t.fam !== null &&
|
|
@@ -3941,9 +3980,13 @@ function bornStaged(target, node, staged, key) {
|
|
|
3941
3980
|
if (k === null) return; // a node-less staging holds nothing (`stageOn`)
|
|
3942
3981
|
// Held by the container's transaction only for a key the HELD staging
|
|
3943
3982
|
// changed — a mainline layer's change above it stages mainline. (A
|
|
3944
|
-
// container carrying a guess is a lane's: the flush's park decides
|
|
3945
|
-
|
|
3946
|
-
|
|
3983
|
+
// container carrying a guess is a lane's: the flush's park decides —
|
|
3984
|
+
// unless a correction folded under the guess, D-34: the key is that
|
|
3985
|
+
// correction's hold's.)
|
|
3986
|
+
if (k._config & CONFIG_HELD && heldKeyChanged(target, key)) {
|
|
3987
|
+
const l = txOf(k);
|
|
3988
|
+
if (!(k._config & CONFIG_OVERRIDE) || l.folded) holdNode(node, resolveTx(l._parent ?? l));
|
|
3989
|
+
}
|
|
3947
3990
|
// A28 (4): a batch written inside a creation-time pass is promoted — its
|
|
3948
3991
|
// late-materialized leaf with it.
|
|
3949
3992
|
if (k._config & CONFIG_PROMOTED) notePromotedWrite(node);
|
|
@@ -3972,12 +4015,7 @@ function getNode(
|
|
|
3972
4015
|
accKnown === -1 ? isOwnAccessor(pb ?? target.v, key) : accKnown === 1
|
|
3973
4016
|
));
|
|
3974
4017
|
if (pb !== null && !created.acc)
|
|
3975
|
-
bornStaged(
|
|
3976
|
-
target,
|
|
3977
|
-
created,
|
|
3978
|
-
target.del !== null && target.del.has(key) ? undefined : pb[key],
|
|
3979
|
-
key
|
|
3980
|
-
);
|
|
4018
|
+
bornStaged(target, created, target.del?.has(key) ? undefined : pb[key], key);
|
|
3981
4019
|
// Attribution-only: name store property nodes by path segment so
|
|
3982
4020
|
// attribution chains and wide-scope warnings read "store.todos" (or
|
|
3983
4021
|
// "todos.title" when the store was declared with a name), not
|
|
@@ -4002,8 +4040,7 @@ function getHasNode(target, key) {
|
|
|
4002
4040
|
if (node === undefined) {
|
|
4003
4041
|
const created = (node = slotSignal(key in committed(target), isEqual, target, key, false));
|
|
4004
4042
|
const pb = target.pb;
|
|
4005
|
-
if (pb !== null)
|
|
4006
|
-
bornStaged(target, created, key in pb && !(target.del !== null && target.del.has(key)), key);
|
|
4043
|
+
if (pb !== null) bornStaged(target, created, key in pb && !target.del?.has(key), key);
|
|
4007
4044
|
if (attrHooks !== null) stampNodeOwner(created, target);
|
|
4008
4045
|
nodes[key] = node;
|
|
4009
4046
|
noteNode(target, created, key);
|
|
@@ -4177,7 +4214,7 @@ function scanAccessorsOnce(target) {
|
|
|
4177
4214
|
const keys = Reflect.ownKeys(src);
|
|
4178
4215
|
let plain = Object.getPrototypeOf(src) === Object.prototype;
|
|
4179
4216
|
for (const key of keys) {
|
|
4180
|
-
if (
|
|
4217
|
+
if (isOwnAccessor(src, key)) {
|
|
4181
4218
|
target.a = true;
|
|
4182
4219
|
plain = false;
|
|
4183
4220
|
break;
|
|
@@ -4202,7 +4239,7 @@ const plainProto = o => {
|
|
|
4202
4239
|
* container at flatten so its shape stays fast (#3689). */
|
|
4203
4240
|
function overlayRebuilds(t, pb) {
|
|
4204
4241
|
if (t.kc > OVERLAY_REBUILD_MAX_KEYS) return false;
|
|
4205
|
-
if (t.del
|
|
4242
|
+
if (t.del?.size) return true;
|
|
4206
4243
|
const wk = t.wk;
|
|
4207
4244
|
if (wk !== null && wk !== WK_ALL && wk.u === undefined && wk.size <= OVERLAY_REBUILD_MIN_ADDS)
|
|
4208
4245
|
return false;
|
|
@@ -4216,18 +4253,14 @@ function overlayRebuilds(t, pb) {
|
|
|
4216
4253
|
function materializePB(target) {
|
|
4217
4254
|
const pb = target.pb;
|
|
4218
4255
|
if (!target.ovl) return pb;
|
|
4219
|
-
const clone =
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
}
|
|
4225
|
-
for (const key of Reflect.ownKeys(pb))
|
|
4226
|
-
target.sc === 2 ? (clone[key] = pb[key]) : copyOwn(clone, pb, key);
|
|
4256
|
+
const clone = overlayOnto(
|
|
4257
|
+
target,
|
|
4258
|
+
target.sc === 2 ? wideClone(target.v, target) : cloneRaw(target.v, target),
|
|
4259
|
+
pb
|
|
4260
|
+
);
|
|
4227
4261
|
target.pb = clone;
|
|
4228
|
-
target.ovl = false;
|
|
4229
4262
|
// The staging IS the pending backing: re-point the container node.
|
|
4230
|
-
if (target.k
|
|
4263
|
+
if (target.k?._pendingValue === pb) target.k._pendingValue = clone;
|
|
4231
4264
|
return clone;
|
|
4232
4265
|
}
|
|
4233
4266
|
/** The batch's pending backing, created on the first draft write: an overlay
|
|
@@ -4279,7 +4312,6 @@ function privatizeCommitted(target) {
|
|
|
4279
4312
|
target.ch = false;
|
|
4280
4313
|
if (target.u) {
|
|
4281
4314
|
privatizeCommitted(target.u);
|
|
4282
|
-
devAssertNeverUserMutation(target.u.v);
|
|
4283
4315
|
const pv = target.u.v;
|
|
4284
4316
|
const slot = parentSlotKey(target, before);
|
|
4285
4317
|
if (pv[slot] === before) pv[slot] = target.v;
|
|
@@ -4303,16 +4335,19 @@ function parentSlotKey(target, expected) {
|
|
|
4303
4335
|
* place — the backing keeps its identity. */
|
|
4304
4336
|
function flattenOverlay(t, pb) {
|
|
4305
4337
|
privatizeCommitted(t);
|
|
4306
|
-
|
|
4307
|
-
|
|
4338
|
+
overlayOnto(t, t.v, pb); // the caller (`foldTarget`) closes the staging
|
|
4339
|
+
}
|
|
4340
|
+
/** An overlay's own keys and deletions onto `to` (the two are disjoint: a
|
|
4341
|
+
* write un-deletes its key); the overlay is closed. */
|
|
4342
|
+
function overlayOnto(t, to, pb) {
|
|
4343
|
+
for (const key of Reflect.ownKeys(pb)) t.sc === 2 ? (to[key] = pb[key]) : copyOwn(to, pb, key);
|
|
4308
4344
|
if (t.del !== null) {
|
|
4309
|
-
for (const key of t.del) delete
|
|
4345
|
+
for (const key of t.del) delete to[key];
|
|
4310
4346
|
t.kc -= t.del.size;
|
|
4311
4347
|
t.del = null;
|
|
4312
4348
|
}
|
|
4313
|
-
t.pb = null;
|
|
4314
4349
|
t.ovl = false;
|
|
4315
|
-
|
|
4350
|
+
return to;
|
|
4316
4351
|
}
|
|
4317
4352
|
/** Adoption (a setter's returned replacement; reconcile and projection
|
|
4318
4353
|
* landings in S3): the incoming object becomes the backing by reference at
|
|
@@ -4351,7 +4386,7 @@ function adoptPB(target, incoming, notify = true) {
|
|
|
4351
4386
|
target.a = false;
|
|
4352
4387
|
target.wk = null; // adoption supersedes staged trap writes
|
|
4353
4388
|
const owner = incoming[$OWNER];
|
|
4354
|
-
if (owner
|
|
4389
|
+
if (owner?.fam === target.fam) incoming[$OWNER] = target;
|
|
4355
4390
|
else setLookup(incoming, target);
|
|
4356
4391
|
if (notify && base !== incoming) notifyFold(target, base, incoming);
|
|
4357
4392
|
}
|
|
@@ -4448,7 +4483,7 @@ function drainFolds() {
|
|
|
4448
4483
|
* landing) read it. */
|
|
4449
4484
|
GlobalQueue._slotFlight = n => {
|
|
4450
4485
|
const fam = n._host?.fam;
|
|
4451
|
-
return
|
|
4486
|
+
return (fam?.node?._statusFlags & STATUS_PENDING) !== 0;
|
|
4452
4487
|
};
|
|
4453
4488
|
/** Core asks (lanes.ts `covered`): the value a slot node's guess covered.
|
|
4454
4489
|
* A chained link's committed value is the inner store's at the last
|
|
@@ -4459,8 +4494,8 @@ GlobalQueue._slotCovered = n => {
|
|
|
4459
4494
|
if (t.ch) {
|
|
4460
4495
|
const key = n._key;
|
|
4461
4496
|
const inner = t.v;
|
|
4462
|
-
if (t.h
|
|
4463
|
-
else if (t.n
|
|
4497
|
+
if (t.h?.[key] === n) n._value = untrack(() => key in inner);
|
|
4498
|
+
else if (t.n?.[key] === n) n._value = untrack(() => unwrapValue(inner[key]));
|
|
4464
4499
|
}
|
|
4465
4500
|
return n._value;
|
|
4466
4501
|
};
|
|
@@ -4493,12 +4528,8 @@ function foldTarget(t, old) {
|
|
|
4493
4528
|
const k = t.k;
|
|
4494
4529
|
const pb = t.pb;
|
|
4495
4530
|
if (pb !== null) {
|
|
4496
|
-
if (pb === t.v)
|
|
4497
|
-
|
|
4498
|
-
// the adopted object (shared ownership — never cloned).
|
|
4499
|
-
t.pb = null;
|
|
4500
|
-
t.wk = null;
|
|
4501
|
-
} else if (
|
|
4531
|
+
if (pb === t.v);
|
|
4532
|
+
else if (
|
|
4502
4533
|
t.ovl &&
|
|
4503
4534
|
(t.v !== old || (!overlayRebuilds(t, pb) && k?._x?._snapshotValue !== old))
|
|
4504
4535
|
) {
|
|
@@ -4521,26 +4552,19 @@ function foldTarget(t, old) {
|
|
|
4521
4552
|
else delete v[key];
|
|
4522
4553
|
}
|
|
4523
4554
|
} else {
|
|
4524
|
-
for (const key of Reflect.ownKeys(pb))
|
|
4525
|
-
const d = Object.getOwnPropertyDescriptor(pb, key);
|
|
4526
|
-
if (d.get || d.set || !d.enumerable || !d.writable || !d.configurable)
|
|
4527
|
-
Object.defineProperty(v, key, d);
|
|
4528
|
-
else if (d.value !== old[key] || !hasOwn$1.call(old, key)) v[key] = d.value;
|
|
4529
|
-
}
|
|
4555
|
+
for (const key of Reflect.ownKeys(pb)) copyOwn(v, pb, key);
|
|
4530
4556
|
for (const key of Reflect.ownKeys(old)) {
|
|
4531
4557
|
if (!hasOwn$1.call(pb, key)) delete v[key];
|
|
4532
4558
|
}
|
|
4533
4559
|
}
|
|
4534
|
-
t.pb = null;
|
|
4535
|
-
t.wk = null;
|
|
4536
4560
|
} else {
|
|
4537
4561
|
// The clone (or adopted object) becomes the committed backing
|
|
4538
4562
|
// (path copy below).
|
|
4539
4563
|
t.v = t.ovl ? materializePB(t) : pb;
|
|
4540
4564
|
t.ch = t.v[$TARGET] !== undefined;
|
|
4541
|
-
t.pb = null;
|
|
4542
|
-
t.wk = null;
|
|
4543
4565
|
}
|
|
4566
|
+
t.pb = null;
|
|
4567
|
+
t.wk = null; // the written-keys window closes with the commit
|
|
4544
4568
|
}
|
|
4545
4569
|
if (k !== null) {
|
|
4546
4570
|
// The node's committed value is the backing. A container nobody
|
|
@@ -4555,7 +4579,6 @@ function foldTarget(t, old) {
|
|
|
4555
4579
|
const slot = parentSlotKey(t, old);
|
|
4556
4580
|
if (t.u.v[slot] === old) {
|
|
4557
4581
|
privatizeCommitted(t.u);
|
|
4558
|
-
devAssertNeverUserMutation(t.u.v);
|
|
4559
4582
|
t.u.v[slot] = t.v;
|
|
4560
4583
|
}
|
|
4561
4584
|
}
|
|
@@ -4583,7 +4606,7 @@ function reportReplacedContainers(t, old, pb, writtenKeys) {
|
|
|
4583
4606
|
const owner = storeRootOwner(t);
|
|
4584
4607
|
for (const key of keys) {
|
|
4585
4608
|
if ((isArray && key === "length") || key === $OWNER) continue;
|
|
4586
|
-
if (t.del
|
|
4609
|
+
if (t.del?.has(key)) continue;
|
|
4587
4610
|
const ov = unwrapValue(old[key]);
|
|
4588
4611
|
const nv = unwrapValue(pb[key]);
|
|
4589
4612
|
if (
|
|
@@ -4731,7 +4754,7 @@ function notifyWrites(t) {
|
|
|
4731
4754
|
if (od?.get || od?.set || !isEqual(od?.value, nd.value)) setSignal(node, () => nd.value);
|
|
4732
4755
|
continue;
|
|
4733
4756
|
}
|
|
4734
|
-
const nv = t.del
|
|
4757
|
+
const nv = t.del?.has(key) ? undefined : pb[key];
|
|
4735
4758
|
setSignal(node, () => nv);
|
|
4736
4759
|
if (t.fam !== null) {
|
|
4737
4760
|
// The derive's write is a derivation; a user setter's is a proposal
|
|
@@ -4749,13 +4772,13 @@ function notifyWrites(t) {
|
|
|
4749
4772
|
for (const key of keys) {
|
|
4750
4773
|
const node = has[key];
|
|
4751
4774
|
if (node !== undefined) {
|
|
4752
|
-
setSignal(node, key in pb && !
|
|
4775
|
+
setSignal(node, key in pb && !t.del?.has(key));
|
|
4753
4776
|
if (t.fam !== null) holdWithDerive(t, node);
|
|
4754
4777
|
}
|
|
4755
4778
|
}
|
|
4756
4779
|
}
|
|
4757
4780
|
if (t.dk !== null) {
|
|
4758
|
-
if (t.del
|
|
4781
|
+
if (t.del?.size) bumpDeep(t);
|
|
4759
4782
|
else
|
|
4760
4783
|
for (const key of writtenKeys ?? Reflect.ownKeys(pb)) {
|
|
4761
4784
|
if (key === $OWNER) continue;
|
|
@@ -4775,7 +4798,7 @@ function notifyWrites(t) {
|
|
|
4775
4798
|
if (k !== null && (k._subs !== null || k._config & CONFIG_OVERRIDE)) {
|
|
4776
4799
|
let changed;
|
|
4777
4800
|
if (t.ovl) {
|
|
4778
|
-
changed = t.del
|
|
4801
|
+
changed = !!t.del?.size;
|
|
4779
4802
|
if (!changed) {
|
|
4780
4803
|
for (const key of Reflect.ownKeys(pb)) {
|
|
4781
4804
|
if (!hasOwn$1.call(old, key)) {
|
|
@@ -4930,7 +4953,7 @@ function serveShallow(target, key, v) {
|
|
|
4930
4953
|
function draftServe(target, proxy) {
|
|
4931
4954
|
if (writeScopes !== null && inDraft(target)) {
|
|
4932
4955
|
const ct = proxy?.[$TARGET];
|
|
4933
|
-
if (ct
|
|
4956
|
+
if (ct?.v !== undefined) writeScopes.add(scopeKey(ct));
|
|
4934
4957
|
}
|
|
4935
4958
|
return proxy;
|
|
4936
4959
|
}
|
|
@@ -4973,13 +4996,7 @@ function readSource(target, key, shape = false) {
|
|
|
4973
4996
|
// sees — the lanes' values and the tick's own guesses over the truth
|
|
4974
4997
|
// (#3665), never a staging awaiting its fold: the draft is born on the
|
|
4975
4998
|
// read (and notified at the setter's exit like any).
|
|
4976
|
-
if (
|
|
4977
|
-
userWrite &&
|
|
4978
|
-
target.fam !== null &&
|
|
4979
|
-
target.fam.opt === true &&
|
|
4980
|
-
!pendingNotify.has(target) &&
|
|
4981
|
-
inDraft(target)
|
|
4982
|
-
) {
|
|
4999
|
+
if (userWrite && target.fam?.opt === true && !pendingNotify.has(target) && inDraft(target)) {
|
|
4983
5000
|
const draft = ensurePB(target);
|
|
4984
5001
|
pendingNotify.add(target);
|
|
4985
5002
|
return draft;
|
|
@@ -5018,7 +5035,7 @@ function readSource(target, key, shape = false) {
|
|
|
5018
5035
|
// it).
|
|
5019
5036
|
if (key !== undefined) {
|
|
5020
5037
|
const leaf = target.n?.[key];
|
|
5021
|
-
if (leaf
|
|
5038
|
+
if (leaf?._config & CONFIG_OVERRIDE) return committed(target);
|
|
5022
5039
|
}
|
|
5023
5040
|
const held = k !== null && (k._config & CONFIG_HELD) !== 0;
|
|
5024
5041
|
// A held container: the hold's unit is the key (#3706). A key the HELD
|
|
@@ -5132,18 +5149,14 @@ function adoptChild(target, key) {
|
|
|
5132
5149
|
// A raw-marked value wraps to itself, a proxy to its own target: neither
|
|
5133
5150
|
// is a fresh target around `ov`.
|
|
5134
5151
|
const ct = wrap(ov, target, key)[$TARGET];
|
|
5135
|
-
if (ct
|
|
5152
|
+
if (ct?.v !== ov) return false;
|
|
5136
5153
|
adoptPB(ct, nv, false);
|
|
5137
5154
|
holdNode(getContainerNode(ct), txOf(k));
|
|
5138
5155
|
return true;
|
|
5139
5156
|
}
|
|
5140
5157
|
/** A family target's unheld staging, read with no pass (a handler). */
|
|
5141
5158
|
function familyAhead(target) {
|
|
5142
|
-
return (
|
|
5143
|
-
target.fam !== null &&
|
|
5144
|
-
context === null &&
|
|
5145
|
-
!(target.k !== null && target.k._config & CONFIG_HELD)
|
|
5146
|
-
);
|
|
5159
|
+
return target.fam !== null && context === null && !(target.k?._config & CONFIG_HELD);
|
|
5147
5160
|
}
|
|
5148
5161
|
/** Did this batch change `key` — value (slot equality), presence, and (for
|
|
5149
5162
|
* a `shape` reader — a descriptor read, a node's hold) enumerability or
|
|
@@ -5168,7 +5181,7 @@ function changedBetween(target, v, pb, key, shape) {
|
|
|
5168
5181
|
!plainProto(v)
|
|
5169
5182
|
)
|
|
5170
5183
|
return true;
|
|
5171
|
-
if (target.del
|
|
5184
|
+
if (target.del?.has(key)) return key in v;
|
|
5172
5185
|
const inNew = hasOwn$1.call(pb, key) || (target.ovl && hasOwn$1.call(target.v, key));
|
|
5173
5186
|
if (inNew !== hasOwn$1.call(v, key)) return true;
|
|
5174
5187
|
if (!inNew) return false;
|
|
@@ -5349,7 +5362,7 @@ function enumerationSource(target) {
|
|
|
5349
5362
|
* draft's (it composed already), not a derive's write-override read (the
|
|
5350
5363
|
* derive composes on the truth). */
|
|
5351
5364
|
function optRead(target) {
|
|
5352
|
-
return target.fam
|
|
5365
|
+
return target.fam?.opt === true && !inDraft(target) && !writeOverride;
|
|
5353
5366
|
}
|
|
5354
5367
|
/** Pollution keys are never served from the prototype (core R30). */
|
|
5355
5368
|
const UNSAFE_KEYS = new Set(["__proto__", "prototype", "constructor"]);
|
|
@@ -5371,6 +5384,47 @@ function touch(target, key) {
|
|
|
5371
5384
|
}
|
|
5372
5385
|
if (wk !== WK_ALL) (target.wk ??= new Set()).add(key);
|
|
5373
5386
|
}
|
|
5387
|
+
/** Dev: targets (and their keys) already warned about for a write outside
|
|
5388
|
+
* the setter — #4179's once-per-target+key memory. */
|
|
5389
|
+
let warnedOutsideWrites;
|
|
5390
|
+
/** Dev: set while the runtime itself writes through a proxy it knows the
|
|
5391
|
+
* trap ignores (`registerGraph`'s `_owner` stamp). */
|
|
5392
|
+
let internalOutsideWrite = false;
|
|
5393
|
+
/** Dev: a write, defineProperty or delete on a store proxy outside its
|
|
5394
|
+
* setter's draft is ignored (the trap returns `true` so strict-mode code
|
|
5395
|
+
* does not throw) — say so once per target+key instead of silently dropping
|
|
5396
|
+
* it (#4179). */
|
|
5397
|
+
function warnWriteOutsideSetter(target, key, operation) {
|
|
5398
|
+
if (internalOutsideWrite) return;
|
|
5399
|
+
warnedOutsideWrites ??= new WeakMap();
|
|
5400
|
+
let keys = warnedOutsideWrites.get(target);
|
|
5401
|
+
if (keys === undefined) warnedOutsideWrites.set(target, (keys = new Set()));
|
|
5402
|
+
if (keys.has(key)) return;
|
|
5403
|
+
keys.add(key);
|
|
5404
|
+
const name = String(key);
|
|
5405
|
+
const access =
|
|
5406
|
+
typeof key === "string" && /^[A-Za-z_$][\w$]*$/.test(key)
|
|
5407
|
+
? `.${key}`
|
|
5408
|
+
: typeof key === "string" && /^\d+$/.test(key)
|
|
5409
|
+
? `[${key}]`
|
|
5410
|
+
: `[${typeof key === "string" ? JSON.stringify(key) : name}]`;
|
|
5411
|
+
const hint =
|
|
5412
|
+
operation === "deleteProperty"
|
|
5413
|
+
? `setStore(s => { delete s${access} })`
|
|
5414
|
+
: `setStore(s => { s${access} = value })`;
|
|
5415
|
+
reportDiagnostic(
|
|
5416
|
+
emitDiagnostic({
|
|
5417
|
+
code: "STORE_WRITE_OUTSIDE_SETTER",
|
|
5418
|
+
kind: "write",
|
|
5419
|
+
severity: "warn",
|
|
5420
|
+
message:
|
|
5421
|
+
`[STORE_WRITE_OUTSIDE_SETTER] ${operation === "deleteProperty" ? "Deleting" : "Writing"} store property "${name}" outside its setter was ignored. ` +
|
|
5422
|
+
`Stores are read-only outside the setter's draft: use \`${hint}\`.`,
|
|
5423
|
+
nodeName: name,
|
|
5424
|
+
data: { operation, property: name }
|
|
5425
|
+
})
|
|
5426
|
+
);
|
|
5427
|
+
}
|
|
5374
5428
|
const traps = {
|
|
5375
5429
|
get(target, key, receiver) {
|
|
5376
5430
|
// One typeof gates every brand-symbol compare off the hot string path.
|
|
@@ -5434,7 +5488,7 @@ const traps = {
|
|
|
5434
5488
|
const src = readSource(target, key);
|
|
5435
5489
|
// Overlay delete (#3044): a prototype overlay cannot shadow a delete, so
|
|
5436
5490
|
// deleted keys are tracked aside and read as absent in the pending view.
|
|
5437
|
-
if (
|
|
5491
|
+
if (src === target.pb && target.del?.has(key)) {
|
|
5438
5492
|
if (!inDraft(target) && getObserver() !== null) read(getNode(target, key));
|
|
5439
5493
|
return undefined;
|
|
5440
5494
|
}
|
|
@@ -5462,7 +5516,8 @@ const traps = {
|
|
|
5462
5516
|
!inDraft(target) &&
|
|
5463
5517
|
typeof key === "string" &&
|
|
5464
5518
|
key !== "then" &&
|
|
5465
|
-
getObserver() === null
|
|
5519
|
+
getObserver() === null &&
|
|
5520
|
+
strictReadActive()
|
|
5466
5521
|
) {
|
|
5467
5522
|
warnStrictReadUntracked(strictRead, {
|
|
5468
5523
|
nodeName: key,
|
|
@@ -5566,7 +5621,7 @@ const traps = {
|
|
|
5566
5621
|
if (guessed !== undefined) return guessed;
|
|
5567
5622
|
}
|
|
5568
5623
|
}
|
|
5569
|
-
return key in src && !(
|
|
5624
|
+
return key in src && !(src === target.pb && target.del?.has(key));
|
|
5570
5625
|
},
|
|
5571
5626
|
ownKeys(target) {
|
|
5572
5627
|
if (verdict !== null && affectsHooks !== null && getObserver() === null)
|
|
@@ -5613,8 +5668,10 @@ const traps = {
|
|
|
5613
5668
|
},
|
|
5614
5669
|
set(target, key, value) {
|
|
5615
5670
|
const draft = inDraft(target);
|
|
5616
|
-
|
|
5617
|
-
|
|
5671
|
+
if (!draft && !writeOverride) {
|
|
5672
|
+
warnWriteOutsideSetter(target, key, "set");
|
|
5673
|
+
return true;
|
|
5674
|
+
}
|
|
5618
5675
|
if (key === "__proto__") return true; // pollution guard (core R30)
|
|
5619
5676
|
const uv = target.s ? value : unwrapValue(value);
|
|
5620
5677
|
const pb = ensurePB(target);
|
|
@@ -5637,17 +5694,8 @@ const traps = {
|
|
|
5637
5694
|
touch(target, key);
|
|
5638
5695
|
if (!(key in pb)) target.kc++;
|
|
5639
5696
|
}
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
value: uv,
|
|
5643
|
-
writable: true,
|
|
5644
|
-
enumerable: true,
|
|
5645
|
-
configurable: true
|
|
5646
|
-
});
|
|
5647
|
-
if (target.del !== null) target.del.delete(key);
|
|
5648
|
-
return true;
|
|
5649
|
-
}
|
|
5650
|
-
if (target.ovl && target.sc !== 2 && !hasOwn$1.call(pb, key)) {
|
|
5697
|
+
const unsafe = UNSAFE_KEYS.has(key);
|
|
5698
|
+
if (unsafe || (target.ovl && target.sc !== 2 && !hasOwn$1.call(pb, key))) {
|
|
5651
5699
|
Object.defineProperty(pb, key, {
|
|
5652
5700
|
value: uv,
|
|
5653
5701
|
writable: true,
|
|
@@ -5655,15 +5703,18 @@ const traps = {
|
|
|
5655
5703
|
configurable: true
|
|
5656
5704
|
});
|
|
5657
5705
|
} else pb[key] = uv;
|
|
5658
|
-
|
|
5706
|
+
target.del?.delete(key);
|
|
5707
|
+
if (unsafe) return true;
|
|
5659
5708
|
if (target.s && uv !== null && typeof uv === "object") markRawOne(uv);
|
|
5660
|
-
if (
|
|
5709
|
+
if (!draft) notifyWrites(target); // a write-override write
|
|
5661
5710
|
return true;
|
|
5662
5711
|
},
|
|
5663
5712
|
defineProperty(target, key, desc) {
|
|
5664
5713
|
const draft = inDraft(target);
|
|
5665
|
-
|
|
5666
|
-
|
|
5714
|
+
if (!draft && !writeOverride) {
|
|
5715
|
+
warnWriteOutsideSetter(target, key, "defineProperty");
|
|
5716
|
+
return true;
|
|
5717
|
+
}
|
|
5667
5718
|
if (key === "__proto__") return true;
|
|
5668
5719
|
if (desc.get || desc.set) target.a = true;
|
|
5669
5720
|
if ("value" in desc) desc = { ...desc, value: unwrapValue(desc.value) };
|
|
@@ -5671,14 +5722,16 @@ const traps = {
|
|
|
5671
5722
|
if (target.a || !(desc.enumerable && desc.writable && desc.configurable)) target.sc = 1;
|
|
5672
5723
|
touch(target, key);
|
|
5673
5724
|
Object.defineProperty(pb, key, desc);
|
|
5674
|
-
|
|
5675
|
-
if (
|
|
5725
|
+
target.del?.delete(key);
|
|
5726
|
+
if (!draft) notifyWrites(target); // a write-override write
|
|
5676
5727
|
return true;
|
|
5677
5728
|
},
|
|
5678
5729
|
deleteProperty(target, key) {
|
|
5679
5730
|
const draft = inDraft(target);
|
|
5680
|
-
|
|
5681
|
-
|
|
5731
|
+
if (!draft && !writeOverride) {
|
|
5732
|
+
warnWriteOutsideSetter(target, key, "deleteProperty");
|
|
5733
|
+
return true;
|
|
5734
|
+
}
|
|
5682
5735
|
const pb = ensurePB(target);
|
|
5683
5736
|
touch(target, key);
|
|
5684
5737
|
// The key count (`kc`, the overlay gate and the rebuild cap) follows a
|
|
@@ -5696,7 +5749,7 @@ const traps = {
|
|
|
5696
5749
|
committed || target.kc--;
|
|
5697
5750
|
}
|
|
5698
5751
|
if (committed) (target.del ??= new Set()).add(key);
|
|
5699
|
-
if (
|
|
5752
|
+
if (!draft) notifyWrites(target); // a write-override write
|
|
5700
5753
|
return true;
|
|
5701
5754
|
}
|
|
5702
5755
|
};
|
|
@@ -5836,8 +5889,11 @@ function createStore$1(initialValue, options) {
|
|
|
5836
5889
|
{
|
|
5837
5890
|
const owner = getOwner();
|
|
5838
5891
|
// Dev-tier graph registration (owner signal lists, onGraph); the
|
|
5839
|
-
// `_owner` write itself never reaches the proxy, see storeOwners
|
|
5892
|
+
// `_owner` write itself never reaches the proxy, see storeOwners — an
|
|
5893
|
+
// internal ignored write, not the user's (#4179's warning skips it).
|
|
5894
|
+
internalOutsideWrite = true;
|
|
5840
5895
|
registerGraph(proxy, owner);
|
|
5896
|
+
internalOutsideWrite = false;
|
|
5841
5897
|
// Only once the engine is installed, like the node stamping it feeds: a
|
|
5842
5898
|
// WeakMap.set per fresh store is a growing ephemeron table and,
|
|
5843
5899
|
// disabled, buys nothing.
|
|
@@ -5854,17 +5910,17 @@ function createStore$1(initialValue, options) {
|
|
|
5854
5910
|
* slot-patch channel (collected row bodies) over per-record registration. */
|
|
5855
5911
|
function storeIsShallow(proxy) {
|
|
5856
5912
|
const t = proxy?.[$TARGET];
|
|
5857
|
-
return t
|
|
5913
|
+
return t?.s === true;
|
|
5858
5914
|
}
|
|
5859
5915
|
/** True when `proxy` belongs to a projection family (S3). */
|
|
5860
5916
|
function storeHasFamily(proxy) {
|
|
5861
5917
|
const t = proxy?.[$TARGET];
|
|
5862
|
-
return t
|
|
5918
|
+
return t?.fam != null;
|
|
5863
5919
|
}
|
|
5864
5920
|
/** True when `proxy` belongs to an OPTIMISTIC family (S4). */
|
|
5865
5921
|
function storeHasOptimisticFamily(proxy) {
|
|
5866
5922
|
const t = proxy?.[$TARGET];
|
|
5867
|
-
return t
|
|
5923
|
+
return t?.fam?.opt === true;
|
|
5868
5924
|
}
|
|
5869
5925
|
// ---------------------------------------------------------------------------
|
|
5870
5926
|
// enumeration views (one visibility rule for the traps AND the deep walk)
|
|
@@ -5873,7 +5929,7 @@ function visibleKeys(target, src) {
|
|
|
5873
5929
|
if (target.ovl && src === target.pb) {
|
|
5874
5930
|
keys = Reflect.ownKeys(target.v);
|
|
5875
5931
|
const del = target.del;
|
|
5876
|
-
if (del
|
|
5932
|
+
if (del?.size) keys = keys.filter(key => !del.has(key));
|
|
5877
5933
|
for (const key of Reflect.ownKeys(src)) {
|
|
5878
5934
|
if (!hasOwn$1.call(target.v, key)) keys.push(key);
|
|
5879
5935
|
}
|
|
@@ -5890,7 +5946,7 @@ function visibleKeys(target, src) {
|
|
|
5890
5946
|
function visibleDescriptor(target, src, key) {
|
|
5891
5947
|
let desc = Object.getOwnPropertyDescriptor(src, key);
|
|
5892
5948
|
if (target.ovl && src === target.pb) {
|
|
5893
|
-
if (target.del
|
|
5949
|
+
if (target.del?.has(key)) return undefined;
|
|
5894
5950
|
if (desc === undefined) desc = Object.getOwnPropertyDescriptor(target.v, key);
|
|
5895
5951
|
}
|
|
5896
5952
|
return desc;
|
|
@@ -5901,7 +5957,7 @@ function visibleDescriptor(target, src, key) {
|
|
|
5901
5957
|
* witness (one node per record, not one per path), then snapshots. */
|
|
5902
5958
|
function deep$1(value) {
|
|
5903
5959
|
const t0 = value?.[$TARGET];
|
|
5904
|
-
if (t0
|
|
5960
|
+
if (t0?.px !== value) return value;
|
|
5905
5961
|
const visited = new Set();
|
|
5906
5962
|
const childTarget = (t, child, key) => {
|
|
5907
5963
|
let ct = lookupTarget(child, t.fam);
|
|
@@ -6143,8 +6199,8 @@ const storePath = /* @__PURE__ */ Object.assign(
|
|
|
6143
6199
|
*/
|
|
6144
6200
|
function reconcileState(value, state, key, replace = false) {
|
|
6145
6201
|
if (state == null) throw new Error("Cannot reconcile null or undefined state");
|
|
6146
|
-
const t = state
|
|
6147
|
-
if (t
|
|
6202
|
+
const t = state[$TARGET];
|
|
6203
|
+
if (t?.px !== state) throw new Error("reconcile target is not a store proxy");
|
|
6148
6204
|
const keyFn = key === null ? null : typeof key === "string" ? item => item?.[key] : key;
|
|
6149
6205
|
// A user's reconcile on an optimistic family (S4): not an adoption of
|
|
6150
6206
|
// truth but an optimistic edit — the keyed diff is written into the draft
|
|
@@ -6169,9 +6225,8 @@ function reconcileState(value, state, key, replace = false) {
|
|
|
6169
6225
|
if (!replace) throw new Error("Cannot reconcile states with different identity");
|
|
6170
6226
|
// A different entity at the root: the old backing is disowned (wraps
|
|
6171
6227
|
// fresh if re-handed) and the new one adopted whole.
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
else (t.fam?.map ?? storeLookup).delete(out);
|
|
6228
|
+
if (isOwned(prev)) delete prev[$OWNER];
|
|
6229
|
+
else (t.fam?.map ?? storeLookup).delete(prev);
|
|
6175
6230
|
adoptPB(t, incoming);
|
|
6176
6231
|
return;
|
|
6177
6232
|
}
|
|
@@ -6187,50 +6242,42 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6187
6242
|
// as present through its prototype; materialized first — `adoptPB` does
|
|
6188
6243
|
// so anyway, after the base was taken — so a deletion the draft made is
|
|
6189
6244
|
// a deletion here (#3743: the presence and value diffs both read `old`).
|
|
6190
|
-
const
|
|
6191
|
-
if (incoming ===
|
|
6192
|
-
const fam = t.fam;
|
|
6245
|
+
const old = t.ovl ? materializePB(t) : (t.pb ?? t.v);
|
|
6246
|
+
if (incoming === old && !isOwned(old)) return;
|
|
6193
6247
|
// Q-D: a landing on an optimistic family is reconciled against the VIEW
|
|
6194
6248
|
// — key matching from the arrangement the guesses made (R28), so a row
|
|
6195
6249
|
// the guess added keeps its proxy when the server returns it.
|
|
6196
|
-
const prevView = fam?.opt === true ? optHooks.view(t,
|
|
6250
|
+
const prevView = t.fam?.opt === true ? optHooks.view(t, old) : old;
|
|
6197
6251
|
const nextArr = Array.isArray(incoming);
|
|
6198
6252
|
const shallow = t.s === true;
|
|
6199
|
-
const old = prev;
|
|
6200
6253
|
adoptPB(t, incoming, false);
|
|
6201
6254
|
if (shallow) markRawIngest(incoming);
|
|
6255
|
+
// The deep witness is bumped once per adoption (none to bump: done).
|
|
6256
|
+
let bumped = t.dk === null;
|
|
6202
6257
|
if (Array.isArray(prevView) !== nextArr) {
|
|
6203
6258
|
notifyFold(t, old, incoming);
|
|
6204
6259
|
return;
|
|
6205
6260
|
}
|
|
6206
6261
|
if (nextArr) {
|
|
6207
|
-
const prevRows = prevView;
|
|
6208
|
-
const nextRows = incoming;
|
|
6209
6262
|
const nodes = t.n;
|
|
6210
6263
|
let nodesHit = 0;
|
|
6211
6264
|
if (keyFn && !shallow) {
|
|
6212
|
-
const plen =
|
|
6213
|
-
const nlen =
|
|
6214
|
-
let dkBumpedA = false;
|
|
6265
|
+
const plen = prevView.length;
|
|
6266
|
+
const nlen = incoming.length;
|
|
6215
6267
|
let i = 0;
|
|
6216
6268
|
// Aligned prefix: same row (by reference or key) at the same index.
|
|
6217
6269
|
for (const end = Math.min(plen, nlen); i < end; i++) {
|
|
6218
|
-
const nv =
|
|
6219
|
-
const pvRaw =
|
|
6270
|
+
const nv = incoming[i];
|
|
6271
|
+
const pvRaw = prevView[i];
|
|
6220
6272
|
if (pvRaw !== nv && !sameRow$1(pvRaw, nv, keyFn)) break; // misaligned: fall to the keyed remainder below
|
|
6273
|
+
if (nv !== null && typeof nv === "object" && (pvRaw !== nv || isOwned(nv)))
|
|
6274
|
+
descend(unwrapValue(pvRaw), nv, keyFn, proj, t, i);
|
|
6221
6275
|
if (
|
|
6222
|
-
|
|
6223
|
-
nv !== null &&
|
|
6224
|
-
typeof nv === "object"
|
|
6225
|
-
)
|
|
6226
|
-
descend(unwrapValue(pvRaw), nv, keyFn, fam, proj);
|
|
6227
|
-
if (
|
|
6228
|
-
t.dk !== null &&
|
|
6229
|
-
!dkBumpedA &&
|
|
6276
|
+
!bumped &&
|
|
6230
6277
|
!(nv !== null && typeof nv === "object" ? targetsEqual(pvRaw, nv) : isEqual(pvRaw, nv))
|
|
6231
6278
|
) {
|
|
6232
6279
|
bumpDeep(t);
|
|
6233
|
-
|
|
6280
|
+
bumped = true;
|
|
6234
6281
|
}
|
|
6235
6282
|
if (nodes !== null) {
|
|
6236
6283
|
const node = nodes[i];
|
|
@@ -6240,19 +6287,19 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6240
6287
|
}
|
|
6241
6288
|
}
|
|
6242
6289
|
}
|
|
6243
|
-
if (
|
|
6290
|
+
if (!bumped && i < incoming.length) bumpDeep(t);
|
|
6244
6291
|
const structStart = i; // misalignment point (== nlen on aligned ticks)
|
|
6245
6292
|
let prevByKey = null;
|
|
6246
|
-
for (; i <
|
|
6247
|
-
const nv =
|
|
6293
|
+
for (; i < incoming.length; i++) {
|
|
6294
|
+
const nv = incoming[i];
|
|
6248
6295
|
if (nv !== null && typeof nv === "object") {
|
|
6249
6296
|
const nk = keyFn(nv);
|
|
6250
6297
|
let pv;
|
|
6251
6298
|
if (nk !== undefined) {
|
|
6252
6299
|
if (prevByKey === null) {
|
|
6253
6300
|
prevByKey = new Map();
|
|
6254
|
-
for (let j = structStart; j <
|
|
6255
|
-
const p = unwrapValue(
|
|
6301
|
+
for (let j = structStart; j < prevView.length; j++) {
|
|
6302
|
+
const p = unwrapValue(prevView[j]);
|
|
6256
6303
|
if (p !== null && typeof p === "object") {
|
|
6257
6304
|
const pk = keyFn(p);
|
|
6258
6305
|
if (pk === undefined) continue;
|
|
@@ -6266,16 +6313,16 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6266
6313
|
const m = prevByKey.get(nk);
|
|
6267
6314
|
if (m === undefined) pv = undefined;
|
|
6268
6315
|
else if (Array.isArray(m)) {
|
|
6269
|
-
pv = unwrapValue(
|
|
6316
|
+
pv = unwrapValue(prevView[m.shift()]);
|
|
6270
6317
|
if (m.length === 1) prevByKey.set(nk, m[0]);
|
|
6271
6318
|
} else {
|
|
6272
|
-
pv = unwrapValue(
|
|
6319
|
+
pv = unwrapValue(prevView[m]);
|
|
6273
6320
|
prevByKey.delete(nk);
|
|
6274
6321
|
}
|
|
6275
6322
|
} else {
|
|
6276
|
-
pv = unwrapValue(
|
|
6323
|
+
pv = unwrapValue(prevView[i]); // keyless item: positional fallback
|
|
6277
6324
|
}
|
|
6278
|
-
descend(pv, nv, keyFn,
|
|
6325
|
+
descend(pv, nv, keyFn, proj, t, i);
|
|
6279
6326
|
}
|
|
6280
6327
|
if (nodes !== null) {
|
|
6281
6328
|
const node = nodes[i];
|
|
@@ -6286,22 +6333,20 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6286
6333
|
}
|
|
6287
6334
|
}
|
|
6288
6335
|
} else {
|
|
6289
|
-
const dlen = Math.min(
|
|
6290
|
-
const nlen =
|
|
6291
|
-
let dkBumpedP = false;
|
|
6336
|
+
const dlen = Math.min(prevView.length, incoming.length);
|
|
6337
|
+
const nlen = incoming.length;
|
|
6292
6338
|
for (let i = 0; i < nlen; i++) {
|
|
6293
|
-
const nvP =
|
|
6339
|
+
const nvP = incoming[i];
|
|
6294
6340
|
if (!shallow && i < dlen && nvP !== null && typeof nvP === "object")
|
|
6295
|
-
descend(unwrapValue(
|
|
6341
|
+
descend(unwrapValue(prevView[i]), nvP, keyFn, proj, t, i);
|
|
6296
6342
|
if (
|
|
6297
|
-
|
|
6298
|
-
!dkBumpedP &&
|
|
6343
|
+
!bumped &&
|
|
6299
6344
|
!(nvP !== null && typeof nvP === "object"
|
|
6300
|
-
? targetsEqual(
|
|
6301
|
-
: isEqual(
|
|
6345
|
+
? targetsEqual(prevView[i], nvP)
|
|
6346
|
+
: isEqual(prevView[i], nvP))
|
|
6302
6347
|
) {
|
|
6303
6348
|
bumpDeep(t);
|
|
6304
|
-
|
|
6349
|
+
bumped = true;
|
|
6305
6350
|
}
|
|
6306
6351
|
if (nodes !== null) {
|
|
6307
6352
|
const node = nodes[i];
|
|
@@ -6316,7 +6361,7 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6316
6361
|
if (nodes !== null && nodesHit < t.nc) {
|
|
6317
6362
|
for (const key of Reflect.ownKeys(nodes)) {
|
|
6318
6363
|
const idx = typeof key === "string" ? +key : NaN;
|
|
6319
|
-
if (!(idx >= 0 && idx <
|
|
6364
|
+
if (!(idx >= 0 && idx < incoming.length))
|
|
6320
6365
|
notifyKeyDiff(nodes[key], key, old, incoming, false);
|
|
6321
6366
|
}
|
|
6322
6367
|
}
|
|
@@ -6325,7 +6370,6 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6325
6370
|
}
|
|
6326
6371
|
const nodes = t.n;
|
|
6327
6372
|
let nodesHit = 0;
|
|
6328
|
-
let dkBumped = false;
|
|
6329
6373
|
for (const k in incoming) {
|
|
6330
6374
|
const nv = incoming[k];
|
|
6331
6375
|
const ov = old[k];
|
|
@@ -6335,13 +6379,13 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6335
6379
|
(!isObj || !isOwned(nv)) &&
|
|
6336
6380
|
(nodes === null || nodes[k] === undefined || !hasAccessorFlag(nodes[k]))
|
|
6337
6381
|
) {
|
|
6338
|
-
if (nodes
|
|
6382
|
+
if (nodes?.[k] !== undefined) nodesHit++;
|
|
6339
6383
|
continue;
|
|
6340
6384
|
}
|
|
6341
|
-
if (isObj && !shallow) descend(unwrapValue(prevView[k]), nv, keyFn,
|
|
6342
|
-
if (
|
|
6385
|
+
if (isObj && !shallow) descend(unwrapValue(prevView[k]), nv, keyFn, proj, t, k);
|
|
6386
|
+
if (!bumped && !(isObj ? targetsEqual(ov, nv) : isEqual(ov, nv))) {
|
|
6343
6387
|
bumpDeep(t);
|
|
6344
|
-
|
|
6388
|
+
bumped = true;
|
|
6345
6389
|
}
|
|
6346
6390
|
if (nodes !== null) {
|
|
6347
6391
|
const node = nodes[k];
|
|
@@ -6357,7 +6401,7 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6357
6401
|
if (k === $OWNER) continue;
|
|
6358
6402
|
const nv = incoming[k];
|
|
6359
6403
|
if (!shallow && nv !== null && typeof nv === "object")
|
|
6360
|
-
descend(unwrapValue(old[k]), nv, keyFn,
|
|
6404
|
+
descend(unwrapValue(old[k]), nv, keyFn, proj, t, k);
|
|
6361
6405
|
if (nodes !== null) {
|
|
6362
6406
|
const node = nodes[k];
|
|
6363
6407
|
if (node !== undefined) {
|
|
@@ -6377,16 +6421,39 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6377
6421
|
const hasOwnP = Object.prototype.hasOwnProperty;
|
|
6378
6422
|
/** Descend into a changed child pair — only where something is proxied
|
|
6379
6423
|
* below (§6d), never into a raw-marked leaf, never across array/object or a
|
|
6380
|
-
* key mismatch (that is a replacement, handled by the parent's slot).
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6424
|
+
* key mismatch (that is a replacement, handled by the parent's slot).
|
|
6425
|
+
*
|
|
6426
|
+
* A raw in both frames (the same objects swapped, reordered or shifted,
|
|
6427
|
+
* #4001) must not leave two slots on one row. A raw already a live row keeps
|
|
6428
|
+
* it at the slot it moved to; a row's `pk` follows the slot it sits at (a
|
|
6429
|
+
* move or a pairing writes it), so a row whose raw is at that slot of the
|
|
6430
|
+
* incoming frame is spoken for and not paired again here; a raw still
|
|
6431
|
+
* resolving to a row that moved on drops the lookup (it wraps fresh, or is
|
|
6432
|
+
* paired here). One lookup of `nv` on the common path, no allocation. */
|
|
6433
|
+
function descend(pv, nv, keyFn, proj, t, k) {
|
|
6434
|
+
// `nv` is an object at every call site.
|
|
6435
|
+
if (pv === null || typeof pv !== "object") return;
|
|
6436
|
+
const fam = t.fam;
|
|
6437
|
+
nv = unwrapValue(nv);
|
|
6438
|
+
let ct = lookupTarget(pv, fam);
|
|
6439
|
+
const nt = lookupTarget(nv, fam);
|
|
6440
|
+
if (ct !== undefined && ct.pk !== k) {
|
|
6441
|
+
if (ct.pk != k && t.v[ct.pk] === ct.v) ct = undefined;
|
|
6442
|
+
else if (ct.u === t) ct.pk = k;
|
|
6443
|
+
}
|
|
6444
|
+
if (nt !== undefined && nt !== ct) {
|
|
6445
|
+
if (nt.v === nv) {
|
|
6446
|
+
if (nt.u === t) nt.pk = k;
|
|
6447
|
+
return;
|
|
6448
|
+
}
|
|
6449
|
+
(fam?.map ?? storeLookup).delete(nv);
|
|
6450
|
+
}
|
|
6384
6451
|
if (ct === undefined) return; // nothing proxied below this pair
|
|
6385
6452
|
if (!isWrappable(nv)) return;
|
|
6386
6453
|
if (rawValuesUsed && isRawValue(nv)) return;
|
|
6387
|
-
nv = unwrapValue(nv);
|
|
6388
6454
|
if (Array.isArray(pv) !== Array.isArray(nv)) return;
|
|
6389
|
-
|
|
6455
|
+
// An array slot was paired by key already (or both rows are keyless).
|
|
6456
|
+
if (typeof k !== "number" && keyFn) {
|
|
6390
6457
|
const pk = keyFn(pv);
|
|
6391
6458
|
const nk = keyFn(nv);
|
|
6392
6459
|
if (pk !== undefined && nk !== undefined && !sameKey(pk, nk)) return;
|
|
@@ -6809,10 +6876,12 @@ function notifyOptimisticWrites(t, pb) {
|
|
|
6809
6876
|
if (structural) {
|
|
6810
6877
|
const rows = isArr ? pb.map(unwrapValue) : shallowKeys(pb);
|
|
6811
6878
|
// The rows the setter removed from the view it saw, by key: a later
|
|
6812
|
-
// re-base over another action's truth must not bring them back.
|
|
6879
|
+
// re-base over another action's truth must not bring them back. A set
|
|
6880
|
+
// (empty or not) marks a keyed arrangement guess (`fold`).
|
|
6813
6881
|
let removed = null;
|
|
6814
6882
|
const keyFn = t.fam.key;
|
|
6815
6883
|
if (isArr && keyFn !== null && keyFn !== undefined) {
|
|
6884
|
+
removed = new Set();
|
|
6816
6885
|
const kept = new Set();
|
|
6817
6886
|
for (let i = 0; i < rows.length; i++) {
|
|
6818
6887
|
const k = isWrappable(rows[i]) ? keyFn(rows[i]) : undefined;
|
|
@@ -6821,7 +6890,7 @@ function notifyOptimisticWrites(t, pb) {
|
|
|
6821
6890
|
for (let i = 0; i < old.length; i++) {
|
|
6822
6891
|
const r = unwrapValue(old[i]);
|
|
6823
6892
|
const k = isWrappable(r) ? keyFn(r) : undefined;
|
|
6824
|
-
if (k !== undefined && !kept.has(k))
|
|
6893
|
+
if (k !== undefined && !kept.has(k)) removed.add(k);
|
|
6825
6894
|
}
|
|
6826
6895
|
}
|
|
6827
6896
|
optimisticWrite(getContainerNode(t), new LaneView(rows, base, removed));
|
|
@@ -6957,7 +7026,8 @@ function reconcileDraft(draft, incoming, keyFn) {
|
|
|
6957
7026
|
* committed length differs, and as the `LaneView`'s base for structural
|
|
6958
7027
|
* reads. Unkeyed families compose
|
|
6959
7028
|
* positionally — the guess stands as written (the documented residue). */
|
|
6960
|
-
GlobalQueue._laneRebase = (el, truth) => {
|
|
7029
|
+
GlobalQueue._laneRebase = (el, truth, older) => {
|
|
7030
|
+
if (!older) return fold(el, truth);
|
|
6961
7031
|
const t = el._host;
|
|
6962
7032
|
if (t === undefined || el._key !== $TRACK) return;
|
|
6963
7033
|
const view = el._x._lane;
|
|
@@ -7018,6 +7088,51 @@ GlobalQueue._laneRebase = (el, truth) => {
|
|
|
7018
7088
|
laneSet(len, rows.length, lane);
|
|
7019
7089
|
}
|
|
7020
7090
|
};
|
|
7091
|
+
/** D-34 for a keyed arrangement guess: rows by key, not positions. A
|
|
7092
|
+
* current truth that differs folds into the hold beneath it instead of
|
|
7093
|
+
* voiding the lane: the guess stays the lane's value and the screen's until
|
|
7094
|
+
* the hold commits, where rows match by key, and the graph outside the lane
|
|
7095
|
+
* re-derives from the truth now (`foldedRead`). A confirmation is silent
|
|
7096
|
+
* (A17): only truth readers are told. True: the lane stages the truth
|
|
7097
|
+
* beneath (`laneWrite`). */
|
|
7098
|
+
function fold(el, truth) {
|
|
7099
|
+
const k = el._host?.k;
|
|
7100
|
+
const l = txOf(el);
|
|
7101
|
+
// A guess the screen never showed is void at the correction (D-34); a
|
|
7102
|
+
// keyed arrangement guess's view carries its removed-keys set.
|
|
7103
|
+
if (!l._shown || !(k?._config & CONFIG_OVERRIDE) || !k._x._lane?.removed) return false;
|
|
7104
|
+
const guess = el._x._lane;
|
|
7105
|
+
if ((!el._equals || !el._equals(guess, truth)) && !GlobalQueue._echoes(guess, truth)) {
|
|
7106
|
+
l.folded = foldedRead;
|
|
7107
|
+
insertSubs(el);
|
|
7108
|
+
} else GlobalQueue._confirmed?.(l);
|
|
7109
|
+
joinFuture(resolveTx(l._parent ?? l));
|
|
7110
|
+
return true;
|
|
7111
|
+
}
|
|
7112
|
+
/** A folded lane's guess read by a deriving pass outside the lane, tracked
|
|
7113
|
+
* or not (`untrack` is about dependencies, not about which world a pass
|
|
7114
|
+
* derives from), or by `latest()` (`c` null): the hold's world — the truth
|
|
7115
|
+
* staged beneath the guess, else the value it covered — and the pass joins
|
|
7116
|
+
* the hold. Lane passes and the screen keep the guess: held truth is masked
|
|
7117
|
+
* from lane passes only (#3164). The store's own derive reconciles its
|
|
7118
|
+
* landings against the arrangement the guesses made: it is the author, not
|
|
7119
|
+
* a reader. */
|
|
7120
|
+
function foldedRead(c, el) {
|
|
7121
|
+
if (c !== null) {
|
|
7122
|
+
if (
|
|
7123
|
+
!(el._config & CONFIG_GUESS) ||
|
|
7124
|
+
passLane !== null ||
|
|
7125
|
+
c._type === EFFECT_RENDER ||
|
|
7126
|
+
c._config & CONFIG_CHILDREN_FORBIDDEN ||
|
|
7127
|
+
el._host?.fam?.node === c
|
|
7128
|
+
)
|
|
7129
|
+
return NOT_PENDING;
|
|
7130
|
+
const l = txOf(el);
|
|
7131
|
+
joinPassAt(c, resolveTx(l._parent ?? l));
|
|
7132
|
+
}
|
|
7133
|
+
if (el._pendingValue !== NOT_PENDING) return el._pendingValue;
|
|
7134
|
+
return el._config & CONFIG_SLOT_NODE ? GlobalQueue._slotCovered(el) : el._value;
|
|
7135
|
+
}
|
|
7021
7136
|
function sameRow(a, b, keyFn) {
|
|
7022
7137
|
if (a === b) return true;
|
|
7023
7138
|
if (!isWrappable(a) || !isWrappable(b)) return false;
|
|
@@ -8774,6 +8889,7 @@ function createDeferred(fn, options) {
|
|
|
8774
8889
|
// The wrapping form: an unready source parks the node in the window,
|
|
8775
8890
|
// and the wait is its flight until the source's settle re-runs it.
|
|
8776
8891
|
if (open && e instanceof NotReadyError) ask(e);
|
|
8892
|
+
else land(flight);
|
|
8777
8893
|
throw e;
|
|
8778
8894
|
}
|
|
8779
8895
|
if (open && typeof r === "object" && r !== null) {
|
|
@@ -8794,7 +8910,11 @@ function createDeferred(fn, options) {
|
|
|
8794
8910
|
// promise, as for a plain flight: verdict and value in one flush.
|
|
8795
8911
|
next: v => {
|
|
8796
8912
|
const p = it.next(v);
|
|
8797
|
-
if (first)
|
|
8913
|
+
if (first) {
|
|
8914
|
+
first = false;
|
|
8915
|
+
if (isThenable(p)) p.then(done, done);
|
|
8916
|
+
else done();
|
|
8917
|
+
}
|
|
8798
8918
|
return p;
|
|
8799
8919
|
},
|
|
8800
8920
|
return: v => it.return?.(v) ?? Promise.resolve({ done: true, value: v })
|
|
@@ -8809,6 +8929,238 @@ function createDeferred(fn, options) {
|
|
|
8809
8929
|
);
|
|
8810
8930
|
}
|
|
8811
8931
|
|
|
8932
|
+
// `from` — a push source (callback subscription, Observable, AsyncIterable)
|
|
8933
|
+
// as an AsyncIterable a computation can return or `for await` over:
|
|
8934
|
+
//
|
|
8935
|
+
// const value = createMemo(() => from(source));
|
|
8936
|
+
//
|
|
8937
|
+
// A subscription keeps the latest value: values that arrive between pulls
|
|
8938
|
+
// coalesce. An AsyncIterable streams through unchanged. Either way the source
|
|
8939
|
+
// opens when the result is iterated and closes on return(), on supersede (the
|
|
8940
|
+
// owning computation re-runs) and on owner disposal, whichever comes first.
|
|
8941
|
+
function toSubscribe(source) {
|
|
8942
|
+
if (typeof source === "function") return source;
|
|
8943
|
+
// TC39 / RxJS interop: `Symbol.observable` (or "@@observable") returns the observable.
|
|
8944
|
+
// Read per call, not at module scope, so the module stays side-effect free.
|
|
8945
|
+
const $$observable = Symbol.observable;
|
|
8946
|
+
const interop = ($$observable && source?.[$$observable]) ?? source?.["@@observable"];
|
|
8947
|
+
const obs = typeof interop === "function" ? interop.call(source) : source;
|
|
8948
|
+
if (obs && typeof obs.subscribe === "function")
|
|
8949
|
+
return (next, error, complete) => obs.subscribe({ next, error, complete });
|
|
8950
|
+
return null;
|
|
8951
|
+
}
|
|
8952
|
+
const DONE = { value: undefined, done: true };
|
|
8953
|
+
/**
|
|
8954
|
+
* Ties an iterator's `finish` to the computation iterating it. Solid reaches
|
|
8955
|
+
* an iterator's return() only when the compute returns the iterable directly.
|
|
8956
|
+
* Inside an async generator the generator's own return() is queued behind its
|
|
8957
|
+
* pending `await`, and owner cleanups wait for the replacing pass to commit,
|
|
8958
|
+
* so close on supersede, with owner disposal as the backstop. No owner (an
|
|
8959
|
+
* async compute iterating it after its first `await`, or plain iteration):
|
|
8960
|
+
* no registration and no diagnostic, so only return() closes it. Scopes that
|
|
8961
|
+
* forbid cleanups rely on supersede and return().
|
|
8962
|
+
*/
|
|
8963
|
+
function bindToOwner(finish) {
|
|
8964
|
+
const owner = getOwner();
|
|
8965
|
+
if (!owner) return;
|
|
8966
|
+
onSupersede(finish);
|
|
8967
|
+
if (!(owner._config & CONFIG_CHILDREN_FORBIDDEN)) cleanup(finish);
|
|
8968
|
+
}
|
|
8969
|
+
/**
|
|
8970
|
+
* An AsyncIterable as a stream bound to the iterating computation: every
|
|
8971
|
+
* value passes through (no coalescing). `finish` calls the inner return()
|
|
8972
|
+
* once and settles pending pulls as done, so a `for await` over it exits as
|
|
8973
|
+
* soon as the computation re-runs — even when the inner iterator is an async
|
|
8974
|
+
* generator whose own return() the language queues behind its pending
|
|
8975
|
+
* `await`.
|
|
8976
|
+
*/
|
|
8977
|
+
function wrapIterable(source) {
|
|
8978
|
+
return {
|
|
8979
|
+
[Symbol.asyncIterator]() {
|
|
8980
|
+
const it = source[Symbol.asyncIterator]();
|
|
8981
|
+
let closed = false;
|
|
8982
|
+
const pending = new Set();
|
|
8983
|
+
const finish = () => {
|
|
8984
|
+
if (closed) return DONE;
|
|
8985
|
+
closed = true;
|
|
8986
|
+
for (const resolve of pending) resolve(DONE);
|
|
8987
|
+
pending.clear();
|
|
8988
|
+
try {
|
|
8989
|
+
const returned = it.return?.();
|
|
8990
|
+
if (isThenable(returned)) returned.then(undefined, () => {});
|
|
8991
|
+
} catch {}
|
|
8992
|
+
return DONE;
|
|
8993
|
+
};
|
|
8994
|
+
bindToOwner(finish);
|
|
8995
|
+
return {
|
|
8996
|
+
next(...args) {
|
|
8997
|
+
if (closed) return Promise.resolve(DONE);
|
|
8998
|
+
const step = it.next(...args);
|
|
8999
|
+
// A bare result (the producer's buffered fast path) passes through.
|
|
9000
|
+
if (!isThenable(step)) return step;
|
|
9001
|
+
return new Promise((resolve, reject) => {
|
|
9002
|
+
pending.add(resolve);
|
|
9003
|
+
step.then(
|
|
9004
|
+
r => pending.delete(resolve) && resolve(r),
|
|
9005
|
+
e => pending.delete(resolve) && reject(e)
|
|
9006
|
+
);
|
|
9007
|
+
});
|
|
9008
|
+
},
|
|
9009
|
+
return() {
|
|
9010
|
+
return Promise.resolve(finish());
|
|
9011
|
+
}
|
|
9012
|
+
};
|
|
9013
|
+
}
|
|
9014
|
+
};
|
|
9015
|
+
}
|
|
9016
|
+
const toCleanup = t =>
|
|
9017
|
+
typeof t === "function"
|
|
9018
|
+
? t
|
|
9019
|
+
: t && typeof t.unsubscribe === "function"
|
|
9020
|
+
? () => t.unsubscribe()
|
|
9021
|
+
: () => {};
|
|
9022
|
+
/**
|
|
9023
|
+
* Converts a callback subscription, an Observable or an AsyncIterable into an
|
|
9024
|
+
* AsyncIterable for a Solid computation. A subscription keeps only the latest
|
|
9025
|
+
* value, and a value the source emits during `subscribe` is served without a
|
|
9026
|
+
* loading frame; an AsyncIterable streams every value through.
|
|
9027
|
+
*
|
|
9028
|
+
* The source closes on supersede — the owning computation re-running — and
|
|
9029
|
+
* on owner disposal. Inside an async generator memo that holds for a
|
|
9030
|
+
* `for await` that starts before the first `await`; one that starts after it
|
|
9031
|
+
* has no owner to bind to, so its source closes only when the loop ends.
|
|
9032
|
+
* Prefer returning `from(...)` from its own memo, with awaited inputs read
|
|
9033
|
+
* from upstream memos and transforms done in a downstream memo.
|
|
9034
|
+
*
|
|
9035
|
+
* Iterate the result with `for await` or return it from a computation: its
|
|
9036
|
+
* `next()` returns an already-buffered value as a bare result, not a promise.
|
|
9037
|
+
*
|
|
9038
|
+
* @example
|
|
9039
|
+
* ```ts
|
|
9040
|
+
* const position = createMemo(() =>
|
|
9041
|
+
* from<Position>((next, error) => {
|
|
9042
|
+
* const id = navigator.geolocation.watchPosition(next, error);
|
|
9043
|
+
* return () => navigator.geolocation.clearWatch(id);
|
|
9044
|
+
* })
|
|
9045
|
+
* );
|
|
9046
|
+
* const ticks = createMemo(() => from(interval$(rate())));
|
|
9047
|
+
* ```
|
|
9048
|
+
*/
|
|
9049
|
+
function from(source) {
|
|
9050
|
+
const subscribe = toSubscribe(source);
|
|
9051
|
+
if (!subscribe) {
|
|
9052
|
+
if (source && typeof source[Symbol.asyncIterator] === "function") return wrapIterable(source);
|
|
9053
|
+
throw new TypeError("from(): expected a subscribe function, an Observable or an AsyncIterable");
|
|
9054
|
+
}
|
|
9055
|
+
return {
|
|
9056
|
+
[Symbol.asyncIterator]() {
|
|
9057
|
+
let latest;
|
|
9058
|
+
let has = false;
|
|
9059
|
+
let done = false;
|
|
9060
|
+
let failed = false;
|
|
9061
|
+
let failure;
|
|
9062
|
+
let waiting = null;
|
|
9063
|
+
let unsubscribe = null;
|
|
9064
|
+
let closed = false;
|
|
9065
|
+
const close = () => {
|
|
9066
|
+
if (closed) return;
|
|
9067
|
+
closed = true;
|
|
9068
|
+
done = true;
|
|
9069
|
+
const c = unsubscribe;
|
|
9070
|
+
unsubscribe = null;
|
|
9071
|
+
// A throwing unsubscribe must not escape: at supersede this runs
|
|
9072
|
+
// inside flush(), ahead of the replacing pass (the returned-iterator
|
|
9073
|
+
// path swallows it the same way).
|
|
9074
|
+
try {
|
|
9075
|
+
c?.();
|
|
9076
|
+
} catch {}
|
|
9077
|
+
};
|
|
9078
|
+
const settle = () => {
|
|
9079
|
+
if (!waiting) return;
|
|
9080
|
+
const w = waiting;
|
|
9081
|
+
if (has) {
|
|
9082
|
+
waiting = null;
|
|
9083
|
+
has = false;
|
|
9084
|
+
w.resolve({ value: latest, done: false });
|
|
9085
|
+
} else if (failed) {
|
|
9086
|
+
waiting = null;
|
|
9087
|
+
failed = false;
|
|
9088
|
+
w.reject(failure);
|
|
9089
|
+
} else if (done) {
|
|
9090
|
+
waiting = null;
|
|
9091
|
+
w.resolve({ value: undefined, done: true });
|
|
9092
|
+
}
|
|
9093
|
+
};
|
|
9094
|
+
const teardown = subscribe(
|
|
9095
|
+
value => {
|
|
9096
|
+
if (done) return;
|
|
9097
|
+
latest = value;
|
|
9098
|
+
has = true;
|
|
9099
|
+
settle();
|
|
9100
|
+
},
|
|
9101
|
+
err => {
|
|
9102
|
+
if (done) return;
|
|
9103
|
+
failed = true;
|
|
9104
|
+
failure = err;
|
|
9105
|
+
done = true;
|
|
9106
|
+
settle();
|
|
9107
|
+
close();
|
|
9108
|
+
},
|
|
9109
|
+
() => {
|
|
9110
|
+
if (done) return;
|
|
9111
|
+
done = true;
|
|
9112
|
+
settle();
|
|
9113
|
+
close();
|
|
9114
|
+
}
|
|
9115
|
+
);
|
|
9116
|
+
unsubscribe = toCleanup(teardown);
|
|
9117
|
+
// Completed or errored during subscribe: release what it just returned.
|
|
9118
|
+
if (closed) {
|
|
9119
|
+
const c = unsubscribe;
|
|
9120
|
+
unsubscribe = null;
|
|
9121
|
+
try {
|
|
9122
|
+
c();
|
|
9123
|
+
} catch {}
|
|
9124
|
+
}
|
|
9125
|
+
// Idempotent: return(), supersede and disposal may all reach it.
|
|
9126
|
+
const finish = () => {
|
|
9127
|
+
close();
|
|
9128
|
+
has = false;
|
|
9129
|
+
if (waiting) {
|
|
9130
|
+
const w = waiting;
|
|
9131
|
+
waiting = null;
|
|
9132
|
+
w.resolve(DONE);
|
|
9133
|
+
}
|
|
9134
|
+
return DONE;
|
|
9135
|
+
};
|
|
9136
|
+
bindToOwner(finish);
|
|
9137
|
+
return {
|
|
9138
|
+
next() {
|
|
9139
|
+
// A buffered value is returned as a bare result, not a promise: the
|
|
9140
|
+
// iterator consumer lands it in the same pass, so a source that
|
|
9141
|
+
// emits during subscribe (BehaviorSubject-style) shows its value
|
|
9142
|
+
// with no loading frame. `for await` accepts either form.
|
|
9143
|
+
if (has) {
|
|
9144
|
+
has = false;
|
|
9145
|
+
return { value: latest, done: false };
|
|
9146
|
+
}
|
|
9147
|
+
if (failed) {
|
|
9148
|
+
failed = false;
|
|
9149
|
+
return Promise.reject(failure);
|
|
9150
|
+
}
|
|
9151
|
+
if (done) return Promise.resolve({ value: undefined, done: true });
|
|
9152
|
+
return new Promise((resolve, reject) => {
|
|
9153
|
+
waiting = { resolve, reject };
|
|
9154
|
+
});
|
|
9155
|
+
},
|
|
9156
|
+
return() {
|
|
9157
|
+
return Promise.resolve(finish());
|
|
9158
|
+
}
|
|
9159
|
+
};
|
|
9160
|
+
}
|
|
9161
|
+
};
|
|
9162
|
+
}
|
|
9163
|
+
|
|
8812
9164
|
// CARVE 4: `flatten` lived in boundaries.ts but is the general children
|
|
8813
9165
|
// resolver the renderers (`web`, `universal`, `solid`'s `children()`) walk
|
|
8814
9166
|
// through — not a boundary feature. Moved verbatim so the boundary carve
|
|
@@ -9310,7 +9662,7 @@ function createBoundary(type, fn, show, onFn) {
|
|
|
9310
9662
|
} catch (e) {
|
|
9311
9663
|
if (!(e instanceof NotReadyError)) {
|
|
9312
9664
|
if (!globalQueue.notify(getOwner(), STATUS_ERROR, STATUS_ERROR, e)) {
|
|
9313
|
-
|
|
9665
|
+
if (true) haltReactivityAt(e, getOwner());
|
|
9314
9666
|
throw e;
|
|
9315
9667
|
}
|
|
9316
9668
|
return;
|
|
@@ -9847,6 +10199,7 @@ export {
|
|
|
9847
10199
|
enableExternalSource,
|
|
9848
10200
|
flatten,
|
|
9849
10201
|
flush,
|
|
10202
|
+
from,
|
|
9850
10203
|
getContext,
|
|
9851
10204
|
getObserver,
|
|
9852
10205
|
getOwner,
|