@solidjs/signals 2.0.0-beta.25 → 2.0.0-beta.27
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 +370 -73
- package/dist/node.cjs +1247 -946
- package/dist/prod/core/action.js +11 -6
- package/dist/prod/core/async.js +212 -108
- package/dist/prod/core/core.js +203 -189
- package/dist/prod/core/effect.js +28 -28
- package/dist/prod/core/external.js +3 -3
- package/dist/prod/core/graph.js +28 -28
- package/dist/prod/core/heap.js +30 -30
- package/dist/prod/core/lanes.js +15 -15
- package/dist/prod/core/optimistic.js +39 -39
- package/dist/prod/core/owner.js +44 -44
- package/dist/prod/core/scheduler.js +127 -106
- package/dist/prod/core/verdict.js +54 -54
- package/dist/prod/map.js +60 -60
- package/dist/prod/signals.js +1 -1
- package/dist/prod/store/optimistic.js +55 -36
- package/dist/prod/store/projection.js +38 -33
- package/dist/prod/store/reconcile.js +299 -243
- package/dist/prod/store/store.js +127 -50
- package/dist/types/core/async.d.ts +2 -0
- package/dist/types/core/scheduler.d.ts +1 -0
- package/dist/types/store/optimistic.d.ts +2 -2
- package/dist/types/store/projection.d.ts +7 -2
- package/dist/types/store/reconcile.d.ts +14 -0
- package/dist/types/store/store.d.ts +2 -2
- package/dist/types-cjs/core/async.d.cts +2 -0
- package/dist/types-cjs/core/scheduler.d.cts +1 -0
- package/dist/types-cjs/store/optimistic.d.cts +2 -2
- package/dist/types-cjs/store/projection.d.cts +7 -2
- package/dist/types-cjs/store/reconcile.d.cts +14 -0
- package/dist/types-cjs/store/store.d.cts +2 -2
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { STATUS_PENDING, CONFIG_AUTO_DISPOSE, NOT_PENDING } from "../core/constants.js";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { computed } from "../core/core.js";
|
|
4
4
|
|
|
5
5
|
import { GlobalQueue, schedule, currentTransition, insertSubs, setProjectionWriteActive, projectionWriteActive } from "../core/scheduler.js";
|
|
6
6
|
|
|
@@ -14,21 +14,40 @@ import { installOptimisticEngine } from "../core/optimistic.js";
|
|
|
14
14
|
|
|
15
15
|
import { runProjectionComputed } from "./projection.js";
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { $TARGET, STORE_FIREWALL, storeSetter, STORE_OPTIMISTIC_OVERRIDE, STORE_NODE, STORE_OPTIMISTIC_OWNERS, getOverlayLayer, STORE_VALUE, $DELETED, isWrappable, wrap, visibleNodeValue, $TRACK, notifySelf, STORE_WRAP, createStoreProxy, storeTraps, STORE_LOOKUP, STORE_SHALLOW, markRawIngest, STORE_OPTIMISTIC } from "./store.js";
|
|
18
18
|
|
|
19
|
-
function createOptimisticStore(e, t,
|
|
19
|
+
function createOptimisticStore(e, t, r) {
|
|
20
20
|
// Register clear function with scheduler; store nodes marked
|
|
21
21
|
// STORE_OPTIMISTIC take the engine's write path, so install it before any
|
|
22
22
|
// node can be created.
|
|
23
23
|
installOptimisticEngine();
|
|
24
|
-
GlobalQueue.Dt
|
|
25
|
-
|
|
24
|
+
if (!GlobalQueue.Dt) {
|
|
25
|
+
GlobalQueue.Dt = clearOptimisticStores;
|
|
26
|
+
// Store half of the engine's override blockage (#2951): signal-form
|
|
27
|
+
// createOptimistic carries the pending async and the override on ONE node,
|
|
28
|
+
// so transitionBlocked sees both; a derived optimistic STORE splits them —
|
|
29
|
+
// the layer sits on store targets while the in-flight truth lives on the
|
|
30
|
+
// firewall computed. Without this, the transition adopting a bare store
|
|
31
|
+
// write settled in the same flush that started the refetch and its settle
|
|
32
|
+
// consumed the layer mid-flight (follow-up writes then drafted from base,
|
|
33
|
+
// clobbering instead of composing). Optimistic state clears when truth
|
|
34
|
+
// lands or its transaction ends — never mid-refetch. Wrapped here (engine
|
|
35
|
+
// is already installed above) so store-free apps never carry the check.
|
|
36
|
+
const e = GlobalQueue.dn;
|
|
37
|
+
GlobalQueue.dn = t => {
|
|
38
|
+
for (const e of t.cn) {
|
|
39
|
+
if ((e[$TARGET]?.[STORE_FIREWALL]?.S ?? 0) & STATUS_PENDING) return true;
|
|
40
|
+
}
|
|
41
|
+
return e(t);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const i = typeof e === "function";
|
|
26
45
|
// Plain form: the second slot carries options.
|
|
27
|
-
if (!
|
|
28
|
-
const o =
|
|
29
|
-
const n =
|
|
46
|
+
if (!i && r === undefined) r = t;
|
|
47
|
+
const o = i ? t : e;
|
|
48
|
+
const n = i ? e : undefined;
|
|
30
49
|
// Create optimistic projection store
|
|
31
|
-
const {store: c} = createOptimisticProjectionInternal(n, o,
|
|
50
|
+
const {store: c} = createOptimisticProjectionInternal(n, o, r);
|
|
32
51
|
return [ c, e => storeSetter(c, e) ];
|
|
33
52
|
}
|
|
34
53
|
|
|
@@ -37,8 +56,8 @@ function createOptimisticStore(e, t, i) {
|
|
|
37
56
|
// scheduler's flush tail carries only a size-guarded hook call. The
|
|
38
57
|
// completing transition scopes each clear to its own layer keys (#2899).
|
|
39
58
|
function clearOptimisticStores(e, t) {
|
|
40
|
-
for (const
|
|
41
|
-
const e =
|
|
59
|
+
for (const r of e) {
|
|
60
|
+
const e = r[$TARGET];
|
|
42
61
|
if (e?.[STORE_OPTIMISTIC_OVERRIDE]) clearOptimisticOverride(e, t);
|
|
43
62
|
}
|
|
44
63
|
e.clear();
|
|
@@ -56,9 +75,9 @@ function clearOptimisticStores(e, t) {
|
|
|
56
75
|
* fresh authoritative data) consumes everything — the correction supersedes
|
|
57
76
|
* every tentative layer.
|
|
58
77
|
*/ function clearOptimisticOverride(e, t) {
|
|
59
|
-
const
|
|
60
|
-
if (!
|
|
61
|
-
const
|
|
78
|
+
const r = e[STORE_OPTIMISTIC_OVERRIDE];
|
|
79
|
+
if (!r) return;
|
|
80
|
+
const i = e[STORE_NODE];
|
|
62
81
|
const o = e[STORE_OPTIMISTIC_OWNERS];
|
|
63
82
|
const n = t !== undefined;
|
|
64
83
|
let c = false;
|
|
@@ -68,7 +87,7 @@ function clearOptimisticStores(e, t) {
|
|
|
68
87
|
const O = projectionWriteActive;
|
|
69
88
|
setProjectionWriteActive(true);
|
|
70
89
|
try {
|
|
71
|
-
for (const O of Reflect.ownKeys(
|
|
90
|
+
for (const O of Reflect.ownKeys(r)) {
|
|
72
91
|
if (n) {
|
|
73
92
|
let e = o?.[O] ?? null;
|
|
74
93
|
// Resolve merge chains (entangled actions settle as one); path-compress
|
|
@@ -85,25 +104,25 @@ function clearOptimisticStores(e, t) {
|
|
|
85
104
|
}
|
|
86
105
|
}
|
|
87
106
|
}
|
|
88
|
-
delete
|
|
107
|
+
delete r[O];
|
|
89
108
|
if (o) delete o[O];
|
|
90
109
|
c = true;
|
|
91
|
-
const T =
|
|
110
|
+
const T = i?.[O];
|
|
92
111
|
if (T) {
|
|
93
112
|
// Clear lane association so effects go to regular queue
|
|
94
|
-
T.
|
|
113
|
+
T.Me = undefined;
|
|
95
114
|
// Re-read from base — this key left the optimistic layer above, so the
|
|
96
115
|
// overlay resolves to STORE_OVERRIDE or STORE_VALUE.
|
|
97
116
|
const t = getOverlayLayer(e, O);
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
const o = isWrappable(
|
|
117
|
+
const r = t ? t[O] : e[STORE_VALUE][O];
|
|
118
|
+
const i = r === $DELETED ? undefined : r;
|
|
119
|
+
const o = isWrappable(i) ? wrap(i, e) : i;
|
|
101
120
|
const n = visibleNodeValue(T);
|
|
102
|
-
T.
|
|
121
|
+
T.Ae = NOT_PENDING;
|
|
103
122
|
T.sn = null;
|
|
104
|
-
T.
|
|
105
|
-
T.
|
|
106
|
-
if (!T.
|
|
123
|
+
T.De = NOT_PENDING;
|
|
124
|
+
T.Ue = o;
|
|
125
|
+
if (!T.be || !T.be(n, o)) {
|
|
107
126
|
insertSubs(T, true);
|
|
108
127
|
schedule();
|
|
109
128
|
}
|
|
@@ -116,8 +135,8 @@ function clearOptimisticStores(e, t) {
|
|
|
116
135
|
e[STORE_OPTIMISTIC_OWNERS] = undefined;
|
|
117
136
|
}
|
|
118
137
|
// Notify $TRACK
|
|
119
|
-
if (c &&
|
|
120
|
-
|
|
138
|
+
if (c && i?.[$TRACK]) {
|
|
139
|
+
i[$TRACK].Me = undefined;
|
|
121
140
|
notifySelf(e);
|
|
122
141
|
}
|
|
123
142
|
} finally {
|
|
@@ -125,10 +144,10 @@ function clearOptimisticStores(e, t) {
|
|
|
125
144
|
}
|
|
126
145
|
}
|
|
127
146
|
|
|
128
|
-
function createOptimisticProjectionInternal(e, t,
|
|
129
|
-
let
|
|
147
|
+
function createOptimisticProjectionInternal(e, t, r) {
|
|
148
|
+
let i;
|
|
130
149
|
const o = new WeakMap;
|
|
131
|
-
const n = !!
|
|
150
|
+
const n = !!r?.shallow;
|
|
132
151
|
const wrapper = e => {
|
|
133
152
|
e[STORE_WRAP] = wrapProjection;
|
|
134
153
|
e[STORE_LOOKUP] = o;
|
|
@@ -140,7 +159,7 @@ function createOptimisticProjectionInternal(e, t, i) {
|
|
|
140
159
|
// Mark as optimistic store
|
|
141
160
|
Object.defineProperty(e, STORE_FIREWALL, {
|
|
142
161
|
get() {
|
|
143
|
-
return
|
|
162
|
+
return i;
|
|
144
163
|
},
|
|
145
164
|
configurable: true
|
|
146
165
|
});
|
|
@@ -174,19 +193,19 @@ function createOptimisticProjectionInternal(e, t, i) {
|
|
|
174
193
|
setProjectionWriteActive(t);
|
|
175
194
|
}
|
|
176
195
|
};
|
|
177
|
-
|
|
196
|
+
i = computed(() => {
|
|
178
197
|
setProjectionWriteActive(true);
|
|
179
198
|
try {
|
|
180
|
-
runProjectionComputed(c, e,
|
|
199
|
+
runProjectionComputed(c, e, r?.key === undefined ? "id" : r.key, wrapCommit, clearProjectionOverride);
|
|
181
200
|
} finally {
|
|
182
201
|
setProjectionWriteActive(false);
|
|
183
202
|
}
|
|
184
203
|
}, undefined);
|
|
185
|
-
|
|
204
|
+
i.T &= ~CONFIG_AUTO_DISPOSE;
|
|
186
205
|
}
|
|
187
206
|
return {
|
|
188
207
|
store: c,
|
|
189
|
-
node:
|
|
208
|
+
node: i
|
|
190
209
|
};
|
|
191
210
|
}
|
|
192
211
|
|
|
@@ -12,16 +12,16 @@ import "../core/effect.js";
|
|
|
12
12
|
|
|
13
13
|
import { CONFIG_AUTO_DISPOSE } from "../core/constants.js";
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import { reconcileState } from "./reconcile.js";
|
|
16
16
|
|
|
17
17
|
import { storeSetter, $TARGET, STORE_WRAP, createStoreProxy, storeTraps, setWriteOverride, STORE_LOOKUP, STORE_SHALLOW, markRawIngest, STORE_VALUE, STORE_FIREWALL } from "./store.js";
|
|
18
18
|
|
|
19
|
-
function createProjectionInternal(e,
|
|
19
|
+
function createProjectionInternal(e, t, r) {
|
|
20
20
|
let o;
|
|
21
21
|
const n = new WeakMap;
|
|
22
22
|
// A shallow projection's children are raw and never wrapped, so the
|
|
23
23
|
// wrapper only ever runs for the root — flagging unconditionally is safe.
|
|
24
|
-
const i = !!
|
|
24
|
+
const i = !!r?.shallow;
|
|
25
25
|
const wrapper = e => {
|
|
26
26
|
e[STORE_WRAP] = wrapProjection;
|
|
27
27
|
e[STORE_LOOKUP] = n;
|
|
@@ -39,14 +39,14 @@ function createProjectionInternal(e, r, t) {
|
|
|
39
39
|
const wrapProjection = e => {
|
|
40
40
|
if (n.has(e)) return n.get(e);
|
|
41
41
|
if (e[$TARGET]?.[STORE_WRAP] === wrapProjection) return e;
|
|
42
|
-
const
|
|
43
|
-
n.set(e,
|
|
44
|
-
return
|
|
42
|
+
const t = createStoreProxy(e, storeTraps, wrapper);
|
|
43
|
+
n.set(e, t);
|
|
44
|
+
return t;
|
|
45
45
|
};
|
|
46
|
-
const c = wrapProjection(
|
|
46
|
+
const c = wrapProjection(t);
|
|
47
47
|
o = computed(() => {
|
|
48
48
|
if (!o) o = getOwner();
|
|
49
|
-
runProjectionComputed(c, e,
|
|
49
|
+
runProjectionComputed(c, e, r?.key === undefined ? "id" : r.key);
|
|
50
50
|
}, undefined);
|
|
51
51
|
o.T &= ~CONFIG_AUTO_DISPOSE;
|
|
52
52
|
return {
|
|
@@ -63,6 +63,10 @@ function createProjectionInternal(e, r, t) {
|
|
|
63
63
|
* items keep their proxy identity — only added/removed items are
|
|
64
64
|
* created/disposed.
|
|
65
65
|
*
|
|
66
|
+
* If the derive returns a different entity than the one currently held (the
|
|
67
|
+
* `/users/1` → `/users/2` shape), the store swaps to it rather than merging,
|
|
68
|
+
* and nothing below it is treated as surviving.
|
|
69
|
+
*
|
|
66
70
|
* Returns the projected store directly (no setter — reads only).
|
|
67
71
|
*
|
|
68
72
|
* Use this when you want the structural-sharing / per-property tracking
|
|
@@ -75,7 +79,8 @@ function createProjectionInternal(e, r, t) {
|
|
|
75
79
|
* @param seed the backing store value to wrap and reconcile into
|
|
76
80
|
* @param options `ProjectionOptions` — `name`, `key`. `key` defaults to
|
|
77
81
|
* `"id"`; specify it only when your data uses a different identity field
|
|
78
|
-
* (e.g. `{ key: "uuid" }` or `{ key: u => u.slug }`)
|
|
82
|
+
* (e.g. `{ key: "uuid" }` or `{ key: u => u.slug }`), or `null` to merge
|
|
83
|
+
* positionally with no keyed pass.
|
|
79
84
|
*
|
|
80
85
|
* @example
|
|
81
86
|
* ```ts
|
|
@@ -97,8 +102,8 @@ function createProjectionInternal(e, r, t) {
|
|
|
97
102
|
* ```
|
|
98
103
|
*
|
|
99
104
|
* @see {@link https://github.com/solidjs/x-reactivity#createprojection}
|
|
100
|
-
*/ function createProjection(e,
|
|
101
|
-
return createProjectionInternal(e,
|
|
105
|
+
*/ function createProjection(e, t, r) {
|
|
106
|
+
return createProjectionInternal(e, t, r).store;
|
|
102
107
|
}
|
|
103
108
|
|
|
104
109
|
/**
|
|
@@ -113,17 +118,17 @@ function createProjectionInternal(e, r, t) {
|
|
|
113
118
|
* re-enters `setProjectionWriteActive` so reconciles target `STORE_OVERRIDE`
|
|
114
119
|
* instead of `STORE_OPTIMISTIC_OVERRIDE` even when an async yield fires outside
|
|
115
120
|
* the outer `setProjectionWriteActive` scope.
|
|
116
|
-
*/ function runProjectionComputed(e,
|
|
121
|
+
*/ function runProjectionComputed(e, t, r, o, n) {
|
|
117
122
|
const i = getOwner();
|
|
118
123
|
let c = false;
|
|
119
124
|
let s;
|
|
120
125
|
const u = new Proxy(e, createWriteTraps(() => !c || i.Te === s, n));
|
|
121
126
|
storeSetter(u, n => {
|
|
122
|
-
s =
|
|
127
|
+
s = t(n);
|
|
123
128
|
c = true;
|
|
124
|
-
const commit =
|
|
125
|
-
if (
|
|
126
|
-
const write = () => storeSetter(e,
|
|
129
|
+
const commit = t => {
|
|
130
|
+
if (t === n || t === undefined) return;
|
|
131
|
+
const write = () => storeSetter(e, e => reconcileState(t, e, r, true));
|
|
127
132
|
o ? o(write) : write();
|
|
128
133
|
};
|
|
129
134
|
commit(handleAsync(i, s, commit));
|
|
@@ -131,53 +136,53 @@ function createProjectionInternal(e, r, t) {
|
|
|
131
136
|
return i;
|
|
132
137
|
}
|
|
133
138
|
|
|
134
|
-
function createWriteTraps(e,
|
|
135
|
-
const
|
|
136
|
-
get(e,
|
|
139
|
+
function createWriteTraps(e, t) {
|
|
140
|
+
const r = {
|
|
141
|
+
get(e, t) {
|
|
137
142
|
let o;
|
|
138
143
|
setWriteOverride(true);
|
|
139
144
|
setProjectionWriteActive(true);
|
|
140
145
|
try {
|
|
141
|
-
o = e[
|
|
146
|
+
o = e[t];
|
|
142
147
|
} finally {
|
|
143
148
|
setWriteOverride(false);
|
|
144
149
|
setProjectionWriteActive(false);
|
|
145
150
|
}
|
|
146
|
-
if (
|
|
147
|
-
return typeof o === "object" && o !== null ? new Proxy(o,
|
|
151
|
+
if (t === $TARGET) return o;
|
|
152
|
+
return typeof o === "object" && o !== null ? new Proxy(o, r) : o;
|
|
148
153
|
},
|
|
149
|
-
has(e,
|
|
150
|
-
let
|
|
154
|
+
has(e, t) {
|
|
155
|
+
let r;
|
|
151
156
|
setWriteOverride(true);
|
|
152
157
|
setProjectionWriteActive(true);
|
|
153
158
|
try {
|
|
154
|
-
|
|
159
|
+
r = t in e;
|
|
155
160
|
} finally {
|
|
156
161
|
setWriteOverride(false);
|
|
157
162
|
setProjectionWriteActive(false);
|
|
158
163
|
}
|
|
159
|
-
return
|
|
164
|
+
return r;
|
|
160
165
|
},
|
|
161
|
-
set(
|
|
166
|
+
set(r, o, n) {
|
|
162
167
|
if (e && !e()) return true;
|
|
163
168
|
setWriteOverride(true);
|
|
164
169
|
setProjectionWriteActive(true);
|
|
165
170
|
try {
|
|
166
|
-
|
|
167
|
-
|
|
171
|
+
r[o] = n;
|
|
172
|
+
t?.();
|
|
168
173
|
} finally {
|
|
169
174
|
setWriteOverride(false);
|
|
170
175
|
setProjectionWriteActive(false);
|
|
171
176
|
}
|
|
172
177
|
return true;
|
|
173
178
|
},
|
|
174
|
-
deleteProperty(
|
|
179
|
+
deleteProperty(r, o) {
|
|
175
180
|
if (e && !e()) return true;
|
|
176
181
|
setWriteOverride(true);
|
|
177
182
|
setProjectionWriteActive(true);
|
|
178
183
|
try {
|
|
179
|
-
delete
|
|
180
|
-
|
|
184
|
+
delete r[o];
|
|
185
|
+
t?.();
|
|
181
186
|
} finally {
|
|
182
187
|
setWriteOverride(false);
|
|
183
188
|
setProjectionWriteActive(false);
|
|
@@ -185,7 +190,7 @@ function createWriteTraps(e, r) {
|
|
|
185
190
|
return true;
|
|
186
191
|
}
|
|
187
192
|
};
|
|
188
|
-
return
|
|
193
|
+
return r;
|
|
189
194
|
}
|
|
190
195
|
|
|
191
196
|
export { createProjection, createProjectionInternal, createWriteTraps, runProjectionComputed };
|