@solidjs/signals 2.0.0-rc.18 → 2.0.0-rc.19

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.
Files changed (65) hide show
  1. package/dist/dev-shared.js +168 -88
  2. package/dist/dev.attribution.js +16 -13
  3. package/dist/dev.js +272 -129
  4. package/dist/observe/boundaries.js +88 -67
  5. package/dist/observe/core/action.js +8 -0
  6. package/dist/observe/core/async.js +46 -34
  7. package/dist/observe/core/attribution.js +30 -28
  8. package/dist/observe/core/constants.js +21 -1
  9. package/dist/observe/core/core.js +164 -136
  10. package/dist/observe/core/effect.js +6 -6
  11. package/dist/observe/core/graph.js +3 -3
  12. package/dist/observe/core/heap.js +5 -5
  13. package/dist/observe/core/lanes.js +104 -84
  14. package/dist/observe/core/owner.js +10 -9
  15. package/dist/observe/core/scheduler.js +38 -35
  16. package/dist/observe/core/truth.js +6 -6
  17. package/dist/observe/core/verdict.js +13 -13
  18. package/dist/observe/deferred.js +39 -40
  19. package/dist/observe/index.js +2 -2
  20. package/dist/observe/map.js +22 -22
  21. package/dist/observe/reveal.js +5 -5
  22. package/dist/observe/signals.js +57 -15
  23. package/dist/observe/store/affects.js +1 -1
  24. package/dist/observe/store/hooks.js +3 -0
  25. package/dist/observe/store/optimistic.js +11 -11
  26. package/dist/observe/store/projection.js +34 -21
  27. package/dist/observe/store/reconcile.js +2 -2
  28. package/dist/observe/store/store.js +63 -53
  29. package/dist/observe/store/utils.js +7 -2
  30. package/dist/prod/boundaries.js +153 -132
  31. package/dist/prod/core/action.js +8 -0
  32. package/dist/prod/core/async.js +55 -43
  33. package/dist/prod/core/constants.js +14 -1
  34. package/dist/prod/core/core.js +162 -134
  35. package/dist/prod/core/effect.js +9 -9
  36. package/dist/prod/core/graph.js +3 -3
  37. package/dist/prod/core/heap.js +12 -12
  38. package/dist/prod/core/lanes.js +98 -78
  39. package/dist/prod/core/owner.js +15 -14
  40. package/dist/prod/core/scheduler.js +43 -40
  41. package/dist/prod/core/truth.js +6 -6
  42. package/dist/prod/core/verdict.js +17 -17
  43. package/dist/prod/deferred.js +39 -40
  44. package/dist/prod/index.js +2 -2
  45. package/dist/prod/map.js +14 -14
  46. package/dist/prod/reveal.js +8 -8
  47. package/dist/prod/signals.js +46 -4
  48. package/dist/prod/store/affects.js +1 -1
  49. package/dist/prod/store/hooks.js +3 -0
  50. package/dist/prod/store/optimistic.js +16 -16
  51. package/dist/prod/store/projection.js +22 -9
  52. package/dist/prod/store/reconcile.js +2 -2
  53. package/dist/prod/store/store.js +262 -262
  54. package/dist/prod/store/utils.js +2 -0
  55. package/dist/types/core/action.d.ts +8 -0
  56. package/dist/types/core/constants.d.ts +20 -0
  57. package/dist/types/core/core.d.ts +14 -1
  58. package/dist/types/core/dev.d.ts +1 -1
  59. package/dist/types/core/index.d.ts +1 -1
  60. package/dist/types/core/lanes.d.ts +5 -1
  61. package/dist/types/core/scheduler.d.ts +2 -0
  62. package/dist/types/index.d.ts +3 -1
  63. package/dist/types/signals.d.ts +37 -0
  64. package/dist/types/store/target.d.ts +2 -0
  65. package/package.json +1 -1
@@ -283,10 +283,30 @@ const CONFIG_WIDE = 1 << 26;
283
283
  * creation by dev builds only (the observe artifact mangles the option name,
284
284
  * as it does `_wide`). */
285
285
  const CONFIG_SUPERSEDES = 1 << 27;
