@solidjs/signals 2.0.0-rc.2 → 2.0.0-rc.3
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 +120 -24
- package/dist/node.cjs +190 -99
- package/dist/prod/core/optimistic.js +37 -15
- package/dist/prod/core/scheduler.js +8 -8
- package/dist/prod/core/verdict.js +7 -0
- package/dist/prod/store/next/optimistic.js +3 -3
- package/dist/prod/store/next/projection.js +107 -45
- package/dist/types/core/invariants.d.ts +1 -1
- package/dist/types-cjs/core/invariants.d.cts +1 -1
- package/package.json +15 -15
- 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/dev.js
CHANGED
|
@@ -236,7 +236,7 @@ function captureStack() {
|
|
|
236
236
|
// remaining frames are the user code that performed the write.
|
|
237
237
|
return raw
|
|
238
238
|
.slice(1)
|
|
239
|
-
.filter(line => !/
|
|
239
|
+
.filter(line => !/(?:^|[/\\])(?:packages[/\\])?signals[/\\](src|dist)[/\\]/.test(line))
|
|
240
240
|
.slice(0, 3)
|
|
241
241
|
.map(line => line.trim());
|
|
242
242
|
}
|
|
@@ -4507,7 +4507,16 @@ function optimisticWrite(el, v) {
|
|
|
4507
4507
|
const currentValue = hasOverride ? unwrapOverride(el._x?._overrideValue) : el._value;
|
|
4508
4508
|
if (typeof v === "function") v = v(currentValue);
|
|
4509
4509
|
const valueChanged =
|
|
4510
|
-
!!(el._statusFlags & STATUS_UNINITIALIZED) ||
|
|
4510
|
+
!!(el._statusFlags & STATUS_UNINITIALIZED) ||
|
|
4511
|
+
// A dirty node's _value is stale (its queued recompute hasn't run — e.g.
|
|
4512
|
+
// a latest() shadow marked by the previous landing's companion snap), so
|
|
4513
|
+
// equality against it must not swallow the write. Without this, a sync
|
|
4514
|
+
// push returning the shadow to that stale value was dropped, the snap
|
|
4515
|
+
// recompute then committed the parent's old value, and the banner showed
|
|
4516
|
+
// the previous transition's target (#3041 follow-up).
|
|
4517
|
+
!!((el._flags ?? 0) & (REACTIVE_DIRTY | REACTIVE_CHECK)) ||
|
|
4518
|
+
!el._equals ||
|
|
4519
|
+
!el._equals(currentValue, v);
|
|
4511
4520
|
if (!valueChanged) {
|
|
4512
4521
|
// Same-value write with an active override still entangles the current
|
|
4513
4522
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -4663,18 +4672,33 @@ function laneReadsCommitted(el, owner, c) {
|
|
|
4663
4672
|
el._x?._overrideValue !== undefined ||
|
|
4664
4673
|
!!el._x?._optimisticLane ||
|
|
4665
4674
|
!!(owner._statusFlags & STATUS_PENDING)
|
|
4666
|
-
)
|
|
4675
|
+
) {
|
|
4676
|
+
// The committed view hides a staged in-flight value that will promote
|
|
4677
|
+
// silently (commitPendingNode never re-notifies). gatedRead records plain
|
|
4678
|
+
// signals for replay at commit; async memos are excluded from it by the
|
|
4679
|
+
// `_fn` check and reach here instead — a lane-assigned source whose async
|
|
4680
|
+
// already settled (laneAsyncSettled keeps _optimisticLane) served its
|
|
4681
|
+
// committed value to a reader that never re-ran after the landing, so a
|
|
4682
|
+
// pending-gated branch stayed one value behind permanently (#3041
|
|
4683
|
+
// follow-up). Record the reader under the same replay contract.
|
|
4684
|
+
if (el._pendingValue !== NOT_PENDING)
|
|
4685
|
+
(activeTransition ?? globalQueue._batch)._gatedSubs.add(c);
|
|
4667
4686
|
return true;
|
|
4687
|
+
}
|
|
4668
4688
|
if (owner === el && stale && c._x?._parentSource !== el) {
|
|
4669
|
-
// The committed view can hide a
|
|
4670
|
-
//
|
|
4671
|
-
//
|
|
4672
|
-
//
|
|
4673
|
-
//
|
|
4674
|
-
//
|
|
4675
|
-
//
|
|
4676
|
-
|
|
4677
|
-
|
|
4689
|
+
// The committed view can hide a staged write (a lane member — even just
|
|
4690
|
+
// an isPending companion flip — puts the reader "under a lane"). The
|
|
4691
|
+
// staged value commits with no re-delivery (commitPendingNode never
|
|
4692
|
+
// re-notifies), so record the reader for replay at commit — the same
|
|
4693
|
+
// contract gatedRead provides (#2963). gatedRead itself only covers
|
|
4694
|
+
// signal reads where the reading computed differs from the source; the
|
|
4695
|
+
// owner === el memo/self read lands here instead. With a transaction
|
|
4696
|
+
// active the staged value promotes silently at ITS landing, so record
|
|
4697
|
+
// into the transaction (#3041 follow-up: a pending-gated branch that
|
|
4698
|
+
// first read its async source during the landing flush stayed one value
|
|
4699
|
+
// behind permanently); with none, into the ambient batch.
|
|
4700
|
+
if (el._pendingValue !== NOT_PENDING)
|
|
4701
|
+
(activeTransition ?? globalQueue._batch)._gatedSubs.add(c);
|
|
4678
4702
|
return true;
|
|
4679
4703
|
}
|
|
4680
4704
|
return false;
|
|
@@ -5030,6 +5054,13 @@ function snapCompanionsToState(owner) {
|
|
|
5030
5054
|
}
|
|
5031
5055
|
function getLatestValueComputed(el) {
|
|
5032
5056
|
let lvc = el._x?._latestValueComputed;
|
|
5057
|
+
// A shadow disposed while unobserved (its gated reader unmounted at a
|
|
5058
|
+
// landing) is a corpse: sync writes into it equality-swallow against its
|
|
5059
|
+
// frozen _value, and a later read revives it via recompute — clearing
|
|
5060
|
+
// DISPOSED and re-deriving from the committed view, so the banner showed
|
|
5061
|
+
// the previous transition's target (#3041 follow-up). Treat it as absent;
|
|
5062
|
+
// recreation backfills from the in-flight write below.
|
|
5063
|
+
if (lvc && lvc._flags & REACTIVE_DISPOSED) lvc = undefined;
|
|
5033
5064
|
if (!lvc) {
|
|
5034
5065
|
const prevPending = latestReadActive;
|
|
5035
5066
|
setLatestReadActive(false);
|
|
@@ -8463,10 +8494,29 @@ function descend(pv, nv, keyFn, fam, proj = false) {
|
|
|
8463
8494
|
* primitives; the generic draft write-traps are reused from the legacy
|
|
8464
8495
|
* module unchanged.
|
|
8465
8496
|
*/
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8497
|
+
/**
|
|
8498
|
+
* Wrap a store proxy as a projection DRAFT: every operation carries the write
|
|
8499
|
+
* override (the derive is the author — its ops must not hit the §6c firewall
|
|
8500
|
+
* gate, even in a continuation after an `await`/`yield` where the sync write
|
|
8501
|
+
* scope has closed).
|
|
8502
|
+
*
|
|
8503
|
+
* FAKE TARGET, not the store proxy itself (#3060): after a proxy trap
|
|
8504
|
+
* returns, the engine runs spec invariant validation against the proxy's
|
|
8505
|
+
* TARGET — [[OwnPropertyKeys]] after ownKeys, [[GetOwnProperty]] after
|
|
8506
|
+
* set/getOwnPropertyDescriptor/defineProperty. With the store proxy as
|
|
8507
|
+
* target those checks re-enter the store's traps OUTSIDE the override
|
|
8508
|
+
* bracket (the trap's finally has already run), so `Object.keys(state)` in
|
|
8509
|
+
* a derive continuation fired the firewall gate and re-threw the
|
|
8510
|
+
* projection's own pending NotReadyError into the derive. A dummy of
|
|
8511
|
+
* matching kind (array/object, same trick as the store's own TargetShape)
|
|
8512
|
+
* keeps invariant validation away from the store entirely; the traps
|
|
8513
|
+
* forward to the closed-over inner proxy inside the bracket.
|
|
8514
|
+
*
|
|
8515
|
+
* Save/restore projectionWriteActive, never hard-reset: the draft can be
|
|
8516
|
+
* driven from inside an enclosing authoritative-write scope (next-store
|
|
8517
|
+
* optimistic derives), and a hard `false` would clobber it mid-derive.
|
|
8518
|
+
*/
|
|
8519
|
+
function wrapDraft(inner, isActive, onDraftWrite) {
|
|
8470
8520
|
const traps = {
|
|
8471
8521
|
get(_, prop) {
|
|
8472
8522
|
let value;
|
|
@@ -8474,13 +8524,15 @@ function createWriteTraps(isActive, onDraftWrite) {
|
|
|
8474
8524
|
setWriteOverride(true);
|
|
8475
8525
|
setProjectionWriteActive(true);
|
|
8476
8526
|
try {
|
|
8477
|
-
value =
|
|
8527
|
+
value = inner[prop];
|
|
8478
8528
|
} finally {
|
|
8479
8529
|
setWriteOverride(false);
|
|
8480
8530
|
setProjectionWriteActive(was);
|
|
8481
8531
|
}
|
|
8482
8532
|
if (prop === $TARGET) return value;
|
|
8483
|
-
return typeof value === "object" && value !== null
|
|
8533
|
+
return typeof value === "object" && value !== null
|
|
8534
|
+
? wrapDraft(value, isActive, onDraftWrite)
|
|
8535
|
+
: value;
|
|
8484
8536
|
},
|
|
8485
8537
|
has(_, prop) {
|
|
8486
8538
|
let value;
|
|
@@ -8488,7 +8540,7 @@ function createWriteTraps(isActive, onDraftWrite) {
|
|
|
8488
8540
|
setWriteOverride(true);
|
|
8489
8541
|
setProjectionWriteActive(true);
|
|
8490
8542
|
try {
|
|
8491
|
-
value = prop in
|
|
8543
|
+
value = prop in inner;
|
|
8492
8544
|
} finally {
|
|
8493
8545
|
setWriteOverride(false);
|
|
8494
8546
|
setProjectionWriteActive(was);
|
|
@@ -8501,7 +8553,7 @@ function createWriteTraps(isActive, onDraftWrite) {
|
|
|
8501
8553
|
setWriteOverride(true);
|
|
8502
8554
|
setProjectionWriteActive(true);
|
|
8503
8555
|
try {
|
|
8504
|
-
|
|
8556
|
+
inner[prop] = value;
|
|
8505
8557
|
onDraftWrite?.();
|
|
8506
8558
|
} finally {
|
|
8507
8559
|
setWriteOverride(false);
|
|
@@ -8515,7 +8567,49 @@ function createWriteTraps(isActive, onDraftWrite) {
|
|
|
8515
8567
|
setWriteOverride(true);
|
|
8516
8568
|
setProjectionWriteActive(true);
|
|
8517
8569
|
try {
|
|
8518
|
-
delete
|
|
8570
|
+
delete inner[prop];
|
|
8571
|
+
onDraftWrite?.();
|
|
8572
|
+
} finally {
|
|
8573
|
+
setWriteOverride(false);
|
|
8574
|
+
setProjectionWriteActive(was);
|
|
8575
|
+
}
|
|
8576
|
+
return true;
|
|
8577
|
+
},
|
|
8578
|
+
ownKeys() {
|
|
8579
|
+
const was = projectionWriteActive;
|
|
8580
|
+
setWriteOverride(true);
|
|
8581
|
+
setProjectionWriteActive(true);
|
|
8582
|
+
try {
|
|
8583
|
+
return Reflect.ownKeys(inner);
|
|
8584
|
+
} finally {
|
|
8585
|
+
setWriteOverride(false);
|
|
8586
|
+
setProjectionWriteActive(was);
|
|
8587
|
+
}
|
|
8588
|
+
},
|
|
8589
|
+
getOwnPropertyDescriptor(_, prop) {
|
|
8590
|
+
let d;
|
|
8591
|
+
const was = projectionWriteActive;
|
|
8592
|
+
setWriteOverride(true);
|
|
8593
|
+
setProjectionWriteActive(true);
|
|
8594
|
+
try {
|
|
8595
|
+
d = Reflect.getOwnPropertyDescriptor(inner, prop);
|
|
8596
|
+
} finally {
|
|
8597
|
+
setWriteOverride(false);
|
|
8598
|
+
setProjectionWriteActive(was);
|
|
8599
|
+
}
|
|
8600
|
+
// The dummy target doesn't hold the key, so a non-configurable report
|
|
8601
|
+
// would violate the proxy invariant. Store descriptors are already
|
|
8602
|
+
// normalized configurable; enforce it for raw leaves too.
|
|
8603
|
+
if (d) d.configurable = true;
|
|
8604
|
+
return d;
|
|
8605
|
+
},
|
|
8606
|
+
defineProperty(_, prop, desc) {
|
|
8607
|
+
if (isActive && !isActive()) return true;
|
|
8608
|
+
const was = projectionWriteActive;
|
|
8609
|
+
setWriteOverride(true);
|
|
8610
|
+
setProjectionWriteActive(true);
|
|
8611
|
+
try {
|
|
8612
|
+
Reflect.defineProperty(inner, prop, desc);
|
|
8519
8613
|
onDraftWrite?.();
|
|
8520
8614
|
} finally {
|
|
8521
8615
|
setWriteOverride(false);
|
|
@@ -8524,7 +8618,8 @@ function createWriteTraps(isActive, onDraftWrite) {
|
|
|
8524
8618
|
return true;
|
|
8525
8619
|
}
|
|
8526
8620
|
};
|
|
8527
|
-
|
|
8621
|
+
// Matching-kind dummy so Array.isArray(draft) answers like the store.
|
|
8622
|
+
return new Proxy(Array.isArray(inner) ? [] : {}, traps);
|
|
8528
8623
|
}
|
|
8529
8624
|
function createProjectionNextInternal(fn, seed, options) {
|
|
8530
8625
|
const fam = {
|
|
@@ -8578,9 +8673,10 @@ function runProjectionComputedNext(wrappedStore, fn, key, wrapCommit, onDraftWri
|
|
|
8578
8673
|
const shadow = owner._loading
|
|
8579
8674
|
? JSON.parse(JSON.stringify(wrappedStore[$TARGET][STORE_VALUE]))
|
|
8580
8675
|
: null;
|
|
8581
|
-
const draft =
|
|
8676
|
+
const draft = wrapDraft(
|
|
8582
8677
|
wrappedStore,
|
|
8583
|
-
|
|
8678
|
+
() => !settled || owner._x?._inFlight === result,
|
|
8679
|
+
onDraftWrite
|
|
8584
8680
|
);
|
|
8585
8681
|
storeSetterNext(
|
|
8586
8682
|
draft,
|