@solidjs/signals 2.0.0-beta.12 → 2.0.0-beta.14

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/README.md CHANGED
@@ -107,8 +107,8 @@ const data = createMemo(async () => {
107
107
  return response.json();
108
108
  });
109
109
 
110
- // Check async state
111
- isPending(data); // true while loading
110
+ // Check async state for this read
111
+ isPending(data); // true while this read touches pending async work
112
112
  latest(data); // last resolved value
113
113
  ```
114
114
 
@@ -183,7 +183,7 @@ import { createErrorBoundary, createLoadingBoundary } from "@solidjs/signals";
183
183
 
184
184
  createErrorBoundary(
185
185
  () => riskyComputation(),
186
- (error, reset) => handleError(error)
186
+ (error, reset) => handleError(error())
187
187
  );
188
188
 
189
189
  createLoadingBoundary(
@@ -223,7 +223,7 @@ createRoot(dispose => {
223
223
  | ------------------------ | ------------------------------------------------------------------ |
224
224
  | `flush()` | Process all pending updates |
225
225
  | `untrack(fn)` | Run `fn` without tracking dependencies |
226
- | `isPending(accessor)` | Check if an async accessor is loading |
226
+ | `isPending(accessor)` | Check if an async accessor is revalidating stale data |
227
227
  | `latest(accessor)` | Get the last resolved value of an async accessor |
228
228
  | `refresh(accessor)` | Re-trigger an async computation |
229
229
  | `isRefreshing(accessor)` | Check if an async accessor is refreshing |
package/dist/dev.js CHANGED
@@ -1469,6 +1469,7 @@ let foundPending = false;
1469
1469
  let latestReadActive = false;
1470
1470
  let context = null;
1471
1471
  let currentOptimisticLane = null;
1472
+ let pendingCheckSources = null;
1472
1473
  let snapshotCaptureActive = false;
1473
1474
  let snapshotSources = null;
1474
1475
  function ownerInSnapshotScope(owner) {
@@ -1930,6 +1931,26 @@ function read(el) {
1930
1931
  const firewall = el._firewall;
1931
1932
  const prevCheck = pendingCheckActive;
1932
1933
  pendingCheckActive = false;
1934
+ let c = context;
1935
+ if (c?._root) c = c._parentComputed;
1936
+ const owner = firewall || el;
1937
+ const pendingComputed = el;
1938
+ if (typeof pendingComputed._fn === "function") {
1939
+ const comp = el;
1940
+ if (comp._flags & REACTIVE_LAZY) {
1941
+ comp._flags &= ~REACTIVE_LAZY;
1942
+ recompute(comp, true);
1943
+ } else if (comp._flags & REACTIVE_DISPOSED) {
1944
+ recompute(comp, true);
1945
+ } else {
1946
+ updateIfNecessary(comp);
1947
+ }
1948
+ }
1949
+ if (c && owner._statusFlags & STATUS_PENDING && owner._statusFlags & STATUS_UNINITIALIZED) {
1950
+ if (tracking && el !== c) link(el, c);
1951
+ pendingCheckActive = prevCheck;
1952
+ throw owner._error;
1953
+ }
1933
1954
  if (firewall && el._overrideValue !== undefined) {
1934
1955
  if (
1935
1956
  el._overrideValue !== NOT_PENDING &&
@@ -1937,17 +1958,14 @@ function read(el) {
1937
1958
  ) {
1938
1959
  foundPending = true;
1939
1960
  }
1940
- let c = context;
1941
- if (c?._root) c = c._parentComputed;
1961
+ collectPendingSources(el);
1962
+ collectPendingSources(firewall);
1942
1963
  if (c && tracking) link(el, c);
1943
- read(getPendingSignal(el));
1944
- read(getPendingSignal(firewall));
1945
1964
  } else {
1946
- if (read(getPendingSignal(el))) foundPending = true;
1947
- if (firewall && read(getPendingSignal(firewall))) foundPending = true;
1965
+ collectPendingSources(el);
1966
+ if (firewall) collectPendingSources(firewall);
1948
1967
  }
1949
1968
  pendingCheckActive = prevCheck;
1950
- return el._value;
1951
1969
  }
1952
1970
  let c = context;
1953
1971
  if (c?._root) c = c._parentComputed;
@@ -2223,9 +2241,20 @@ function getPendingSignal(el) {
2223
2241
  }
2224
2242
  return el._pendingSignal;
2225
2243
  }
2244
+ function collectPendingSources(el) {
2245
+ pendingCheckSources?.add(el);
2246
+ const owner = el._firewall || el;
2247
+ if (owner !== el) pendingCheckSources?.add(owner);
2248
+ }
2226
2249
  function computePendingState(el) {
2227
2250
  const comp = el;
2228
2251
  const firewall = el._firewall;
2252
+ if (el._parentSource) {
2253
+ const parent = el._parentSource;
2254
+ if (parent._statusFlags & STATUS_PENDING && !(parent._statusFlags & STATUS_UNINITIALIZED))
2255
+ return true;
2256
+ return el._pendingValue !== NOT_PENDING && !(comp._statusFlags & STATUS_UNINITIALIZED);
2257
+ }
2229
2258
  if (firewall && el._pendingValue !== NOT_PENDING) {
2230
2259
  return !firewall._inFlight && !(firewall._statusFlags & STATUS_PENDING);
2231
2260
  }
@@ -2299,16 +2328,38 @@ function latest(fn) {
2299
2328
  function isPending(fn) {
2300
2329
  const prevPendingCheck = pendingCheckActive;
2301
2330
  const prevFoundPending = foundPending;
2331
+ const prevPendingCheckSources = pendingCheckSources;
2302
2332
  pendingCheckActive = true;
2303
2333
  foundPending = false;
2334
+ pendingCheckSources = new Set();
2335
+ const collectPending = () => {
2336
+ pendingCheckActive = false;
2337
+ const prevStrictRead = strictRead;
2338
+ strictRead = false;
2339
+ try {
2340
+ pendingCheckSources.forEach(source => {
2341
+ if (read(getPendingSignal(source))) foundPending = true;
2342
+ });
2343
+ } finally {
2344
+ strictRead = prevStrictRead;
2345
+ pendingCheckActive = true;
2346
+ }
2347
+ };
2304
2348
  try {
2305
2349
  fn();
2350
+ collectPending();
2306
2351
  return foundPending;
2307
- } catch {
2352
+ } catch (e) {
2353
+ collectPending();
2354
+ if (e instanceof NotReadyError) {
2355
+ if (foundPending && !(e.source?._statusFlags & STATUS_UNINITIALIZED)) return true;
2356
+ if (context) throw e;
2357
+ }
2308
2358
  return foundPending;
2309
2359
  } finally {
2310
2360
  pendingCheckActive = prevPendingCheck;
2311
2361
  foundPending = prevFoundPending;
2362
+ pendingCheckSources = prevPendingCheckSources;
2312
2363
  }
2313
2364
  }
2314
2365
  function refresh(target) {
@@ -3141,6 +3192,26 @@ function writeOnly(proxy) {
3141
3192
  function unwrapStoreValue(value) {
3142
3193
  return value?.[$TARGET]?.[STORE_VALUE] ?? value;
3143
3194
  }
3195
+ function isPrototypePollutionKey$1(property) {
3196
+ return property === "__proto__" || property === "constructor" || property === "prototype";
3197
+ }
3198
+ function hasOwnStoreProperty(target, property) {
3199
+ const optimisticOverride = target[STORE_OPTIMISTIC_OVERRIDE];
3200
+ if (
3201
+ optimisticOverride &&
3202
+ Object.prototype.hasOwnProperty.call(optimisticOverride, property) &&
3203
+ optimisticOverride[property] !== $DELETED
3204
+ )
3205
+ return true;
3206
+ const override = target[STORE_OVERRIDE];
3207
+ if (
3208
+ override &&
3209
+ Object.prototype.hasOwnProperty.call(override, property) &&
3210
+ override[property] !== $DELETED
3211
+ )
3212
+ return true;
3213
+ return Object.prototype.hasOwnProperty.call(unwrapStoreValue(target[STORE_VALUE]), property);
3214
+ }
3144
3215
  function hasInheritedAccessor(source, property) {
3145
3216
  let current = Object.getPrototypeOf(source);
3146
3217
  while (current && current !== Object.prototype) {
@@ -3332,6 +3403,8 @@ const storeTraps = {
3332
3403
  }
3333
3404
  }
3334
3405
  if (writeOnly(receiver)) {
3406
+ if (isPrototypePollutionKey$1(property) && !hasOwnStoreProperty(target, property))
3407
+ return undefined;
3335
3408
  let value =
3336
3409
  tracked && (overridden || !proxySource)
3337
3410
  ? tracked._overrideValue !== undefined && tracked._overrideValue !== NOT_PENDING
@@ -3409,6 +3482,7 @@ const storeTraps = {
3409
3482
  return has;
3410
3483
  },
3411
3484
  set(target, property, rawValue) {
3485
+ if (property === "__proto__") return true;
3412
3486
  const store = target[$PROXY];
3413
3487
  if (writeOnly(store)) {
3414
3488
  untrack(() => {
@@ -3470,6 +3544,7 @@ const storeTraps = {
3470
3544
  return true;
3471
3545
  },
3472
3546
  defineProperty(target, property, descriptor) {
3547
+ if (property === "__proto__") return true;
3473
3548
  const store = target[$PROXY];
3474
3549
  if (writeOnly(store)) {
3475
3550
  untrack(() => {
@@ -3496,6 +3571,7 @@ const storeTraps = {
3496
3571
  return true;
3497
3572
  },
3498
3573
  deleteProperty(target, property) {
3574
+ if (property === "__proto__") return true;
3499
3575
  const optDeleted = target[STORE_OPTIMISTIC_OVERRIDE]?.[property] === $DELETED;
3500
3576
  const regDeleted = target[STORE_OVERRIDE]?.[property] === $DELETED;
3501
3577
  if (writeOnly(target[$PROXY]) && !optDeleted && !regDeleted) {
@@ -4207,7 +4283,7 @@ function createBoundChildren(owner, fn, queue, mask) {
4207
4283
  cleanup(() => parentQueue.removeChild(owner._queue));
4208
4284
  return runWithOwner(owner, () => {
4209
4285
  const c = computed(fn);
4210
- return boundaryComputed(() => staleValues(() => flatten(read(c))), mask);
4286
+ return boundaryComputed(() => flatten(read(c)), mask);
4211
4287
  });
4212
4288
  }
4213
4289
  const ON_INIT = Symbol();
@@ -4356,6 +4432,7 @@ class CollectionQueue extends Queue {
4356
4432
  _tree;
4357
4433
  _pending = true;
4358
4434
  _disabled = signal(false, { ownedWrite: true, _noSnapshot: true });
4435
+ _error;
4359
4436
  _collapsed = signal(false, { ownedWrite: true, _noSnapshot: true });
4360
4437
  _revealController;
4361
4438
  _initialized = false;
@@ -4397,6 +4474,9 @@ class CollectionQueue extends Queue {
4397
4474
  const wasEmpty = this._sources.size === 0;
4398
4475
  this._sources.add(source);
4399
4476
  if (wasEmpty) setSignal(this._disabled, true);
4477
+ if (this._collectionType & STATUS_ERROR) {
4478
+ setSignal(this._error, source._error?.cause ?? source._error);
4479
+ }
4400
4480
  }
4401
4481
  }
4402
4482
  type &= ~this._collectionType;
@@ -4450,6 +4530,8 @@ function createCollectionBoundary(type, fn, fallback, onFn) {
4450
4530
  const owner = createOwner();
4451
4531
  if (_revealUsed) setContext(RevealControllerContext, null, owner);
4452
4532
  const queue = new CollectionQueue(type);
4533
+ if (type === STATUS_ERROR)
4534
+ queue._error = signal(undefined, { ownedWrite: true, _noSnapshot: true });
4453
4535
  if (onFn) queue._onFn = onFn;
4454
4536
  const tree = (queue._tree = createBoundChildren(owner, fn, queue, type));
4455
4537
  untrack(() => {
@@ -4485,14 +4567,12 @@ function createLoadingBoundary(fn, fallback, options) {
4485
4567
  return createCollectionBoundary(STATUS_PENDING, fn, () => fallback(), options?.on);
4486
4568
  }
4487
4569
  function createErrorBoundary(fn, fallback) {
4488
- return createCollectionBoundary(STATUS_ERROR, fn, queue => {
4489
- let source = queue._sources.values().next().value;
4490
- const error = source._error?.cause ?? source._error;
4491
- return fallback(error, () => {
4570
+ return createCollectionBoundary(STATUS_ERROR, fn, queue =>
4571
+ fallback(accessor(queue._error), () => {
4492
4572
  for (const source of queue._sources) recompute(source);
4493
4573
  schedule();
4494
- });
4495
- });
4574
+ })
4575
+ );
4496
4576
  }
4497
4577
  function createRevealOrder(fn, options) {
4498
4578
  _revealUsed = true;