@mmstack/primitives 21.9.2 → 21.9.4

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
@@ -766,7 +766,8 @@ const profile = persistedStore({ first: '', last: '' }, {
766
766
  `persistedStore` is `store()` + `persist()`. Reach for `persist(store, opt)` directly to add durability to a store you already have — one you also `meshSync`, or a worker-owned store's replica. Persistence is a reader over the op-log, so it composes with the other readers on the same store.
767
767
 
768
768
  ```typescript
769
- import { store, persist, meshSync } from '@mmstack/primitives';
769
+ import { store, persist } from '@mmstack/primitives';
770
+ import { meshSync } from '@mmstack/mesh';
770
771
 
771
772
  const doc = store({ title: '', body: '' });
772
773
  persist(doc, { key: 'draft', store: idbKeyval }); // durable to IndexedDB
@@ -1721,8 +1721,7 @@ function createImmutableObjectUpdater(source, key, vivifyFn) {
1721
1721
  return { ...vivified, [key]: next };
1722
1722
  });
1723
1723
  }
1724
- function createUpdater(source, key, vivify) {
1725
- const sample = untracked(source);
1724
+ function createUpdaterFromSample(source, key, vivify, sample) {
1726
1725
  // fast path for when vivification is off
1727
1726
  if (!vivify) {
1728
1727
  if (Array.isArray(sample) && typeof key === 'number') {
@@ -1770,6 +1769,19 @@ function createUpdater(source, key, vivify) {
1770
1769
  ? createMutableObjectUpdater(source, key, vivifyFn)
1771
1770
  : createImmutableObjectUpdater(source, key, vivifyFn);
1772
1771
  }
1772
+ /**
1773
+ * Selects the property updater once, on the first actual write. Construction must not sample the
1774
+ * source: a writable derivation may currently throw, and reads still need a child producer that can
1775
+ * subscribe and recover. The routing sample remains deliberately untracked, so deferring it adds no
1776
+ * dependency to the caller.
1777
+ */
1778
+ function createUpdater(source, key, vivify) {
1779
+ let update;
1780
+ return (next) => {
1781
+ update ??= createUpdaterFromSample(source, key, vivify, untracked(source));
1782
+ update(next);
1783
+ };
1784
+ }
1773
1785
  function derived(source, optOrKey, opt) {
1774
1786
  const vivify = typeof optOrKey === 'object' ? false : (opt?.vivify ?? false);
1775
1787
  // With vivification the source may legitimately be null/undefined
@@ -4181,14 +4193,19 @@ function alwaysFalse() {
4181
4193
  function markAsLeaf(sig, value, vivifyEnabled, noUnionLeaves) {
4182
4194
  if (typeof sig[LEAF] !== 'function') {
4183
4195
  let memo;
4196
+ let initialClassification;
4184
4197
  const probe = () => {
4185
4198
  if (memo)
4186
4199
  return memo();
4187
- memo = noUnionLeaves
4188
- ? isLeafValue(untracked(value), vivifyEnabled)
4189
- ? alwaysTrue
4190
- : alwaysFalse
4191
- : computed(() => isLeafValue(value(), vivifyEnabled));
4200
+ if (noUnionLeaves) {
4201
+ initialClassification ??= computed(() => isLeafValue(value(), vivifyEnabled));
4202
+ const result = initialClassification();
4203
+ memo = result ? alwaysTrue : alwaysFalse;
4204
+ initialClassification = undefined;
4205
+ }
4206
+ else {
4207
+ memo = computed(() => isLeafValue(value(), vivifyEnabled));
4208
+ }
4192
4209
  return memo();
4193
4210
  };
4194
4211
  Object.defineProperty(sig, LEAF, {
@@ -4535,21 +4552,19 @@ function mutableChildEqual(a, b) {
4535
4552
  * correct after it. The only place a child node is constructed — shared by every container kind.
4536
4553
  */
4537
4554
  function buildChildNode(target, prop, isMutableSource, options) {
4538
- const value = untracked(target);
4539
- const nodeVivify = resolveVivify(value, options.vivify);
4540
- const vivifyFn = createVivify(nodeVivify);
4541
- const equalFn = isMutableSource && (isRecord$1(value) || Array.isArray(value))
4542
- ? mutableChildEqual
4543
- : undefined;
4555
+ let vivifyFn = options.vivify === false ? createVivify(false) : undefined;
4556
+ const resolveVivifyFn = (sample) => (vivifyFn ??= createVivify(resolveVivify(sample, options.vivify)));
4557
+ const lazyVivify = (value, key) => resolveVivifyFn(value)(value, key);
4544
4558
  const computation = derived(target, {
4545
- from: (v) => v?.[prop],
4546
- onChange: createFallbackOnChange(target, prop, vivifyFn, isMutableSource),
4547
- equal: equalFn,
4559
+ from: (v) => {
4560
+ resolveVivifyFn(v);
4561
+ return v?.[prop];
4562
+ },
4563
+ onChange: createFallbackOnChange(target, prop, lazyVivify, isMutableSource),
4564
+ equal: isMutableSource ? mutableChildEqual : undefined,
4548
4565
  });
4549
- const childSample = untracked(computation);
4550
- const childVivify = resolveVivify(childSample, options.vivify);
4551
4566
  const proxy = toStore(computation, options);
4552
- markAsLeaf(proxy, computation, childVivify !== false, options.noUnionLeaves);
4567
+ markAsLeaf(proxy, computation, options.vivify !== false, options.noUnionLeaves);
4553
4568
  return proxy;
4554
4569
  }
4555
4570
  /**
@@ -4687,7 +4702,16 @@ function toStore(source, { injector, vivify = false, noUnionLeaves = false, ...r
4687
4702
  if ((typeof prop === 'symbol' && prop !== Symbol.iterator) ||
4688
4703
  (typeof prop === 'string' && SIGNAL_FN_PROP.has(prop)))
4689
4704
  return target[prop];
4690
- const k = untracked(kind);
4705
+ const child = (key) => getCachedChild(target, prop, () => buildChildNode(target, key, isMutableSource, STORE_OPTIONS), STORE_OPTIONS[STORE_SHARED_GLOBALS].cache, STORE_OPTIONS[STORE_SHARED_GLOBALS].registry);
4706
+ let k;
4707
+ try {
4708
+ k = untracked(kind);
4709
+ }
4710
+ catch (cause) {
4711
+ if (typeof prop === 'string' && prop !== 'extend')
4712
+ return child(isIndexProp(prop) ? +prop : prop);
4713
+ throw cause;
4714
+ }
4691
4715
  if (prop === 'extend' && k !== 'array')
4692
4716
  return (seed) => scopedStore(s, seed, isMutableSource
4693
4717
  ? 'mutable'
@@ -4706,7 +4730,7 @@ function toStore(source, { injector, vivify = false, noUnionLeaves = false, ...r
4706
4730
  }
4707
4731
  if (k === 'array' && !isIndexProp(prop))
4708
4732
  return Reflect.get(target, prop, receiver);
4709
- return getCachedChild(target, prop, () => buildChildNode(target, k === 'array' ? +prop : prop, isMutableSource, STORE_OPTIONS), STORE_OPTIONS[STORE_SHARED_GLOBALS].cache, STORE_OPTIONS[STORE_SHARED_GLOBALS].registry);
4733
+ return child(k === 'array' ? +prop : prop);
4710
4734
  },
4711
4735
  });
4712
4736
  return s;