286
+ /** Observe tiers only: the memo `merge()` creates for a function source — a
287
+ * key bag readers consume key by key, built by the framework (a compiled
288
+ * component spread) with options no user can reach. The attribution engine's
289
+ * UNSTABLE_MEMO_OUTPUT skips it: a fresh-but-equal bag is the idiom
290
+ * (`{...(on() ? { a } : {})}`), and the advice (`equals`) cannot be applied
291
+ * (#4256). Set through `_extraConfig` by observe builds only. */
292
+ const CONFIG_KEY_BAG = 1 << 28;
293
+ /** The frame (rule 3, D-3): a render effect (set at creation, as
294
+ * `EFFECT_RENDER << 23` — keep the two in step), and a boundary's tree and
295
+ * output (boundaries.ts) — structure between the content and the render
296
+ * effect that shows it, not a user derivation of the content. Outside a
297
+ * hold's own flush it reads that hold's values as committed and is
298
+ * re-derived at its landing, and a re-pass of it publishes mainline: it
299
+ * joins nothing, so two mounts under one boundary made in separate flushes
300
+ * keep their holds apart (D-4, S-5 rows 1′–3′, #4283). */
301
+ const CONFIG_FRAME = 1 << 23;
286
302
  const STATUS_NONE = 0;
287
303
  const STATUS_PENDING = 1 << 0;
288
304
  const STATUS_ERROR = 1 << 1;
289
305
  const STATUS_UNINITIALIZED = 1 << 2;
306
+ /** An error that answered a node's first read (no value has ever landed):
307
+ * the error, not UNINITIALIZED, is its status while shown, but a re-ask
308
+ * makes it uninitialized-pending again — it still has no value (#4244). */
309
+ const STATUS_NO_VALUE = 1 << 3;
290
310
  /** `catchHook`'s answer when the catcher is a boundary re-armed by
291
311
  * `on` (truthy, as any catch): what it collects is its own, not the hold's. */
292
312
  const CAUGHT_REARMED = 2;
@@ -1214,10 +1234,12 @@ function disposeChildren(node, self = false, zombie) {
1214
1234
  // A death that can unblock the future (L2, `futureBlocked`): a held
1215
1235
  // flight's — a transaction's or a lane's (its `_x._transaction`) — or a
1216
1236
  // stale reader's (REACTIVE_FRAME_READ — a frame that derived from one).
1237
+ // An idle pending queue would also pin it until an unrelated flush.
1217
1238
  // Nothing else re-examines a dead node, so make sure a seam comes.
1218
1239
  if (
1219
1240
  (node._statusFlags & STATUS_PENDING && node._x?._transaction != null) ||
1220
- flags & REACTIVE_FRAME_READ
1241
+ flags & REACTIVE_FRAME_READ ||
1242
+ pendingNodes.length
1221
1243
  )
1222
1244
  schedule();
1223
1245
  }
