@solidjs/signals 0.9.1 → 0.9.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 CHANGED
@@ -34,6 +34,7 @@ const EFFECT_USER = 2;
34
34
  const NOT_PENDING = {};
35
35
  const SUPPORTS_PROXY = typeof Proxy === "function";
36
36
  const defaultContext = {};
37
+ const $REFRESH = Symbol("refresh");
37
38
  function actualInsertIntoHeap(n, heap) {
38
39
  const parentHeight =
39
40
  (n._parent?._root ? n._parent._parentComputed?._height : n._parent?._height) ?? -1;
@@ -132,6 +133,7 @@ function adjustHeight(el, heap) {
132
133
  }
133
134
  }
134
135
  const transitions = new Set();
136
+ let optimisticRun = false;
135
137
  const dirtyQueue = { _heap: new Array(2e3).fill(undefined), _marked: false, _min: 0, _max: 0 };
136
138
  const zombieQueue = { _heap: new Array(2e3).fill(undefined), _marked: false, _min: 0, _max: 0 };
137
139
  let clock = 0;
@@ -140,7 +142,7 @@ let scheduled = false;
140
142
  function schedule() {
141
143
  if (scheduled) return;
142
144
  scheduled = true;
143
- if (!globalQueue._running) queueMicrotask(flush);
145
+ if (!globalQueue._running) Promise.resolve().then(() => queueMicrotask(flush));
144
146
  }