@@ -2071,12 +2093,13 @@ function schedule() {
2071
2093
  * hook machinery (pay-for-use).
2072
2094
  */
2073
2095
  const ROOT_ERROR_HOOK = Symbol.for("solid-js/root-error-hook");
2096
+ const HALTED = "[REACTIVITY_HALTED]";
2074
2097
  function haltReactivity(cause) {
2075
2098
  if (halted) return;
2076
2099
  halted = true;
2077
2100
  // A cleanup error collected before the halt is dropped (owner.ts).
2078
2101
  rethrowCleanupError(true);
2079
- let message = "[REACTIVITY_HALTED]";
2102
+ let message = HALTED;
2080
2103
  {
2081
2104
  message +=
2082
2105
  " An uncaught error halted the reactive system. No further updates will be processed. Handle errors with <Errored> or treat this as a crash.";
@@ -2302,11 +2325,12 @@ class GlobalQueue {
2302
2325
  // This flush's own runs, the lanes' reveals, and the landings' held runs
2303
2326
  // are collected apart and ordered below.
2304
2327
  const own = this._queues;
2305
- const lanes = (this._queues = [[], []]);
2328
+ const lanes = [[], []];
2306
2329
  // The passes that read this frame's stagings as the screen read held
2307
2330
  // writes if it parked: the lane seam re-derives them on the committed
2308
2331
  // world (a lane's runs wait this round).
2309
2332
  if (laneSeamsHook) {
2333
+ this._queues = lanes;
2310
2334
  laneSeamsHook(t !== null ? stagedReaders : null);
2311
2335
  if (stagedReaders.length) stagedReaders.length = 0;
2312
2336
  }
@@ -2462,7 +2486,7 @@ function land(u) {
2462
2486
  // (`_nodes` still lists them).
2463
2487
  if (attrHooks !== null) attrHooks.transitionSettled(u);
2464
2488
  const frame = reruns(u);
2465
- if (u._marks !== null) releaseMarksHook(u._marks);
2489
+ if (releaseMarksHook && u._marks !== null) releaseMarksHook(u._marks);
2466
2490
  // Old children die in the commits (cleanups first), then the stashed
2467
2491
  // effects run ahead of this flush's own. A node a lane took over since
2468
2492
  // (a guess written over the staged truth) is the lane's to land.
@@ -3515,8 +3539,14 @@ function handleAsync(
3515
3539
  return;
3516
3540
  }
3517
3541
  // A store derive's landing commits through its setter: unheld, the
3518
- // shown error leaves now; held, at the derive's commit.
3519
- if (!(el._config & CONFIG_HELD)) el._x._shownError = undefined;
3542
+ // shown error leaves now, and so does a commit-beneath-a-flight's
3543
+ // CONFIG_INPUTS_PUBLISHED (its first flight's, #4269) — left standing,
3544
+ // a verdict reader of the next flight would suspend instead of being
3545
+ // served the screen; held, both at the derive's commit.
3546
+ if (!(el._config & CONFIG_HELD)) {
3547
+ el._x._shownError = undefined;
3548
+ el._config &= ~CONFIG_INPUTS_PUBLISHED;
3549
+ }
3520
3550
  if (wasUninitialized) landStatus(el, true);
3521
3551
  // Attribution hook: this path landed through the setter (derived
3522
3552
  // stores, projections), which does not go through setSignal, so the
@@ -3849,14 +3879,28 @@ function notifyStatus(el, status, error) {
3849
3879
  // D-41: a re-ask of a shown error keeps it the display (`_shownError`).
3850
3880
  if (el._statusFlags & STATUS_ERROR) el._x._shownError = el._x._error;
3851
3881
  addPendingSource(el, pendingSource);
3852
- el._statusFlags = STATUS_PENDING | (el._statusFlags & STATUS_UNINITIALIZED);
3882
+ // A re-ask of an error that answered the first read: still no value.
3883
+ el._statusFlags =
3884
+ STATUS_PENDING |
3885
+ (el._statusFlags & STATUS_NO_VALUE
3886
+ ? STATUS_UNINITIALIZED
3887
+ : el._statusFlags & STATUS_UNINITIALIZED);
3853
3888
  // Preserve the current source on this propagation so readers park on
3854
3889
  // the distinct pending source.
3855
3890
  setPendingError(el, pendingSource, error);
3856
3891
  } else {
3857
3892
  clearPendingSources(el);
3893
+ // An error answering a node with no value marks it so; a re-ask of it
3894
+ // (pending) is uninitialized again; a write (STATUS_NONE) gives it one.
3858
3895
  el._statusFlags =
3859
- status | (status !== STATUS_ERROR ? el._statusFlags & STATUS_UNINITIALIZED : 0);
3896
+ status |
3897
+ (status === STATUS_ERROR
3898
+ ? el._statusFlags & (STATUS_UNINITIALIZED | STATUS_NO_VALUE)
3899
+ ? STATUS_NO_VALUE
3900
+ : 0
3901
+ : status === STATUS_PENDING && el._statusFlags & STATUS_NO_VALUE
3902
+ ? STATUS_UNINITIALIZED
3903
+ : el._statusFlags & STATUS_UNINITIALIZED);
3860
3904
  ext(el)._error = error;
3861
3905
  }
3862
3906
  // Lanes: a written guess is an optimistic boundary (A17 — "the optimistic
@@ -3955,6 +3999,9 @@ function propagateStatus(el, status, error) {
3955
3999
  joinFuture(txOf(sub));
3956
4000
  }
3957
4001
  notifyStatus(sub, status, error);
4002
+ // A derived store's derive (store/projection.ts): marked, not re-run —
4003
+ // its leaves' readers are not its dependents, so the family walks them.
4004
+ sub.fam?.st(status);
3958
4005
  }
3959
4006
  });
3960
4007
  }
@@ -4057,8 +4104,23 @@ function setSnapshotCapture(active) {
4057
4104
  snapshotCaptureActive = active;
4058
4105
  if (active && !snapshotSources) snapshotSources = new NewSet();
4059
4106
  }
4060
- function markSnapshotScope(owner) {
4061
- owner._snapshotScope = true;
4107
+ /**
4108
+ * Marks `owner` a snapshot scope: while capture is on, the readers created
4109
+ * under it serve each source's snapshot (the value it had when hydration
4110
+ * began) and replay at `releaseSnapshotScope`.
4111
+ *
4112
+ * With `served` (hydration), `owner` is instead a hydrated computed and
4113
+ * `served` its server answer — what the server rendered every reader of the
4114
+ * node with — landing after the node was created pending (so the creation
4115
+ * arm skipped it). It becomes the node's snapshot when it has none, whether
4116
+ * the node committed the answer or a client write had already taken its
4117
+ * compute over. A claim made later reads the value its markup shows, and
4118
+ * replays the node's own value at its release, as for a written signal.
4119
+ */
4120
+ function markSnapshotScope(owner, served) {
4121
+ if (arguments.length < 2) owner._snapshotScope = true;
4122
+ else if (snapshotCaptureActive && owner._x?._snapshotValue === undefined)
4123
+ takeSnapshot(owner, served);
4062
4124
  }
4063
4125
  function releaseSnapshotScope(owner) {
4064
4126
  owner._snapshotScope = false;
@@ -4171,6 +4233,8 @@ function recompute(el, create = false) {
4171
4233
  // A29, or mounted by a pass of it still awaiting its commit, #4010) keeps
4172
4234
  // staging: live writes keep it current, it effects at the swap (ruling
4173
4235
  // A).
4236
+ // A boundary's structure (CONFIG_FRAME) is the frame like a render
4237
+ // effect: it publishes mainline outside its transaction's flush (#4283).
4174
4238
  // A pending flight is the transition's own work (#3884). A probe on an
4175
4239
  // earlier pass left CONFIG_VERDICT, and a frame read here would serve the
4176
4240
  // committed screen, settle the flight and drop the hold — a superseding
@@ -4184,8 +4248,10 @@ function recompute(el, create = false) {
4184
4248
  // world (`read`), and has left it otherwise.
4185
4249
  // An answered deferred node's re-pass is a lagging question (D-40):
4186
4250
  // it joins nothing, so the write that reached it commits mainline.
4251
+ // `EFFECT_RENDER << 23` is CONFIG_FRAME (a render effect, a boundary's
4252
+ // tree and output), spelled from the effect type as at creation.
4187
4253
  if (tx._lane || el._config & CONFIG_LAGS);
4188
- else if (isEffect !== EFFECT_RENDER && !(el._config & CONFIG_VERDICT))
4254
+ else if (!(el._config & (CONFIG_VERDICT | (EFFECT_RENDER << 23))))
4189
4255
  joinPassTx(tx, freshHook?.(el, el._statusFlags & STATUS_UNINITIALIZED));
4190
4256
  else if (
4191
4257
  tx !== flushTransaction &&
@@ -4197,8 +4263,10 @@ function recompute(el, create = false) {
4197
4263
  // after the new frame's first runs, and the held pass's own
4198
4264
  // children die below (`disposeChildren`). The landing re-derives a
4199
4265
  // fresh held frame for the reveal (`_reruns`).
4266
+ // Not held any more, whichever frame reader it is: its readers read
4267
+ // the value this pass publishes.
4200
4268
  el._pendingValue = NOT_PENDING;
4201
- if (isEffect === EFFECT_RENDER) el._config &= ~CONFIG_HELD;
4269
+ el._config &= ~CONFIG_HELD;
4202
4270
  }
4203
4271
  }
4204
4272
  // The previous pass's frame. If that pass is still awaiting its commit
@@ -4482,7 +4550,9 @@ function recompute(el, create = false) {
4482
4550
  // confirm is a landing too — the lane's end commits it) and notifies
4483
4551
  // only a correction: an equal truth re-runs nothing (lanes.ts). (As the
4484
4552
  // lane's own work the lane judged it — `laneStage`.)
4553
+ // (The hook first: a build without lanes folds the arm away.)
4485
4554
  if (
4555
+ laneOutcomeHook &&
4486
4556
  !create &&
4487
4557
  lane === null &&
4488
4558
  el._config & CONFIG_GUESS &&
@@ -4853,13 +4923,18 @@ function frameRead(c, el) {
4853
4923
  // read the screen. Lane work with no committed value yet reads a flight
4854
4924
  // as a mount's memo does: it enters, and the boundary it mounts catches
4855
4925
  // the pending (#3540).
4926
+ // A boundary's tree and output (CONFIG_FRAME) read as a render effect
4927
+ // does: structure, not a derivation of what it shows (#4283). A mount
4928
+ // under a hold still enters it: the content memo it reads is born held,
4929
+ // with no committed value to serve.
4856
4930
  // (Verdict readers and lanes exist only with their engines installed.)
4857
4931
  const verdict = observeFlightHook && c._config & CONFIG_VERDICT;
4858
4932
  const lane = laneStageHook && passLane !== null;
4859
4933
  if (
4860
4934
  (!lane || (c._statusFlags & STATUS_UNINITIALIZED && el._statusFlags & STATUS_PENDING)) &&
4861
4935
  !verdict &&
4862
- (c._type !== EFFECT_RENDER || el._config & CONFIG_INPUTS_PUBLISHED)
4936
+ // CONFIG_FRAME, spelled as at the effect's creation.
4937
+ (!(c._config & (EFFECT_RENDER << 23)) || el._config & CONFIG_INPUTS_PUBLISHED)
4863
4938
  )
4864
4939
  return false;
4865
4940
  const t = txOf(el);
@@ -4916,6 +4991,9 @@ function createEffectNode(fn, effectFn, errorFn, type, options) {
4916
4991
  const self = {
4917
4992
  id: inheritId(options, transparent, context),
4918
4993
  _config:
4994
+ // CONFIG_FRAME for a render effect (EFFECT_RENDER = 1; a user
4995
+ // effect's 1 << 24 is unused).
4996
+ (type << 23) |
4919
4997
  (transparent ? CONFIG_TRANSPARENT : 0) |
4920
4998
  (options?.ownedWrite ? CONFIG_OWNED_WRITE : 0) |
4921
4999
  (options?.sync ? CONFIG_SYNC : 0) |
@@ -5008,11 +5086,8 @@ function setupComputedNode(self, options) {
5008
5086
  wireExternalSourceHook?.(self);
5009
5087
  !options?.lazy && recompute(self, true);
5010
5088
  if (snapshotCaptureActive && !options?.lazy) {
5011
- if (!(self._statusFlags & STATUS_PENDING) && !(self._config & CONFIG_NO_SNAPSHOT)) {
5012
- ext(self)._snapshotValue = self._value === undefined ? NO_SNAPSHOT : self._value;
5013
- self._config |= CONFIG_HAS_SNAPSHOT;
5014
- snapshotSources.add(self);
5015
- }
5089
+ if (!(self._statusFlags & STATUS_PENDING) && !(self._config & CONFIG_NO_SNAPSHOT))
5090
+ takeSnapshot(self, self._value);
5016
5091
  }
5017
5092
  }
5018
5093
  function signal(v, options) {
@@ -5038,11 +5113,7 @@ function signal(v, options) {
5038
5113
  };
5039
5114
  s._internal = false;
5040
5115
  if (options?.unobserved) ext(s)._unobserved = options.unobserved;
5041
- if (snapshotCaptureActive && !(s._config & CONFIG_NO_SNAPSHOT)) {
5042
- ext(s)._snapshotValue = v === undefined ? NO_SNAPSHOT : v;
5043
- s._config |= CONFIG_HAS_SNAPSHOT;
5044
- snapshotSources.add(s);
5045
- }
5116
+ if (snapshotCaptureActive && !(s._config & CONFIG_NO_SNAPSHOT)) takeSnapshot(s, v);
5046
5117
  return s;
5047
5118
  }
5048
5119
  function isEqual(a, b) {
@@ -5459,6 +5530,28 @@ function read(el) {
5459
5530
  const v = laneReadHook(c, el);
5460
5531
  if (v !== NOT_PENDING) return v;
5461
5532
  }
5533
+ // Ahead of the snapshot serve below: a component body's direct read is
5534
+ // wrong in the same way whether the pass is hydrating or not, and the
5535
+ // hydration pass is the console nobody is watching (#3675).
5536
+ if (strictRead && strictReadActive())
5537
+ warnStrictReadUntracked(strictRead, {
5538
+ ownerId: c?.id,
5539
+ ownerName: c?._name,
5540
+ nodeName: owner?._name
5541
+ });
5542
+ // A reader in a snapshot scope (a hydration claim) is served the value the
5543
+ // server rendered with: a client write's recompute still in flight does
5544
+ // not pull the claim off the markup it adopts — the reader replays at the
5545
+ // scope's release. An errored node throws below as for any reader.
5546
+ if (snapshotCaptureActive && c && c._config & CONFIG_IN_SNAPSHOT_SCOPE) {
5547
+ const sv = el._x?._snapshotValue;
5548
+ if (sv !== undefined && !(owner._statusFlags & STATUS_ERROR)) {
5549
+ const snapshot = sv === NO_SNAPSHOT ? undefined : sv;
5550
+ const current = el._pendingValue !== NOT_PENDING ? el._pendingValue : el._value;
5551
+ if (current !== snapshot) c._flags |= REACTIVE_SNAPSHOT_STALE;
5552
+ return snapshot;
5553
+ }
5554
+ }
5462
5555
  // A stale reader of a held flight (rule 3, A15's reveal corollary) is served
5463
5556
  // the committed value — coherent with the frame, whose inputs are the
5464
5557
  // committed ones too — and does not go pending on it. So is lane work
@@ -5535,24 +5628,6 @@ function read(el) {
5535
5628
  return read(el);
5536
5629
  } else throw owner._x?._error;
5537
5630
  }
5538
- // Ahead of the snapshot serve below: a component body's direct read is
5539
- // wrong in the same way whether the pass is hydrating or not, and the
5540
- // hydration pass is the console nobody is watching (#3675).
5541
- if (strictRead && strictReadActive())
5542
- warnStrictReadUntracked(strictRead, {
5543
- ownerId: c?.id,
5544
- ownerName: c?._name,
5545
- nodeName: owner?._name
5546
- });
5547
- if (snapshotCaptureActive && c && c._config & CONFIG_IN_SNAPSHOT_SCOPE) {
5548
- const sv = el._x?._snapshotValue;
5549
- if (sv !== undefined) {
5550
- const snapshot = sv === NO_SNAPSHOT ? undefined : sv;
5551
- const current = el._pendingValue !== NOT_PENDING ? el._pendingValue : el._value;
5552
- if (current !== snapshot) c._flags |= REACTIVE_SNAPSHOT_STALE;
5553
- return snapshot;
5554
- }
5555
- }
5556
5631
  if (committed) return el._value;
5557
5632
  // D-41: an untracked read reads the screen, and a shown error is on it
5558
5633
  // until the answer that replaces it commits.
@@ -5679,7 +5754,10 @@ function captureWriteSnapshot(el, current) {
5679
5754
  el._x?._snapshotValue !== undefined
5680
5755
  )
5681
5756
  return;
5682
- ext(el)._snapshotValue = current === undefined ? NO_SNAPSHOT : current;
5757
+ takeSnapshot(el, current);
5758
+ }
5759
+ function takeSnapshot(el, value) {
5760
+ ext(el)._snapshotValue = value === undefined ? NO_SNAPSHOT : value;
5683
5761
  el._config |= CONFIG_HAS_SNAPSHOT;
5684
5762
  snapshotSources.add(el);
5685
5763
  }
@@ -5936,13 +6014,13 @@ function markRefresh(node) {
5936
6014
  }
5937
6015
 
5938
6016
  export {
5939
- setPassLane as $,
6017
+ merge as $,
5940
6018
  tracking as A,
5941
6019
  CONFIG_CHILDREN_FORBIDDEN as B,
5942
6020
  CONFIG_GUESS as C,
5943
6021
  passLane as D,
5944
- STATUS_PENDING as E,
5945
- EFFECT_RENDER as F,
6022
+ EFFECT_RENDER as E,
6023
+ setPassLane as F,
5946
6024
  GlobalQueue as G,
5947
6025
  sameLane as H,
5948
6026
  flushTransaction as I,
@@ -5956,14 +6034,14 @@ export {
5956
6034
  REACTIVE_CHECK as Q,
5957
6035
  REACTIVE_DISPOSED as R,
5958
6036
  STATUS_UNINITIALIZED as S,
5959
- CONFIG_INPUTS_PUBLISHED as T,
5960
- releaseQueues as U,
5961
- CONFIG_SLOT_NODE as V,
5962
- holdNode as W,
5963
- joinFuture as X,
5964
- reruns as Y,
5965
- CONFIG_STAGED as Z,
5966
- merge as _,
6037
+ STATUS_PENDING as T,
6038
+ CONFIG_INPUTS_PUBLISHED as U,
6039
+ releaseQueues as V,
6040
+ CONFIG_SLOT_NODE as W,
6041
+ holdNode as X,
6042
+ joinFuture as Y,
6043
+ reruns as Z,
6044
+ CONFIG_STAGED as _,
5967
6045
  NotReadyError as a,
5968
6046
  resetUnhandledAsync as a$,
5969
6047
  REACTIVE_JOINED as a0,
@@ -6030,7 +6108,7 @@ export {
6030
6108
  effectCallbackEvent as ay,
6031
6109
  setExternalHooks as az,
6032
6110
  CONFIG_AUTHORITATIVE as b,
6033
- resetErrorHalt as b$,
6111
+ peekNextChildId as b$,
6034
6112
  ROOT_ERROR_HOOK as b0,
6035
6113
  registerGraph as b1,
6036
6114
  runWithOwner as b2,
@@ -6049,25 +6127,25 @@ export {
6049
6127
  joinPassAt as bF,
6050
6128
  notifyEpoch as bG,
6051
6129
  SUPPORTS_PROXY as bH,
6052
- releaseMarksHook as bI,
6053
- installMarkHooks as bJ,
6054
- CONFIG_LAGS as bK,
6055
- REACTIVE_REASK as bL,
6056
- onSupersede as bM,
6057
- haltReactivity as bN,
6058
- heldUnder as bO,
6059
- unhold as bP,
6060
- laneStageHook as bQ,
6061
- REACTIVE_ZOMBIE as bR,
6062
- installBoundaryHooks as bS,
6063
- CAUGHT_REARMED as bT,
6064
- OBSERVE as bU,
6065
- clearSnapshots as bV,
6066
- enforceLoadingBoundary as bW,
6067
- getNextChildId as bX,
6068
- markSnapshotScope as bY,
6069
- peekNextChildId as bZ,
6070
- releaseSnapshotScope as b_,
6130
+ CONFIG_KEY_BAG as bI,
6131
+ releaseMarksHook as bJ,
6132
+ installMarkHooks as bK,
6133
+ CONFIG_LAGS as bL,
6134
+ REACTIVE_REASK as bM,
6135
+ onSupersede as bN,
6136
+ haltReactivity as bO,
6137
+ CONFIG_FRAME as bP,
6138
+ heldUnder as bQ,
6139
+ unhold as bR,
6140
+ laneStageHook as bS,
6141
+ REACTIVE_ZOMBIE as bT,
6142
+ installBoundaryHooks as bU,
6143
+ CAUGHT_REARMED as bV,
6144
+ OBSERVE as bW,
6145
+ clearSnapshots as bX,
6146
+ enforceLoadingBoundary as bY,
6147
+ getNextChildId as bZ,
6148
+ markSnapshotScope as b_,
6071
6149
  untrack as ba,
6072
6150
  dirtyQueue as bb,
6073
6151
  CONFIG_REDERIVE as bc,
@@ -6095,21 +6173,23 @@ export {
6095
6173
  insertIntoHeap as by,
6096
6174
  isDisposed as bz,
6097
6175
  CONFIG_OVERRIDE as c,
6098
- setConsoleFooter as c0,
6099
- setSnapshotCapture as c1,
6100
- setWriteHook as c2,
6101
- setAttributionHooks as c3,
6102
- liveRootOwners as c4,
6103
- ownerPath as c5,
6104
- isSuppressed as c6,
6105
- blockersOf as c7,
6106
- CONFIG_PLUMBING as c8,
6107
- anyExcluded as c9,
6108
- isExcluded as ca,
6109
- CONFIG_WIDE as cb,
6110
- GRAPH_SIZE_WARN_AT as cc,
6111
- noteFanOut as cd,
6112
- CONFIG_SUPERSEDES as ce,
6176
+ releaseSnapshotScope as c0,
6177
+ resetErrorHalt as c1,
6178
+ setConsoleFooter as c2,
6179
+ setSnapshotCapture as c3,
6180
+ setWriteHook as c4,
6181
+ setAttributionHooks as c5,
6182
+ liveRootOwners as c6,
6183
+ ownerPath as c7,
6184
+ isSuppressed as c8,
6185
+ blockersOf as c9,
6186
+ CONFIG_PLUMBING as ca,
6187
+ anyExcluded as cb,
6188
+ isExcluded as cc,
6189
+ CONFIG_WIDE as cd,
6190
+ GRAPH_SIZE_WARN_AT as ce,
6191
+ noteFanOut as cf,
6192
+ CONFIG_SUPERSEDES as cg,
6113
6193
  newTransaction as d,
6114
6194
  enqueueSub as e,
6115
6195
  CONFIG_VERDICT as f,
@@ -1,24 +1,25 @@
1
1
  import {
2
- bU as OBSERVE,
3
- c3 as setAttributionHooks,
4
- c4 as liveRootOwners,
2
+ bW as OBSERVE,
3
+ c5 as setAttributionHooks,
4
+ c6 as liveRootOwners,
5
5
  N as NOT_PENDING,
6
6
  at as emitDiagnostic,
7
- c5 as ownerPath,
7
+ c7 as ownerPath,
8
8
  aL as reportDiagnostic,
9
- c6 as isSuppressed,
10
- c7 as blockersOf,
11
- c8 as CONFIG_PLUMBING,
12
- c9 as anyExcluded,
13
- ca as isExcluded,
14
- cb as CONFIG_WIDE,
9
+ c8 as isSuppressed,
10
+ c9 as blockersOf,
11
+ ca as CONFIG_PLUMBING,
12
+ cb as anyExcluded,
13
+ cc as isExcluded,
14
+ bI as CONFIG_KEY_BAG,
15
+ cd as CONFIG_WIDE,
15
16
  c as CONFIG_OVERRIDE,
16
17
  C as CONFIG_GUESS,
17
18
  G as GlobalQueue,
18
19
  f as CONFIG_VERDICT,
19
- cc as GRAPH_SIZE_WARN_AT,
20
- cd as noteFanOut,
21
- ce as CONFIG_SUPERSEDES,
20
+ ce as GRAPH_SIZE_WARN_AT,
21
+ cf as noteFanOut,
22
+ cg as CONFIG_SUPERSEDES,
22
23
  b4 as $REFRESH
23
24
  } from "./dev-shared.js";
24
25
 
@@ -897,6 +898,8 @@ function checkUnstableOutput(el, prevValue, newValue) {
897
898
  // typeof guard: an explicit `unstableMemos: undefined` in enable() options
898
899
  // clobbers the default through the spread — treat any non-number as off.
899
900
  if (typeof limit !== "number") return;
901
+ // merge()'s function-source memo: a key bag no user configures (#4256).
902
+ if (el._config & CONFIG_KEY_BAG) return;
900
903
  const node = el;
901
904
  if (
902
905
  prevValue === newValue || // paranoia: changed runs should never hit this