145
147
  class Queue {
146
148
  _parent = null;
@@ -203,6 +205,7 @@ class Queue {
203
205
  class GlobalQueue extends Queue {
204
206
  _running = false;
205
207
  _pendingNodes = [];
208
+ _optimisticNodes = [];
206
209
  static _update;
207
210
  static _dispose;
208
211
  flush() {
@@ -212,6 +215,7 @@ class GlobalQueue extends Queue {
212
215
  runHeap(dirtyQueue, GlobalQueue._update);
213
216
  if (activeTransition) {
214
217
  if (!transitionComplete(activeTransition)) {
218
+ let t = activeTransition;
215
219
  runHeap(zombieQueue, GlobalQueue._update);
216
220
  this._pendingNodes = [];
217
221
  this.stashQueues(activeTransition.queueStash);
@@ -219,20 +223,18 @@ class GlobalQueue extends Queue {
219
223
  scheduled = false;
220
224
  runTransitionPending(activeTransition.pendingNodes, true);
221
225
  activeTransition = null;
226
+ runOptimistic(t);
222
227
  return;
223
228
  }
224
229
  this._pendingNodes.push(...activeTransition.pendingNodes);
230
+ this._optimisticNodes !== activeTransition.optimisticNodes &&
231
+ this._optimisticNodes.push(...activeTransition.optimisticNodes);
225
232
  this.restoreQueues(activeTransition.queueStash);
226
233
  transitions.delete(activeTransition);
227
234
  activeTransition = null;
228
235
  runTransitionPending(this._pendingNodes, false);
229
- dirtyQueue._max >= dirtyQueue._min && runHeap(dirtyQueue, GlobalQueue._update);
230
236
  } else if (transitions.size) runHeap(zombieQueue, GlobalQueue._update);
231
- runPending(this._pendingNodes);
232
- while (dirtyQueue._max >= dirtyQueue._min) {
233
- runHeap(dirtyQueue, GlobalQueue._update);
234
- runPending(this._pendingNodes);
235
- }
237
+ runOptimistic();
236
238
  clock++;
237
239
  scheduled = false;
238
240
  this.run(EFFECT_RENDER);
@@ -256,11 +258,14 @@ class GlobalQueue extends Queue {
256
258
  initTransition(node) {
257
259
  if (activeTransition && activeTransition.time === clock) return;
258
260
  if (!activeTransition) {
259
- activeTransition = node._transition ?? {
261
+ activeTransition = node?._transition ?? {
260
262
  time: clock,
261
263
  pendingNodes: [],
262
264
  asyncNodes: [],
263
- queueStash: { _queues: [[], []], _children: [] }
265
+ optimisticNodes: [],
266
+ actions: [],
267
+ queueStash: { _queues: [[], []], _children: [] },
268
+ done: false
264
269
  };
265
270
  }
266
271
  transitions.add(activeTransition);
@@ -270,9 +275,47 @@ class GlobalQueue extends Queue {
270
275
  n._transition = activeTransition;
271
276
  activeTransition.pendingNodes.push(n);
272
277
  }
278
+ for (let i = 0; i < this._optimisticNodes.length; i++) {
279
+ const n = this._optimisticNodes[i];
280
+ n._transition = activeTransition;
281
+ activeTransition.optimisticNodes.push(n);
282
+ }
273
283
  this._pendingNodes = activeTransition.pendingNodes;
284
+ this._optimisticNodes = activeTransition.optimisticNodes;
285
+ }
286
+ }
287
+ function notifySubs(node) {
288
+ for (let s = node._subs; s !== null; s = s._nextSub) {
289
+ const queue = s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
290
+ if (queue._min > s._sub._height) queue._min = s._sub._height;
291
+ insertIntoHeap(s._sub, queue);
274
292
  }
275
293
  }
294
+ function runOptimistic(activeTransition = null) {
295
+ let resolvePending = !activeTransition;
296
+ const optimisticNodes = globalQueue._optimisticNodes;
297
+ optimisticRun = true;
298
+ for (let i = 0; i < optimisticNodes.length; i++) {
299
+ const n = optimisticNodes[i];
300
+ if (
301
+ !activeTransition &&
302
+ (!n._transition || n._transition.done) &&
303
+ n._pendingValue !== NOT_PENDING
304
+ ) {
305
+ n._value = n._pendingValue;
306
+ n._pendingValue = NOT_PENDING;
307
+ }
308
+ n._transition = activeTransition;
309
+ notifySubs(n);
310
+ }
311
+ globalQueue._optimisticNodes = [];
312
+ if (dirtyQueue._max >= dirtyQueue._min) {
313
+ resolvePending = true;
314
+ runHeap(dirtyQueue, GlobalQueue._update);
315
+ }
316
+ optimisticRun = false;
317
+ resolvePending && runPending(globalQueue._pendingNodes);
318
+ }
276
319
  function runPending(pendingNodes) {
277
320
  for (let i = 0; i < pendingNodes.length; i++) {
278
321
  const n = pendingNodes[i];
@@ -281,8 +324,6 @@ function runPending(pendingNodes) {
281
324
  n._pendingValue = NOT_PENDING;
282
325
  if (n._type) n._modified = true;
283
326
  }
284
- if (n._pendingSignal && n._pendingSignal._pendingValue !== NOT_PENDING)
285
- n._pendingSignal._set(n._pendingSignal._pendingValue);
286
327
  if (n._fn) GlobalQueue._dispose(n, false, true);
287
328
  }
288
329
  pendingNodes.length = 0;
@@ -293,10 +334,6 @@ function runTransitionPending(pendingNodes, value) {
293
334
  const n = p[i];
294
335
  n._transition = activeTransition;
295
336
  if (n._pendingCheck) n._pendingCheck._set(value);
296
- if (n._pendingSignal && n._pendingSignal._pendingValue !== NOT_PENDING) {
297
- n._pendingSignal._set(n._pendingSignal._pendingValue);
298
- n._pendingSignal._pendingValue = NOT_PENDING;
299
- }
300
337
  }
301
338
  }
302
339
  const globalQueue = new GlobalQueue();
@@ -311,6 +348,8 @@ function runQueue(queue, type) {
311
348
  for (let i = 0; i < queue.length; i++) queue[i](type);
312
349
  }
313
350
  function transitionComplete(transition) {
351
+ if (transition.done) return true;
352
+ if (transition.actions.length) return false;
314
353
  let done = true;
315
354
  for (let i = 0; i < transition.asyncNodes.length; i++) {
316
355
  if (transition.asyncNodes[i]._statusFlags & STATUS_PENDING) {
@@ -318,13 +357,43 @@ function transitionComplete(transition) {
318
357
  break;
319
358
  }
320
359
  }
360
+ done && (transition.done = true);
321
361
  return done;
322
362
  }
323
- function runInTransition(el, recompute) {
363
+ function runInTransition(transition, fn) {
324
364
  const prevTransition = activeTransition;
325
- activeTransition = el._transition;
326
- recompute(el);
327
- activeTransition = prevTransition;
365
+ try {
366
+ activeTransition = transition;
367
+ return fn();
368
+ } finally {
369
+ activeTransition = prevTransition;
370
+ }
371
+ }
372
+ function action(genFn) {
373
+ return (...args) => {
374
+ const iterator = genFn(...args);
375
+ globalQueue.initTransition();
376
+ let ctx = activeTransition;
377
+ ctx.actions.push(iterator);
378
+ const step = input => {
379
+ let nextValue = iterator.next(input);
380
+ if (nextValue instanceof Promise) return nextValue.then(process);
381
+ process(nextValue);
382
+ };
383
+ const process = result => {
384
+ if (result.done) {
385
+ ctx.actions.splice(ctx.actions.indexOf(iterator), 1);
386
+ activeTransition = ctx;
387
+ schedule();
388
+ flush();
389
+ return;
390
+ }
391
+ const yielded = result.value;
392
+ if (yielded instanceof Promise) return yielded.then(step);
393
+ runInTransition(ctx, () => step(yielded));
394
+ };
395
+ runInTransition(ctx, () => step());
396
+ };
328
397
  }
329
398
  GlobalQueue._update = recompute;
330
399
  GlobalQueue._dispose = disposeChildren;
@@ -334,13 +403,6 @@ let pendingValueCheck = false;
334
403
  let pendingCheck = null;
335
404
  let refreshing = false;
336
405
  let context = null;
337
- function notifySubs(node) {
338
- for (let s = node._subs; s !== null; s = s._nextSub) {
339
- const queue = s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
340
- if (queue._min > s._sub._height) queue._min = s._sub._height;
341
- insertIntoHeap(s._sub, queue);
342
- }
343
- }
344
406
  function recompute(el, create = false) {
345
407
  const honoraryOptimistic = el._type && el._transition != activeTransition;
346
408
  if (!create) {
@@ -361,7 +423,10 @@ function recompute(el, create = false) {
361
423
  el._depsTail = null;
362
424
  el._flags = REACTIVE_RECOMPUTING_DEPS;
363
425
  el._time = clock;
364
- let value = el._pendingValue === NOT_PENDING ? el._value : el._pendingValue;
426
+ let value =
427
+ el._pendingValue === NOT_PENDING || (el._optimistic && el._transition)
428
+ ? el._value
429
+ : el._pendingValue;
365
430
  let oldHeight = el._height;
366
431
  let prevStatusFlags = el._statusFlags;
367
432
  let prevError = el._error;
@@ -395,7 +460,7 @@ function recompute(el, create = false) {
395
460
  const valueChanged =
396
461
  !el._equals ||
397
462
  !el._equals(
398
- el._pendingValue === NOT_PENDING || el._optimistic || honoraryOptimistic
463
+ el._pendingValue === NOT_PENDING || (el._optimistic && el._transition) || honoraryOptimistic
399
464
  ? el._value
400
465
  : el._pendingValue,
401
466
  value
@@ -406,21 +471,19 @@ function recompute(el, create = false) {
406
471
  if (valueChanged) {
407
472
  if (create || el._optimistic || honoraryOptimistic) el._value = value;
408
473
  else el._pendingValue = value;
409
- if (el._pendingSignal) el._pendingSignal._pendingValue = value;
410
- }
411
- for (let s = el._subs; s !== null; s = s._nextSub) {
412
- const queue = s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue;
413
- if (s._sub._height < el._height && queue._min > s._sub._height) queue._min = s._sub._height;
414
- insertIntoHeap(s._sub, queue);
474
+ if (el._pendingSignal) setSignal(el._pendingSignal, value);
415
475
  }
476
+ (!el._optimistic || optimisticRun) && notifySubs(el);
416
477
  } else if (el._height != oldHeight) {
417
478
  for (let s = el._subs; s !== null; s = s._nextSub) {
418
479
  insertIntoHeapHeight(s._sub, s._sub._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
419
480
  }
420
481
  }
421
- if ((!create || el._statusFlags & STATUS_PENDING) && !el._optimistic && !el._transition)
482
+ el._optimistic && !optimisticRun && globalQueue._optimisticNodes.push(el);
483
+ (!create || el._statusFlags & STATUS_PENDING) &&
484
+ !el._transition &&
422
485
  globalQueue._pendingNodes.push(el);
423
- if (el._transition && honoraryOptimistic) runInTransition(el, recompute);
486
+ el._transition && honoraryOptimistic && runInTransition(el._transition, () => recompute(el));
424
487
  }
425
488
  function handleAsync(el, result, setter) {
426
489
  const isObject = typeof result === "object" && result !== null;
@@ -671,7 +734,7 @@ function computed(fn, initialValue, options) {
671
734
  }
672
735
  }
673
736
  if (parent) self._height = parent._height + 1;
674
- recompute(self, true);
737
+ !options?.lazy && recompute(self, true);
675
738
  return self;
676
739
  }
677
740
  function signal(v, options, firewall = null) {
@@ -726,22 +789,10 @@ function read(el) {
726
789
  }
727
790
  }
728
791
  }
729
- if (pendingCheck) {
730
- if (!el._pendingCheck) {
731
- el._pendingCheck = signal(false);
732
- el._pendingCheck._optimistic = true;
733
- el._pendingCheck._set = v => setSignal(el._pendingCheck, v);
734
- }
735
- const prev = pendingCheck;
736
- pendingCheck = null;
737
- prev._value = read(el._pendingCheck) || prev._value;
738
- pendingCheck = prev;
739
- }
740
792
  if (pendingValueCheck) {
741
793
  if (!el._pendingSignal) {
742
794
  el._pendingSignal = signal(el._value);
743
795
  el._pendingSignal._optimistic = true;
744
- el._pendingSignal._set = v => setSignal(el._pendingSignal, v);
745
796
  }
746
797
  pendingValueCheck = false;
747
798
  try {
@@ -750,10 +801,23 @@ function read(el) {
750
801
  pendingValueCheck = true;
751
802
  }
752
803
  }
753
- if (el._statusFlags & STATUS_PENDING && !pendingCheck) {
754
- if ((c && !stale) || el._statusFlags & STATUS_UNINITIALIZED) throw el._error;
804
+ const asyncCompute = el._firewall || el;
805
+ if (pendingCheck) {
806
+ if (!asyncCompute._pendingCheck) {
807
+ asyncCompute._pendingCheck = signal(false);
808
+ asyncCompute._pendingCheck._optimistic = true;
809
+ asyncCompute._pendingCheck._set = v => setSignal(asyncCompute._pendingCheck, v);
810
+ }
811
+ const prev = pendingCheck;
812
+ pendingCheck = null;
813
+ prev._value = read(asyncCompute._pendingCheck) || prev._value;
814
+ pendingCheck = prev;
815
+ }
816
+ if (!pendingCheck && asyncCompute._statusFlags & STATUS_PENDING) {
817
+ if ((c && !stale) || asyncCompute._statusFlags & STATUS_UNINITIALIZED || el._firewall)
818
+ throw asyncCompute._error;
755
819
  else if (c && stale) {
756
- setStatusFlags(c, c._statusFlags | 1, el._error);
820
+ setStatusFlags(c, c._statusFlags | STATUS_PENDING, asyncCompute._error);
757
821
  }
758
822
  }
759
823
  if (el._statusFlags & STATUS_ERROR) {
@@ -767,7 +831,9 @@ function read(el) {
767
831
  return !c ||
768
832
  el._optimistic ||
769
833
  el._pendingValue === NOT_PENDING ||
770
- (stale && !pendingCheck && el._transition && activeTransition !== el._transition)
834
+ (stale &&
835
+ !pendingCheck &&
836
+ (c._optimistic || (el._transition && activeTransition !== el._transition)))
771
837
  ? el._value
772
838
  : el._pendingValue;
773
839
  }
@@ -775,12 +841,18 @@ function setSignal(el, v) {
775
841
  if (!el._pureWrite && context && el._firewall !== context)
776
842
  console.warn("A Signal was written to in an owned scope.");
777
843
  if (typeof v === "function") {
778
- v = v(el._pendingValue === NOT_PENDING ? el._value : el._pendingValue);
844
+ v = v(
845
+ el._pendingValue === NOT_PENDING || (el._optimistic && el._transition)
846
+ ? el._value
847
+ : el._pendingValue
848
+ );
779
849
  }
780
850
  const valueChanged =
781
851
  !el._equals ||
782
852
  !el._equals(
783
- el._pendingValue === NOT_PENDING || el._optimistic ? el._value : el._pendingValue,
853
+ el._pendingValue === NOT_PENDING || (el._optimistic && el._transition)
854
+ ? el._value
855
+ : el._pendingValue,
784
856
  v
785
857
  );
786
858
  if (!valueChanged && !el._statusFlags) return v;
@@ -790,11 +862,11 @@ function setSignal(el, v) {
790
862
  if (el._pendingValue === NOT_PENDING) globalQueue._pendingNodes.push(el);
791
863
  el._pendingValue = v;
792
864
  }
793
- if (el._pendingSignal) el._pendingSignal._pendingValue = v;
865
+ if (el._pendingSignal) setSignal(el._pendingSignal, v);
794
866
  }
795
867
  setStatusFlags(el, STATUS_NONE);
796
868
  el._time = clock;
797
- notifySubs(el);
869
+ el._optimistic && !optimisticRun ? globalQueue._optimisticNodes.push(el) : notifySubs(el);
798
870
  schedule();
799
871
  return v;
800
872
  }
@@ -894,6 +966,10 @@ function refresh(fn) {
894
966
  let prevRefreshing = refreshing;
895
967
  refreshing = true;
896
968
  try {
969
+ if (typeof fn !== "function") {
970
+ recompute(fn[$REFRESH]);
971
+ return fn;
972
+ }
897
973
  return untrack(fn);
898
974
  } finally {
899
975
  refreshing = prevRefreshing;
@@ -1064,7 +1140,30 @@ function resolve(fn) {
1064
1140
  });
1065
1141
  }
1066
1142
  function createOptimistic(first, second, third) {
1067
- return {};
1143
+ if (typeof first === "function") {
1144
+ const node = computed(
1145
+ prev => {
1146
+ let n = node || getOwner();
1147
+ n._pendingValue = first(prev);
1148
+ return prev;
1149
+ },
1150
+ second,
1151
+ third
1152
+ );
1153
+ node._optimistic = true;
1154
+ return [read.bind(null, node), setSignal.bind(null, node)];
1155
+ }
1156
+ const o = getOwner();
1157
+ const needsId = o?.id != null;
1158
+ const node = signal(first, needsId ? { id: getNextChildId(o), ...second } : second);
1159
+ node._optimistic = true;
1160
+ return [
1161
+ read.bind(null, node),
1162
+ v => {
1163
+ node._pendingValue = first;
1164
+ return setSignal(node, v);
1165
+ }
1166
+ ];
1068
1167
  }
1069
1168
  function onSettled(callback) {
1070
1169
  let cleanup;
@@ -1079,11 +1178,7 @@ function unwrap(value) {
1079
1178
  return value?.[$TARGET]?.[STORE_NODE] ?? value;
1080
1179
  }
1081
1180
  function getOverrideValue(value, override, nodes, key) {
1082
- return nodes && key in nodes
1083
- ? read(nodes[key])
1084
- : override && key in override
1085
- ? override[key]
1086
- : value[key];
1181
+ return override && key in override ? override[key] : value[key];
1087
1182
  }
1088
1183
  function getAllKeys(value, override, next) {
1089
1184
  const keys = getKeys(value, override);
@@ -1169,10 +1264,12 @@ function applyState(next, state, keyFn, all) {
1169
1264
  } else target[STORE_NODE][j] && setSignal(target[STORE_NODE][j], wrap(next[j], target));
1170
1265
  }
1171
1266
  if (start < next.length) changed = true;
1172
- } else if (prevLength && next.length) {
1267
+ } else if (next.length) {
1173
1268
  for (let i = 0, len = next.length; i < len; i++) {
1174
1269
  const item = getOverrideValue(previous, override, nodes, i);
1175
- isWrappable(item) && applyState(next[i], wrap(item, target), keyFn, all);
1270
+ isWrappable(item)
1271
+ ? applyState(next[i], wrap(item, target), keyFn, all)
1272
+ : target[STORE_NODE][i] && setSignal(target[STORE_NODE][i], next[i]);
1176
1273
  }
1177
1274
  }
1178
1275
  if (prevLength !== next.length) {
@@ -1222,36 +1319,74 @@ function reconcile(value, key, all = false) {
1222
1319
  function createProjectionInternal(fn, initialValue = {}, options) {
1223
1320
  let node;
1224
1321
  const wrappedMap = new WeakMap();
1322
+ const wrapper = s => {
1323
+ s[STORE_WRAP] = wrapProjection;
1324
+ s[STORE_LOOKUP] = wrappedMap;
1325
+ Object.defineProperty(s, STORE_FIREWALL, {
1326
+ get() {
1327
+ return node;
1328
+ },
1329
+ configurable: true
1330
+ });
1331
+ };
1225
1332
  const wrapProjection = source => {
1226
1333
  if (wrappedMap.has(source)) return wrappedMap.get(source);
1227
1334
  if (source[$TARGET]?.[STORE_WRAP] === wrapProjection) return source;
1228
- const wrapped = createStoreProxy(source, storeTraps, {
1229
- [STORE_WRAP]: wrapProjection,
1230
- [STORE_LOOKUP]: wrappedMap,
1231
- [STORE_FIREWALL]() {
1232
- return node;
1233
- }
1234
- });
1335
+ const wrapped = createStoreProxy(source, storeTraps, wrapper);
1235
1336
  wrappedMap.set(source, wrapped);
1236
1337
  return wrapped;
1237
1338
  };
1238
1339
  const wrappedStore = wrapProjection(initialValue);
1239
1340
  node = computed(() => {
1240
1341
  const owner = node || getOwner();
1241
- storeSetter(wrappedStore, s => {
1342
+ storeSetter(new Proxy(wrappedStore, writeTraps), s => {
1242
1343
  const value = handleAsync(owner, fn(s), value => {
1243
- value !== s &&
1344
+ value !== wrappedStore &&
1244
1345
  value !== undefined &&
1245
1346
  storeSetter(wrappedStore, reconcile(value, options?.key || "id", options?.all));
1347
+ setSignal(node, undefined);
1246
1348
  });
1247
- value !== s && value !== undefined && reconcile(value, options?.key || "id", options?.all)(s);
1349
+ value !== wrappedStore &&
1350
+ value !== undefined &&
1351
+ reconcile(value, options?.key || "id", options?.all)(wrappedStore);
1248
1352
  });
1249
1353
  });
1354
+ node._preventAutoDisposal = true;
1250
1355
  return { store: wrappedStore, node: node };
1251
1356
  }
1252
1357
  function createProjection(fn, initialValue = {}, options) {
1253
1358
  return createProjectionInternal(fn, initialValue, options).store;
1254
1359
  }
1360
+ const writeTraps = {
1361
+ get(_, prop) {
1362
+ let value;
1363
+ setWriteOverride(true);
1364
+ try {
1365
+ value = _[prop];
1366
+ } finally {
1367
+ setWriteOverride(false);
1368
+ }
1369
+ return typeof value === "object" && value !== null ? new Proxy(value, writeTraps) : value;
1370
+ },
1371
+ set(_, prop, value) {
1372
+ setWriteOverride(true);
1373
+ try {
1374
+ _[prop] = value;
1375
+ } finally {
1376
+ setWriteOverride(false);
1377
+ }
1378
+ return true;
1379
+ },
1380
+ deleteProperty(_, prop) {
1381
+ setWriteOverride(true);
1382
+ try {
1383
+ delete _[prop];
1384
+ } finally {
1385
+ setWriteOverride(false);
1386
+ }
1387
+ return true;
1388
+ }
1389
+ };
1255
1390
  const $TRACK = Symbol("STORE_TRACK"),
1256
1391
  $DEEP = Symbol("STORE_DEEP"),
1257
1392
  $TARGET = Symbol("STORE_TARGET"),
@@ -1271,7 +1406,7 @@ function createStoreProxy(value, traps = storeTraps, extend) {
1271
1406
  newTarget = [];
1272
1407
  newTarget.v = value;
1273
1408
  } else newTarget = { v: value };
1274
- extend && Object.assign(newTarget, extend);
1409
+ extend && extend(newTarget);
1275
1410
  return (newTarget[$PROXY] = new Proxy(newTarget, traps));
1276
1411
  }
1277
1412
  const storeLookup = new WeakMap();
@@ -1284,6 +1419,13 @@ function wrap(value, target) {
1284
1419
  function isWrappable(obj) {
1285
1420
  return obj != null && typeof obj === "object" && !Object.isFrozen(obj);
1286
1421
  }
1422
+ let writeOverride = false;
1423
+ function setWriteOverride(value) {
1424
+ writeOverride = value;
1425
+ }
1426
+ function writeOnly(proxy) {
1427
+ return writeOverride || !!Writing?.has(proxy);
1428
+ }
1287
1429
  function getNodes(target, type) {
1288
1430
  let nodes = target[type];
1289
1431
  if (!nodes) target[type] = nodes = Object.create(null);
@@ -1304,9 +1446,7 @@ function getNode(nodes, property, value, firewall, equals = isEqual) {
1304
1446
  }
1305
1447
  function trackSelf(target, symbol = $TRACK) {
1306
1448
  getObserver() &&
1307
- read(
1308
- getNode(getNodes(target, STORE_NODE), symbol, undefined, target[STORE_FIREWALL]?.(), false)
1309
- );
1449
+ read(getNode(getNodes(target, STORE_NODE), symbol, undefined, target[STORE_FIREWALL], false));
1310
1450
  }
1311
1451
  function getKeys(source, override, enumerable = true) {
1312
1452
  const baseKeys = untrack(() => (enumerable ? Object.keys(source) : Reflect.ownKeys(source)));
@@ -1332,6 +1472,7 @@ const storeTraps = {
1332
1472
  get(target, property, receiver) {
1333
1473
  if (property === $TARGET) return target;
1334
1474
  if (property === $PROXY) return receiver;
1475
+ if (property === $REFRESH) return target[STORE_FIREWALL];
1335
1476
  if (property === $TRACK || property === $DEEP) {
1336
1477
  trackSelf(target, property);
1337
1478
  return receiver;
@@ -1345,7 +1486,7 @@ const storeTraps = {
1345
1486
  const desc = Object.getOwnPropertyDescriptor(storeValue, property);
1346
1487
  if (desc && desc.get) return desc.get.call(receiver);
1347
1488
  }
1348
- if (Writing?.has(receiver)) {
1489
+ if (writeOnly(receiver)) {
1349
1490
  let value =
1350
1491
  tracked && (overridden || !proxySource)
1351
1492
  ? tracked._pendingValue !== NOT_PENDING
@@ -1355,7 +1496,7 @@ const storeTraps = {
1355
1496
  value === $DELETED && (value = undefined);
1356
1497
  if (!isWrappable(value)) return value;
1357
1498
  const wrapped = wrap(value, target);
1358
- Writing.add(wrapped);
1499
+ Writing?.add(wrapped);
1359
1500
  return wrapped;
1360
1501
  }
1361
1502
  let value = tracked
@@ -1378,7 +1519,7 @@ const storeTraps = {
1378
1519
  nodes,
1379
1520
  property,
1380
1521
  isWrappable(value) ? wrap(value, target) : value,
1381
- target[STORE_FIREWALL]?.()
1522
+ target[STORE_FIREWALL]
1382
1523
  )
1383
1524
  );
1384
1525
  }
@@ -1392,12 +1533,12 @@ const storeTraps = {
1392
1533
  ? target[STORE_OVERRIDE][property] !== $DELETED
1393
1534
  : property in target[STORE_VALUE];
1394
1535
  getObserver() &&
1395
- read(getNode(getNodes(target, STORE_HAS), property, has, target[STORE_FIREWALL]?.()));
1536
+ read(getNode(getNodes(target, STORE_HAS), property, has, target[STORE_FIREWALL]));
1396
1537
  return has;
1397
1538
  },
1398
1539
  set(target, property, rawValue) {
1399
1540
  const store = target[$PROXY];
1400
- if (Writing?.has(target[$PROXY])) {
1541
+ if (writeOnly(store)) {
1401
1542
  untrack(() => {
1402
1543
  const state = target[STORE_VALUE];
1403
1544
  const base = state[property];
@@ -1432,7 +1573,7 @@ const storeTraps = {
1432
1573
  return true;
1433
1574
  },
1434
1575
  deleteProperty(target, property) {
1435
- if (Writing?.has(target[$PROXY]) && target[STORE_OVERRIDE]?.[property] !== $DELETED) {
1576
+ if (writeOnly(target[$PROXY]) && target[STORE_OVERRIDE]?.[property] !== $DELETED) {
1436
1577
  untrack(() => {
1437
1578
  const prev =
1438
1579
  target[STORE_OVERRIDE] && property in target[STORE_OVERRIDE]
@@ -2157,6 +2298,7 @@ export {
2157
2298
  NoOwnerError,
2158
2299
  NotReadyError,
2159
2300
  SUPPORTS_PROXY,
2301
+ action,
2160
2302
  createBoundary,
2161
2303
  createContext,
2162
2304
  createEffect,