attaform 0.31.0 → 0.31.1

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 (50) hide show
  1. package/dist/abstract.d.mts +5 -5
  2. package/dist/abstract.mjs +4 -4
  3. package/dist/dev/abstract.mjs +4 -4
  4. package/dist/dev/chunks/devtools.mjs +1 -1
  5. package/dist/dev/directive.mjs +1 -1
  6. package/dist/dev/history.mjs +15 -2
  7. package/dist/dev/index.mjs +5 -5
  8. package/dist/dev/runtime/plugins/attaform.mjs +1 -1
  9. package/dist/dev/shared/{attaform-dev.zlvDr0WB.mjs → attaform-dev.04aupFBW.mjs} +3 -2
  10. package/dist/dev/shared/{attaform-dev.y9x9Vp9F.mjs → attaform-dev.3uTCYwy8.mjs} +572 -135
  11. package/dist/dev/shared/{attaform-dev.DJ3nsWw6.mjs → attaform-dev.BpVGFSFa.mjs} +18 -9
  12. package/dist/dev/shared/{attaform-dev.B1q-x9R9.mjs → attaform-dev.Bu6wgrA5.mjs} +1 -1
  13. package/dist/dev/shared/{attaform-dev.k5X47GMD.mjs → attaform-dev.Cbx0AiQF.mjs} +3 -2
  14. package/dist/dev/shared/attaform-dev.CwYTWyPX.mjs +120 -0
  15. package/dist/dev/shared/{attaform-dev.DlaT4xGd.mjs → attaform-dev.D7lKyM_7.mjs} +4 -4
  16. package/dist/dev/shared/{attaform-dev.CtyqGia7.mjs → attaform-dev.OceE0X3v.mjs} +4 -4
  17. package/dist/dev/shared/{attaform-dev.Caibt7sb.mjs → attaform-dev.PTGM9KE1.mjs} +6 -6
  18. package/dist/{shared/attaform.8mfKZCwH.mjs → dev/shared/attaform-dev.n6n00owJ.mjs} +49 -128
  19. package/dist/dev/zod-v3.mjs +6 -6
  20. package/dist/dev/zod-v4.mjs +6 -6
  21. package/dist/dev/zod.mjs +5 -5
  22. package/dist/directive.d.mts +2 -2
  23. package/dist/directive.mjs +1 -1
  24. package/dist/history.d.mts +1 -1
  25. package/dist/history.mjs +15 -2
  26. package/dist/index.d.mts +16 -55
  27. package/dist/index.mjs +5 -5
  28. package/dist/runtime/plugins/attaform.mjs +1 -1
  29. package/dist/shared/{attaform.BWUn8Kjy.mjs → attaform.B5b-HmhH.mjs} +18 -9
  30. package/dist/shared/{attaform.CRVe8s82.d.mts → attaform.B9PYKlhB.d.mts} +43 -19
  31. package/dist/shared/{attaform.DxKQsqFZ.mjs → attaform.BPMOl562.mjs} +3 -2
  32. package/dist/{dev/shared/attaform-dev.CZz4GYZ6.mjs → shared/attaform.BPSqtU7a.mjs} +44 -156
  33. package/dist/shared/{attaform.CdZIEf7_.mjs → attaform.BhtAZysa.mjs} +3 -2
  34. package/dist/shared/{attaform.DAo0QBmS.d.mts → attaform.CYlF4P6X.d.mts} +31 -10
  35. package/dist/shared/{attaform.C4shmwyJ.mjs → attaform.CdA9bfRv.mjs} +1 -1
  36. package/dist/shared/{attaform.DNPJPOO7.mjs → attaform.DAf4ehIe.mjs} +569 -134
  37. package/dist/shared/{attaform.D9RqPgGu.d.mts → attaform.DZOynI6c.d.mts} +1 -1
  38. package/dist/shared/{attaform.L011tHgJ.mjs → attaform.KEfNRDot.mjs} +4 -4
  39. package/dist/shared/attaform._1Zp3mDG.mjs +96 -0
  40. package/dist/shared/{attaform.DZnrDrNb.d.mts → attaform.i13OEHJF.d.mts} +60 -7
  41. package/dist/shared/{attaform.DL2nl_QR.mjs → attaform.j9xI_ObC.mjs} +6 -6
  42. package/dist/shared/{attaform.LUPC-2Qg.mjs → attaform.u6jfHoed.mjs} +4 -4
  43. package/dist/zod-v3.d.mts +4 -4
  44. package/dist/zod-v3.mjs +6 -6
  45. package/dist/zod-v4.d.mts +15 -11
  46. package/dist/zod-v4.mjs +6 -6
  47. package/dist/zod.d.mts +4 -4
  48. package/dist/zod.mjs +5 -5
  49. package/package.json +2 -1
  50. package/skills/attaform/SKILL.md +1 -0
@@ -1,9 +1,10 @@
1
1
  import { computed, readonly, toRaw, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, reactive, shallowReactive, shallowRef, toValue, watch, triggerRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, effectScope, onBeforeMount, onBeforeUpdate, onMounted, nextTick } from 'vue';
2
- import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform.C4shmwyJ.mjs';
3
- import { c as armDomBinding, r as recordInheritedModifiers, w as withInheritedModifiers } from './attaform.DxKQsqFZ.mjs';
2
+ import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform.CdA9bfRv.mjs';
3
+ import { c as armDomBinding, r as recordInheritedModifiers, w as withInheritedModifiers } from './attaform.BPMOl562.mjs';
4
4
  import { R as REGISTER_OWNER_MARKER, b as V_REGISTER_MARKER } from './attaform.KvlEedlF.mjs';
5
- import { A as ANONYMOUS_FORM_KEY_PREFIX, i as isShadowedKey, d as safeOwnHas, a as safeOwnRead, e as consumerHas, f as spreadConsumerRecord, g as copyConsumerArray, r as readConsumerIndex, b as safeAssign, h as consumerKeys, j as readConsumerProp, k as diffAndApply, p as pickDefined, s as structuralSnapshot, n as normalizeNumericOption, l as DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS, m as consumerSymbolKeys, o as applyChangedKeys, R as RESERVED_KEY_PREFIX, q as DEFAULT_MAX_RECURSION_DEPTH, c as callConsumerFn, t as ANONYMOUS_WIZARD_KEY_PREFIX } from './attaform.8mfKZCwH.mjs';
6
- import { i as isPathPrefix, e as canonicalizePath, k as keyForSegments, m as mapSegmentKeys, b as ROOT_PATH_KEY, s as segmentsForPathKey, S as SubmitErrorHandlerError, t as toError, j as groupErrorsByKey, n as normalizeErrorInput, h as SET_MEMBER_SEGMENT, R as ROOT_PATH, l as normalizeErrorInputs, a as InvalidUseFormConfigError, d as ReservedFormKeyError } from './attaform.CdZIEf7_.mjs';
5
+ import { A as ANONYMOUS_FORM_KEY_PREFIX, d as diffAndApply, i as isBarePatch, p as pickDefined, s as structuralSnapshot, n as normalizeNumericOption, a as DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS, b as isDescendable, c as applyChangedKeys, R as RESERVED_KEY_PREFIX, e as DEFAULT_MAX_RECURSION_DEPTH, f as ANONYMOUS_WIZARD_KEY_PREFIX } from './attaform.BPSqtU7a.mjs';
6
+ import { e as canonicalizePath, i as isPathPrefix, f as pathsEqual, k as keyForSegments, m as mapSegmentKeys, b as ROOT_PATH_KEY, s as segmentsForPathKey, S as SubmitErrorHandlerError, t as toError, j as groupErrorsByKey, n as normalizeErrorInput, h as SET_MEMBER_SEGMENT, R as ROOT_PATH, l as normalizeErrorInputs, a as InvalidUseFormConfigError, d as ReservedFormKeyError } from './attaform.BhtAZysa.mjs';
7
+ import { i as isShadowedKey, e as safeOwnHas, a as safeOwnRead, f as consumerHas, g as spreadConsumerRecord, h as copyConsumerArray, r as readConsumerIndex, s as safeAssign, c as consumerKeys, b as readConsumerProp, d as callConsumerFn, j as consumerSymbolKeys } from './attaform._1Zp3mDG.mjs';
7
8
 
8
9
  const AttaformErrorCode = {
9
10
  /** A required field is in the blank set: no value was supplied. */
@@ -142,7 +143,7 @@ function hashStableString(input, seed = 0) {
142
143
  const ANON_STEM = "atta";
143
144
  function readableFormKeyStem(formKey) {
144
145
  if (formKey === "" || formKey.startsWith(ANONYMOUS_FORM_KEY_PREFIX)) return ANON_STEM;
145
- const sanitized = formKey.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|(?<!-)-+$/g, "");
146
+ const sanitized = formKey.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|([^-])-+$/g, "$1");
146
147
  return sanitized === "" ? ANON_STEM : sanitized;
147
148
  }
148
149
  function fieldIdToken(formInstanceId, pathKey) {
@@ -646,6 +647,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
646
647
  let asyncPending = false;
647
648
  const submissionAttempts = state.submissionAttempts.value;
648
649
  const blurredLeafSegments = [];
650
+ const errorsByKey = errorBucketsAt(state, segments, key);
649
651
  const descendantLeaves = [];
650
652
  visitActiveLeafPaths(value, segments, (leafSegments) => {
651
653
  const { key: leafKey } = keyForSegments(leafSegments);
@@ -655,6 +657,8 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
655
657
  });
656
658
  for (const { key: leafKey, segments: leafSeg } of descendantLeaves) {
657
659
  const leafRecord = state.fields.get(leafKey);
660
+ const leafErrors = errorsByKey.get(leafKey);
661
+ if (leafErrors !== void 0) leafErrors.walked = true;
658
662
  if (!state.isPristineAtPathByKey(leafKey, leafSeg)) {
659
663
  pristine = false;
660
664
  dirty = true;
@@ -689,22 +693,28 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
689
693
  if (updatedAt === null || ts > updatedAt) updatedAt = ts;
690
694
  }
691
695
  }
692
- if (!dirty && state.hasStructuralChangeUnder(segments)) {
696
+ if (!dirty && !(Array.isArray(value) || isPlainRecord(value)) && !state.isPristineAtPathByKey(key, segments)) {
693
697
  pristine = false;
694
698
  dirty = true;
695
699
  }
696
- if (!dirty && state.hasRemovedSubtreeUnder(segments)) {
700
+ if (!dirty && state.hasStructuralChangeUnder(segments, key)) {
697
701
  pristine = false;
698
702
  dirty = true;
699
703
  }
700
- const errors = aggregateErrorsAt(state, segments, key);
701
- const revealedDescendantError = errors.length > 0 && errors.some((e) => {
702
- const ePath = e.path;
703
- if (ePath.length === segments.length && ePath.every((s, i) => s === segments[i])) return false;
704
- if (submissionAttempts > 0) return true;
705
- if (ePath.length === 1 && ePath[0] === "") return blurredAfterInteraction;
706
- return blurredLeafSegments.some((s) => isPathPrefix(ePath, s));
707
- });
704
+ if (!dirty && state.hasRemovedSubtreeUnder(segments, key)) {
705
+ pristine = false;
706
+ dirty = true;
707
+ }
708
+ const errorBuckets = sortErrorBuckets(errorsByKey);
709
+ const errors = flattenErrorBuckets(errorBuckets);
710
+ const revealedDescendantError = errors.length > 0 && descendantErrorRevealed(
711
+ state,
712
+ segments,
713
+ errorBuckets,
714
+ submissionAttempts,
715
+ blurredAfterInteraction,
716
+ blurredLeafSegments
717
+ );
708
718
  if (!asyncPending && state.pathHasAsyncValidationByKey(key, segments)) asyncPending = true;
709
719
  if ((state.fieldValidationCounts.get(key) ?? 0) > 0) {
710
720
  validating = true;
@@ -726,6 +736,8 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
726
736
  if (ownRecord.interacted === true) interacted = true;
727
737
  if (ownRecord.blurredAfterInteraction === true) blurredAfterInteraction = true;
728
738
  if (ownRecord.connected === true) connected = true;
739
+ const ts = ownRecord.updatedAt;
740
+ if (ts !== null && (updatedAt === null || ts > updatedAt)) updatedAt = ts;
729
741
  }
730
742
  const ownTransformError = state.transformErrors.get(key) ?? null;
731
743
  const gated = asyncPending && !state.firstValidationDone.value;
@@ -817,9 +829,41 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
817
829
  firstOwnError
818
830
  };
819
831
  }
832
+ function descendantErrorRevealed(state, segments, buckets, submissionAttempts, blurredAfterInteraction, blurredLeafSegments) {
833
+ for (const bucket of buckets) {
834
+ let ownHistory;
835
+ for (const e of bucket.errors) {
836
+ const ePath = e.path;
837
+ if (pathsEqual(ePath, segments)) continue;
838
+ if (submissionAttempts > 0) return true;
839
+ if (ePath.length === 1 && ePath[0] === "") {
840
+ if (blurredAfterInteraction) return true;
841
+ continue;
842
+ }
843
+ for (const leaf of blurredLeafSegments) if (isPathPrefix(ePath, leaf)) return true;
844
+ if (bucket.walked) continue;
845
+ ownHistory ?? (ownHistory = state.fields.get(bucket.key)?.blurredAfterInteraction === true);
846
+ if (ownHistory) return true;
847
+ }
848
+ }
849
+ return false;
850
+ }
820
851
  function aggregateErrorsAt(state, prefix, prefixKey) {
852
+ return flattenErrorBuckets(sortErrorBuckets(errorBucketsAt(state, prefix, prefixKey)));
853
+ }
854
+ const NO_ERROR_BUCKETS = /* @__PURE__ */ new Map();
855
+ function sortErrorBuckets(buckets) {
856
+ if (buckets.size <= 1) return [...buckets.values()];
857
+ return [...buckets.values()].sort((a, b) => a.ordinal - b.ordinal);
858
+ }
859
+ function flattenErrorBuckets(buckets) {
860
+ if (buckets.length === 0) return [];
861
+ if (buckets.length === 1) return buckets[0]?.errors ?? [];
862
+ return buckets.flatMap((bucket) => bucket.errors);
863
+ }
864
+ function errorBucketsAt(state, prefix, prefixKey) {
821
865
  const candidates = state.errorWindowAt(prefix, prefixKey);
822
- if (candidates.length === 0) return [];
866
+ if (candidates.length === 0) return NO_ERROR_BUCKETS;
823
867
  const formValue = state.form.value;
824
868
  const cells = state.errorCells();
825
869
  const buckets = /* @__PURE__ */ new Map();
@@ -832,19 +876,16 @@ function aggregateErrorsAt(state, prefix, prefixKey) {
832
876
  const userList = cell?.user;
833
877
  const total = (schemaList?.length ?? 0) + (blankList?.length ?? 0) + (userList?.length ?? 0);
834
878
  if (total === 0) continue;
835
- const ordinal = state.ensurePathOrdinal(key);
836
- let bucket = buckets.get(ordinal);
879
+ let bucket = buckets.get(key);
837
880
  if (bucket === void 0) {
838
- bucket = [];
839
- buckets.set(ordinal, bucket);
881
+ bucket = { key, ordinal: state.ensurePathOrdinal(key), errors: [], walked: false };
882
+ buckets.set(key, bucket);
840
883
  }
841
- if (schemaList !== void 0) bucket.push(...schemaList);
842
- if (blankList !== void 0) bucket.push(...blankList);
843
- if (userList !== void 0) bucket.push(...userList);
884
+ if (schemaList !== void 0) bucket.errors.push(...schemaList);
885
+ if (blankList !== void 0) bucket.errors.push(...blankList);
886
+ if (userList !== void 0) bucket.errors.push(...userList);
844
887
  }
845
- if (buckets.size === 0) return [];
846
- if (buckets.size === 1) return [...buckets.values()][0];
847
- return [...buckets.entries()].sort(([a], [b]) => a - b).flatMap(([, errs]) => errs);
888
+ return buckets;
848
889
  }
849
890
  const EMPTY_ELEMENTS = Object.freeze([]);
850
891
 
@@ -876,7 +917,7 @@ function liveContainerHasKey(state, segments, key) {
876
917
  return Number.isInteger(index) && index >= 0 && String(index) === key && value.has(index);
877
918
  }
878
919
  if (value instanceof Set) return false;
879
- return Object.hasOwn(value, key);
920
+ return safeOwnHas(value, key);
880
921
  }
881
922
  function isArrayPath(state, segments) {
882
923
  if (segments.length === 0) return false;
@@ -1534,7 +1575,7 @@ function deleteKeysAtIndices(keys, del, arrayPath, indices) {
1534
1575
  del(hit.key);
1535
1576
  }
1536
1577
  }
1537
- function createArrayIdentity(getArrayLength) {
1578
+ function createArrayIdentity(getArrayLength, onChange) {
1538
1579
  const tokens = /* @__PURE__ */ new Map();
1539
1580
  const baselines = /* @__PURE__ */ new Map();
1540
1581
  let counter = 0;
@@ -1546,7 +1587,13 @@ function createArrayIdentity(getArrayLength) {
1546
1587
  ids = [];
1547
1588
  tokens.set(arrayKey, ids);
1548
1589
  }
1549
- while (ids.length < expectedLen) ids.push(allocate());
1590
+ if (ids.length < expectedLen) {
1591
+ const baseline = baselines.get(arrayKey);
1592
+ while (ids.length < expectedLen) {
1593
+ const anchored = baseline?.[ids.length];
1594
+ ids.push(anchored !== void 0 && !ids.includes(anchored) ? anchored : allocate());
1595
+ }
1596
+ }
1550
1597
  if (ids.length > expectedLen) ids.length = expectedLen;
1551
1598
  if (firstTrack) baselines.set(arrayKey, [...ids]);
1552
1599
  return ids;
@@ -1572,15 +1619,39 @@ function createArrayIdentity(getArrayLength) {
1572
1619
  const arrayKey = canonicalizePath(arraySegs).key;
1573
1620
  const ids = ensure(arrayKey, remap.oldLen);
1574
1621
  tokens.set(arrayKey, permuteList(ids, remap, allocate));
1622
+ onChange([arraySegs]);
1575
1623
  },
1576
1624
  applyRemap(arrayPath, remap) {
1577
1625
  if (remap.moved.size === 0 && remap.vacated.size === 0 && remap.fresh.size === 0) return;
1578
- migrateMapSubtree(tokens, arrayPath, remap, (value) => value);
1626
+ const moved = [];
1627
+ for (const hit of collectKeysAtIndices(tokens.keys(), arrayPath, remapAffects(remap))) {
1628
+ moved.push(hit.segments);
1629
+ }
1630
+ migrateMapSubtree(tokens, arrayPath, remap, (value, segments) => {
1631
+ moved.push(segments);
1632
+ return value;
1633
+ });
1579
1634
  migrateMapSubtree(baselines, arrayPath, remap, (value) => value);
1635
+ if (moved.length > 0) onChange(moved);
1580
1636
  },
1581
1637
  realign(arraySegs) {
1582
1638
  ensure(canonicalizePath(arraySegs).key, getArrayLength(arraySegs));
1583
1639
  },
1640
+ realignContaining(paths) {
1641
+ if (tokens.size === 0 || paths.length === 0) return;
1642
+ const resized = [];
1643
+ for (const [arrayKey, ids] of tokens) {
1644
+ const segs = segmentsForPathKey(arrayKey);
1645
+ if (segs === null || !paths.some((path) => isPathPrefix(segs, path) || isPathPrefix(path, segs))) {
1646
+ continue;
1647
+ }
1648
+ const len = getArrayLength(segs);
1649
+ if (ids.length === len) continue;
1650
+ ensure(arrayKey, len);
1651
+ resized.push(segs);
1652
+ }
1653
+ if (resized.length > 0) onChange(resized);
1654
+ },
1584
1655
  hasStructuralChangeUnder(prefix) {
1585
1656
  for (const arrayKey of tokens.keys()) {
1586
1657
  if (orderPristineForKey(arrayKey)) continue;
@@ -1591,15 +1662,39 @@ function createArrayIdentity(getArrayLength) {
1591
1662
  return false;
1592
1663
  },
1593
1664
  rebaselineAll() {
1665
+ const rebased = [];
1594
1666
  for (const arrayKey of [...tokens.keys()]) {
1595
1667
  const segs = segmentsForPathKey(arrayKey);
1596
1668
  if (segs === null) continue;
1597
1669
  const ids = ensure(arrayKey, getArrayLength(segs));
1598
1670
  baselines.set(arrayKey, [...ids]);
1671
+ rebased.push(segs);
1599
1672
  }
1673
+ if (rebased.length > 0) onChange(rebased);
1674
+ },
1675
+ snapshot() {
1676
+ return { tokens: copyLists(tokens), baselines: copyLists(baselines) };
1677
+ },
1678
+ restore(orders) {
1679
+ const keys = /* @__PURE__ */ new Set([...tokens.keys(), ...orders.tokens.keys()]);
1680
+ tokens.clear();
1681
+ for (const [key, ids] of orders.tokens) tokens.set(key, [...ids]);
1682
+ baselines.clear();
1683
+ for (const [key, ids] of orders.baselines) baselines.set(key, [...ids]);
1684
+ const restored = [];
1685
+ for (const key of keys) {
1686
+ const segs = segmentsForPathKey(key);
1687
+ if (segs !== null) restored.push(segs);
1688
+ }
1689
+ if (restored.length > 0) onChange(restored);
1600
1690
  }
1601
1691
  };
1602
1692
  }
1693
+ function copyLists(lists) {
1694
+ const out = /* @__PURE__ */ new Map();
1695
+ for (const [key, ids] of lists) out.set(key, [...ids]);
1696
+ return out;
1697
+ }
1603
1698
  function createVariantMemory() {
1604
1699
  const memory = /* @__PURE__ */ new Map();
1605
1700
  return {
@@ -1666,6 +1761,8 @@ function createArrayBookkeeping(deps) {
1666
1761
  blankPaths,
1667
1762
  originalBlankPaths,
1668
1763
  authoredPaths,
1764
+ removedPaths,
1765
+ notifyStructure,
1669
1766
  fieldValidationCounts,
1670
1767
  fieldValidatingSince,
1671
1768
  fieldValidationState,
@@ -1673,10 +1770,35 @@ function createArrayBookkeeping(deps) {
1673
1770
  arrayIdentity,
1674
1771
  variantMemory,
1675
1772
  touchFieldRecord,
1773
+ stampContainers,
1774
+ stampBareContainers,
1775
+ foldInteractionHistory,
1676
1776
  decFieldValidation
1677
1777
  } = deps;
1678
1778
  function migrateElementState(arrayPath, remap) {
1679
1779
  if (remap.moved.size === 0 && remap.vacated.size === 0) return;
1780
+ migrateSetSubtree(originalBlankPaths, arrayPath, remap);
1781
+ migrateSetSubtree(authoredPaths, arrayPath, remap);
1782
+ const removedMoved = [];
1783
+ for (const hit of collectKeysAtIndices(removedPaths.keys(), arrayPath, remapAffects(remap))) {
1784
+ removedMoved.push(hit.segments);
1785
+ }
1786
+ migrateMapSubtree(removedPaths, arrayPath, remap, (_, segments) => {
1787
+ removedMoved.push(segments);
1788
+ return segments;
1789
+ });
1790
+ if (remap.vacated.size > 0) {
1791
+ const released = [];
1792
+ for (const { key } of collectKeysAtIndices(
1793
+ fields.keys(),
1794
+ arrayPath,
1795
+ (index) => remap.vacated.has(index)
1796
+ )) {
1797
+ const record = fields.get(key);
1798
+ if (record !== void 0) released.push(record);
1799
+ }
1800
+ foldInteractionHistory(arrayPath, released);
1801
+ }
1680
1802
  migrateMapSubtree(fields, arrayPath, remap, (record, segments) => ({
1681
1803
  ...record,
1682
1804
  path: segments
@@ -1690,21 +1812,37 @@ function createArrayBookkeeping(deps) {
1690
1812
  value: record.value
1691
1813
  }));
1692
1814
  migrateSetSubtree(blankPaths, arrayPath, remap);
1693
- migrateSetSubtree(originalBlankPaths, arrayPath, remap);
1694
- migrateSetSubtree(authoredPaths, arrayPath, remap);
1695
1815
  migrateMapSubtree(fieldValidatingSince, arrayPath, remap, (since) => since);
1696
1816
  migrateMapSubtree(fieldValidationCounts, arrayPath, remap, (count) => count);
1817
+ migrateMapSubtree(fieldValidationState, arrayPath, remap, (entry, segments) => {
1818
+ entry.key = keyForSegments(segments).key;
1819
+ entry.path = segments;
1820
+ return entry;
1821
+ });
1697
1822
  arrayIdentity.applyRemap(arrayPath, remap);
1823
+ if (removedMoved.length > 0) notifyStructure(removedMoved);
1698
1824
  }
1699
- function seedFreshElement(arrayPath, freshIndex) {
1825
+ function seedFreshElement(arrayPath, freshIndex, now) {
1700
1826
  const elementPath = [...arrayPath, freshIndex];
1701
- const now = (/* @__PURE__ */ new Date()).toISOString();
1827
+ const patches = [];
1702
1828
  diffAndApply(void 0, getAtPath(form.value, elementPath), elementPath, (patch) => {
1829
+ patches.push(patch);
1830
+ });
1831
+ const bare = [];
1832
+ patches.forEach((patch, index) => {
1703
1833
  if (patch.kind !== "added") return;
1704
- const { key } = canonicalizePath(patch.path);
1834
+ if (isBarePatch(patch)) {
1835
+ bare.push(index);
1836
+ return;
1837
+ }
1838
+ const { key, segments } = canonicalizePath(patch.path);
1705
1839
  if (!originals.has(key)) originals.set(key, { segments: patch.path, value: void 0 });
1706
- touchFieldRecord(key, patch.path, { updatedAt: now });
1840
+ touchFieldRecord(key, segments, { updatedAt: now });
1707
1841
  });
1842
+ if (bare.length > 0) stampBareContainers(patches, bare, now);
1843
+ else if (patches.length === 0 && hasAtPath(form.value, elementPath)) {
1844
+ stampContainers([elementPath], now);
1845
+ }
1708
1846
  }
1709
1847
  function abortValidationAtVacatedIndices(arrayPath, remap) {
1710
1848
  if (remap.vacated.size === 0) return;
@@ -1718,21 +1856,22 @@ function createArrayBookkeeping(deps) {
1718
1856
  if (entry === void 0) continue;
1719
1857
  if (entry.timer !== null) {
1720
1858
  clearTimeout(entry.timer);
1721
- } else if (!entry.settled) {
1859
+ } else if (!entry.settled && !entry.released) {
1722
1860
  activeValidations.value = Math.max(0, activeValidations.value - 1);
1723
1861
  decFieldValidation(hit.key);
1862
+ entry.released = true;
1724
1863
  }
1725
1864
  entry.aborted = true;
1726
1865
  fieldValidationState.delete(hit.key);
1727
1866
  }
1728
1867
  }
1729
1868
  return {
1730
- applyStructuralOp(arrayPath, remap) {
1869
+ applyStructuralOp(arrayPath, remap, now) {
1870
+ abortValidationAtVacatedIndices(arrayPath, remap);
1731
1871
  migrateElementState(arrayPath, remap);
1732
- for (const freshIndex of remap.fresh) seedFreshElement(arrayPath, freshIndex);
1872
+ for (const freshIndex of remap.fresh) seedFreshElement(arrayPath, freshIndex, now);
1733
1873
  const changed = changedIndices(remap);
1734
1874
  evictSchemaVerdictsAtIndices(errorCells(), arrayPath, changed);
1735
- abortValidationAtVacatedIndices(arrayPath, remap);
1736
1875
  variantMemory.dropAtIndices(arrayPath, changed);
1737
1876
  arrayIdentity.applyOp(arrayPath, remap);
1738
1877
  }
@@ -2461,12 +2600,12 @@ function isPrimitiveOrEmpty(value) {
2461
2600
  return t === "string" || t === "number" || t === "boolean" || t === "bigint";
2462
2601
  }
2463
2602
  function isSlimNumericPrimitive(value) {
2464
- return value === 0 || value === 0n;
2603
+ return value === 0 || typeof value === "bigint" && !value;
2465
2604
  }
2466
2605
  function blankForKind(slimDefault) {
2467
2606
  if (typeof slimDefault === "string") return "";
2468
2607
  if (typeof slimDefault === "number") return 0;
2469
- if (typeof slimDefault === "bigint") return 0n;
2608
+ if (typeof slimDefault === "bigint") return typeof BigInt === "function" ? BigInt(0) : void 0;
2470
2609
  if (typeof slimDefault === "boolean") return false;
2471
2610
  if (slimDefault === null) return null;
2472
2611
  return void 0;
@@ -2835,7 +2974,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2835
2974
  };
2836
2975
  const metaTarget = buildMetaProxy(META_KEYS, (key) => {
2837
2976
  if (key === "errorCount") return metaErrors.value.length;
2838
- if (Object.hasOwn(metaOwn, key)) return metaOwn[key];
2977
+ if (safeOwnHas(metaOwn, key)) return metaOwn[key];
2839
2978
  return rootFieldState.value[key];
2840
2979
  });
2841
2980
  const formMeta = readonly(reactive(metaTarget));
@@ -2850,8 +2989,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
2850
2989
  );
2851
2990
  state.reset(walked.cleanedValues);
2852
2991
  for (const pathKey of walked.paths) {
2853
- state.blankPaths.add(pathKey);
2854
2992
  state.originalBlankPaths.add(pathKey);
2993
+ state.blankPaths.add(pathKey);
2855
2994
  }
2856
2995
  }
2857
2996
  };
@@ -3304,16 +3443,15 @@ function appendHydrationFailedEntry(st, error) {
3304
3443
  return entry;
3305
3444
  }
3306
3445
 
3307
- const isContainer = (value) => Array.isArray(value) || isPlainRecord(value);
3308
3446
  function isHydratedFieldRecord(value) {
3309
3447
  if (typeof value !== "object" || value === null) return false;
3310
3448
  const r = value;
3311
3449
  return Array.isArray(r.path) && (typeof r.updatedAt === "string" || r.updatedAt === null) && typeof r.connected === "boolean" && (typeof r.focused === "boolean" || r.focused === null) && (typeof r.blurred === "boolean" || r.blurred === null) && typeof r.touched === "boolean" && typeof r.interacted === "boolean" && typeof r.blurredAfterInteraction === "boolean";
3312
3450
  }
3313
- function withClearedHistoryFlags(record, now) {
3451
+ function withClearedHistoryFlags(record, updatedAt) {
3314
3452
  return {
3315
3453
  path: record.path,
3316
- updatedAt: now,
3454
+ updatedAt,
3317
3455
  connected: record.connected,
3318
3456
  focused: record.focused,
3319
3457
  blurred: record.blurred,
@@ -3428,14 +3566,27 @@ function initialFirstValidationGate(schema) {
3428
3566
  return schema.needsAsyncValidation?.() !== true;
3429
3567
  }
3430
3568
  function seedOriginalsFromBaseline(st, baseline) {
3431
- st.originals.clear();
3569
+ const seeded = /* @__PURE__ */ new Map();
3432
3570
  diffAndApply({}, baseline, [], (patch) => {
3433
- if (patch.kind !== "added") return;
3434
- st.originals.set(canonicalizePath(patch.path).key, {
3435
- segments: patch.path,
3436
- value: patch.newValue
3437
- });
3571
+ if (patch.kind === "added") seedBaseline(seeded, canonicalizePath(patch.path).key, patch);
3438
3572
  });
3573
+ replaceOriginals(st, seeded);
3574
+ }
3575
+ function replaceOriginals(st, next) {
3576
+ for (const [key, entry] of next) st.originals.set(key, entry);
3577
+ for (const key of [...toRaw(st.originals).keys()]) {
3578
+ if (!next.has(key)) st.originals.delete(key);
3579
+ }
3580
+ }
3581
+ function seedBaseline(originals, key, patch) {
3582
+ const value = patch.newValue;
3583
+ if (!isDescendable(value)) {
3584
+ originals.set(key, { segments: patch.path, value });
3585
+ return false;
3586
+ }
3587
+ if (!(value instanceof Map))
3588
+ originals.set(key, { segments: patch.path, value: Array.isArray(value) ? [] : {} });
3589
+ return true;
3439
3590
  }
3440
3591
  function queueInitialAsyncValidation(st) {
3441
3592
  if (!st.ssr && st.schema.needsAsyncValidation?.() === true) {
@@ -3597,8 +3748,18 @@ function settleTransforms(st, path) {
3597
3748
  st.transformWaiters.push({ key, resolve });
3598
3749
  });
3599
3750
  }
3751
+ function writeInstant(st) {
3752
+ const clock = (/* @__PURE__ */ new Date()).toISOString();
3753
+ if (clock > st.latestStamp) return clock;
3754
+ const after = new Date(new Date(st.latestStamp).getTime() + 1);
3755
+ return Number.isFinite(after.getTime()) ? after.toISOString() : clock;
3756
+ }
3757
+ function noteStamp(st, stamp) {
3758
+ if (stamp !== null && stamp > st.latestStamp) st.latestStamp = stamp;
3759
+ }
3600
3760
  function touchFieldRecord(st, pathKey, path, patch) {
3601
3761
  const current = st.fields.get(pathKey);
3762
+ if (patch.updatedAt !== void 0) noteStamp(st, patch.updatedAt);
3602
3763
  st.fields.set(pathKey, {
3603
3764
  path,
3604
3765
  updatedAt: patch.updatedAt ?? current?.updatedAt ?? null,
@@ -3617,19 +3778,188 @@ function touchFieldRecord(st, pathKey, path, patch) {
3617
3778
  blurredAfterInteraction: patch.blurredAfterInteraction ?? current?.blurredAfterInteraction ?? false
3618
3779
  });
3619
3780
  }
3620
- function commitWritePatches(st, patches, meta) {
3621
- const now = (/* @__PURE__ */ new Date()).toISOString();
3781
+ function stampContainers(st, containers, now) {
3782
+ eachAncestorOnce(containers, (key, segments) => raiseStamp(st, key, segments, now));
3783
+ }
3784
+ function raiseStamp(st, key, segments, stamp) {
3785
+ if ((st.fields.get(key)?.updatedAt ?? "") < stamp) {
3786
+ touchFieldRecord(st, key, segments, { updatedAt: stamp });
3787
+ }
3788
+ }
3789
+ function holdRemovedStamps(st, patches, next) {
3790
+ const held = /* @__PURE__ */ new Map();
3791
+ const hold = (path, depth, leaf) => noteHold(st, held, next, path, depth, leaf);
3622
3792
  for (const patch of patches) {
3623
- const { key } = canonicalizePath(patch.path);
3624
- if (!st.originals.has(key)) {
3793
+ if (patch.kind === "added") continue;
3794
+ const { oldValue, path } = patch;
3795
+ if (Array.isArray(oldValue) || isPlainRecord(oldValue)) {
3796
+ if (patch.kind === "changed") {
3797
+ visitActiveLeafPaths(oldValue, path, (leaf) => hold(path, path.length, leaf));
3798
+ }
3799
+ } else if (patch.kind === "removed" ? !hasAtPath(next, path) : Array.isArray(patch.newValue) || isPlainRecord(patch.newValue)) {
3800
+ hold(path, path.length - 1, path);
3801
+ }
3802
+ }
3803
+ applyHolds(st, held);
3804
+ }
3805
+ function noteHold(st, held, next, path, depth, leaf) {
3806
+ const { key: leafKey } = keyForSegments(leaf);
3807
+ const stamp = toRaw(st.originals).has(leafKey) ? toRaw(st.fields).get(leafKey)?.updatedAt : null;
3808
+ if (stamp === null || stamp === void 0) return;
3809
+ let kept = false;
3810
+ for (let at = depth; at >= 0; at--) {
3811
+ const segments = path.slice(0, at);
3812
+ if (!kept && !hasAtPath(next, segments)) continue;
3813
+ kept = true;
3814
+ const { key } = keyForSegments(segments);
3815
+ const current = held.get(key);
3816
+ if (current === void 0) held.set(key, { segments, stamp });
3817
+ else if (stamp > current.stamp) current.stamp = stamp;
3818
+ }
3819
+ }
3820
+ function applyHolds(st, held) {
3821
+ for (const [key, { segments, stamp }] of held) raiseStamp(st, key, segments, stamp);
3822
+ }
3823
+ function stampBareContainers(st, patches, bare, now) {
3824
+ for (const index of bare) {
3825
+ const path = patches[index]?.path ?? [];
3826
+ for (let depth = path.length; depth >= 0; depth--) {
3827
+ const container = path.slice(0, depth);
3828
+ if (depth < path.length && reachedBesides(patches, index, container)) break;
3829
+ const { key, segments } = keyForSegments(container);
3830
+ raiseStamp(st, key, segments, now);
3831
+ }
3832
+ }
3833
+ }
3834
+ function reachedBesides(patches, index, container) {
3835
+ for (const step of [-1, 1]) {
3836
+ for (let i = index + step; ; i += step) {
3837
+ const patch = patches[i];
3838
+ if (patch === void 0 || !isPathPrefix(container, patch.path)) break;
3839
+ if (!isBarePatch(patch)) return true;
3840
+ }
3841
+ }
3842
+ return false;
3843
+ }
3844
+ function eachAncestorOnce(paths, visit) {
3845
+ const seen = /* @__PURE__ */ new Set();
3846
+ for (const path of paths) {
3847
+ for (let depth = path.length; depth >= 0; depth--) {
3848
+ const { key, segments } = keyForSegments(path.slice(0, depth));
3849
+ if (seen.has(key)) break;
3850
+ seen.add(key);
3851
+ visit(key, segments);
3852
+ }
3853
+ }
3854
+ }
3855
+ function foldInteractionHistory(st, path, released) {
3856
+ let touched = false;
3857
+ let interacted = false;
3858
+ let blurredAfterInteraction = false;
3859
+ for (const record of released) {
3860
+ touched || (touched = record.touched);
3861
+ interacted || (interacted = record.interacted);
3862
+ blurredAfterInteraction || (blurredAfterInteraction = record.blurredAfterInteraction);
3863
+ }
3864
+ if (!touched && !interacted && !blurredAfterInteraction) return;
3865
+ for (let depth = path.length; depth >= 0; depth--) {
3866
+ const { key, segments } = keyForSegments(path.slice(0, depth));
3867
+ const current = st.fields.get(key);
3868
+ touchFieldRecord(st, key, segments, {
3869
+ touched: touched || current?.touched === true,
3870
+ interacted: interacted || current?.interacted === true,
3871
+ blurredAfterInteraction: blurredAfterInteraction || current?.blurredAfterInteraction === true
3872
+ });
3873
+ }
3874
+ }
3875
+ function releaseRemovedRecords(st, segments, raw) {
3876
+ const released = [];
3877
+ let depth = segments.length;
3878
+ do {
3879
+ const { key } = keyForSegments(segments.slice(0, depth));
3880
+ abortValidationAt(st, key);
3881
+ const record = st.fields.get(key);
3882
+ if (record !== void 0) {
3883
+ released.push(record);
3884
+ if (record.connected) st.fields.set(key, withClearedHistoryFlags(record, null));
3885
+ else st.fields.delete(key);
3886
+ }
3887
+ depth--;
3888
+ } while (depth > 0 && !hasAtPath(raw, segments.slice(0, depth)));
3889
+ const present = segments.slice(0, depth);
3890
+ foldInteractionHistory(st, present, released);
3891
+ return present;
3892
+ }
3893
+ function noteRemovedBaseline(st, key, segments, notify) {
3894
+ if (st.originals.get(key)?.value === void 0) return;
3895
+ st.removedPaths.set(key, segments);
3896
+ notify.push(segments);
3897
+ }
3898
+ function trackForSweep(st, path, key) {
3899
+ st.pathSweep.track(path, key);
3900
+ for (let i = 1; i < path.length; i++) {
3901
+ const ancestor = path.slice(0, i);
3902
+ st.pathSweep.track(ancestor, canonicalizePath(ancestor).key);
3903
+ }
3904
+ }
3905
+ function commitWritePatches(st, patches, meta, structuralOp, now) {
3906
+ const arrayOpPath = structuralOp?.path;
3907
+ const reshaped = [];
3908
+ const removed = [];
3909
+ const resizing = [];
3910
+ const raw = toRaw(st.form.value);
3911
+ const bareAt = [];
3912
+ for (const [index, patch] of patches.entries()) {
3913
+ const { key, segments } = canonicalizePath(patch.path);
3914
+ const bare = isBarePatch(patch);
3915
+ if (!bare && !st.originals.has(key)) {
3625
3916
  st.originals.set(key, { segments: patch.path, value: void 0 });
3626
3917
  }
3627
- touchFieldRecord(st, key, patch.path, { updatedAt: now });
3628
- st.pathSweep.track(patch.path, key);
3629
- for (let i = 1; i < patch.path.length; i++) {
3630
- const ancestor = patch.path.slice(0, i);
3631
- st.pathSweep.track(ancestor, canonicalizePath(ancestor).key);
3918
+ const positional = arrayOpPath !== void 0 && segments.length > arrayOpPath.length && isPathPrefix(arrayOpPath, segments);
3919
+ if (structuralOp === null && (patch.kind !== "changed" || typeof patch.oldValue === "object" || typeof patch.newValue === "object")) {
3920
+ resizing.push(segments);
3921
+ }
3922
+ if (!positional) {
3923
+ if (patch.kind === "removed" && !hasAtPath(raw, segments)) {
3924
+ reshaped.push(releaseRemovedRecords(st, segments, raw));
3925
+ noteRemovedBaseline(st, key, segments, removed);
3926
+ } else {
3927
+ touchFieldRecord(st, key, segments, { updatedAt: now });
3928
+ if (bare) bareAt.push(index);
3929
+ if (patch.kind === "changed" && typeof patch.oldValue === "object" && patch.oldValue !== null) {
3930
+ diffAndApply(patch.oldValue, void 0, segments, (gone) => {
3931
+ if (!hasAtPath(raw, gone.path)) {
3932
+ reshaped.push(releaseRemovedRecords(st, gone.path, raw));
3933
+ const goneAt = canonicalizePath(gone.path);
3934
+ noteRemovedBaseline(st, goneAt.key, goneAt.segments, removed);
3935
+ }
3936
+ });
3937
+ }
3938
+ if (patch.kind === "changed" && isDescendable(patch.newValue)) {
3939
+ diffAndApply(void 0, patch.newValue, segments, (fresh) => {
3940
+ const at = canonicalizePath(fresh.path);
3941
+ trackForSweep(st, fresh.path, at.key);
3942
+ if (fresh.kind === "added" && isDescendable(fresh.newValue)) {
3943
+ reshaped.push(at.segments);
3944
+ return;
3945
+ }
3946
+ if (!st.originals.has(at.key)) {
3947
+ st.originals.set(at.key, { segments: fresh.path, value: void 0 });
3948
+ }
3949
+ touchFieldRecord(st, at.key, at.segments, { updatedAt: now });
3950
+ });
3951
+ }
3952
+ }
3632
3953
  }
3954
+ trackForSweep(st, patch.path, key);
3955
+ }
3956
+ if (arrayOpPath !== void 0 && patches.length > 0) reshaped.push(arrayOpPath);
3957
+ if (reshaped.length > 0) stampContainers(st, reshaped, now);
3958
+ if (bareAt.length > 0) stampBareContainers(st, patches, bareAt, now);
3959
+ if (removed.length > 0) pulseStructure(st.structureSignal, removed);
3960
+ if (resizing.length > 0) st.arrayIdentity.realignContaining(resizing);
3961
+ if (structuralOp !== null) {
3962
+ st.arrayBookkeeping.applyStructuralOp(structuralOp.path, structuralOp.remap, now);
3633
3963
  }
3634
3964
  for (const listener of st.formChangeListeners) {
3635
3965
  try {
@@ -3639,33 +3969,39 @@ function commitWritePatches(st, patches, meta) {
3639
3969
  }
3640
3970
  }
3641
3971
  }
3642
- function applyFormReplacementWithPath(st, next, meta, arrayOpPath) {
3972
+ function applyFormReplacementWithPath(st, next, meta, structuralOp, now) {
3643
3973
  const prev = st.form.value;
3644
3974
  if (Object.is(prev, next)) return;
3645
3975
  const patches = [];
3646
3976
  diffAndApply(prev, next, [], (patch) => {
3647
3977
  patches.push(patch);
3648
3978
  });
3649
- if (!applyChangedKeys(prev, next, arrayOpPath, [], patches)) {
3979
+ holdRemovedStamps(st, patches, next);
3980
+ const reconciled = callConsumerFn(
3981
+ () => applyChangedKeys(prev, next, structuralOp?.path ?? null, [], patches),
3982
+ null);
3983
+ if (reconciled === null) return;
3984
+ if (!reconciled) {
3650
3985
  st.form.value = next;
3651
3986
  } else if (patches.some(
3652
3987
  (p) => p.path.length > 0 && typeof p.path[0] === "string" && isShadowedKey(p.path[0])
3653
3988
  )) {
3654
3989
  triggerRef(st.form);
3655
3990
  }
3656
- commitWritePatches(st, patches, meta);
3991
+ commitWritePatches(st, patches, meta, structuralOp, now);
3657
3992
  }
3658
3993
  function applyFormReplacement(st, next, meta) {
3659
- applyFormReplacementWithPath(st, next, meta, null);
3994
+ applyFormReplacementWithPath(st, next, meta, null, writeInstant(st));
3660
3995
  }
3661
- function applyTargetedWrite(st, path, completedValue, meta) {
3996
+ function applyTargetedWrite(st, path, completedValue, meta, structuralOp, now) {
3662
3997
  const result = tryInPlaceLeafWrite(st.form.value, path, completedValue);
3663
3998
  if (!result.applied) {
3664
3999
  applyFormReplacementWithPath(
3665
4000
  st,
3666
4001
  setAtPathWithSchemaFill(st.form.value, st.schema, path, completedValue),
3667
4002
  meta,
3668
- meta?.arrayOp !== void 0 ? path : null
4003
+ structuralOp,
4004
+ now
3669
4005
  );
3670
4006
  return;
3671
4007
  }
@@ -3673,9 +4009,9 @@ function applyTargetedWrite(st, path, completedValue, meta) {
3673
4009
  diffAndApply(result.old, completedValue, path, (patch) => {
3674
4010
  patches.push(patch);
3675
4011
  });
3676
- commitWritePatches(st, patches, meta);
4012
+ commitWritePatches(st, patches, meta, null, now);
3677
4013
  }
3678
- function setValueAtPath(st, path, value, meta) {
4014
+ function setValueAtPath(st, path, value, meta, writeStamp) {
3679
4015
  if (st.effectiveDisabled.value) {
3680
4016
  return false;
3681
4017
  }
@@ -3748,7 +4084,8 @@ function setValueAtPath(st, path, value, meta) {
3748
4084
  value,
3749
4085
  variantDefault,
3750
4086
  void 0,
3751
- meta
4087
+ meta,
4088
+ writeStamp
3752
4089
  );
3753
4090
  }
3754
4091
  return reshapeUnionVariant(
@@ -3758,7 +4095,8 @@ function setValueAtPath(st, path, value, meta) {
3758
4095
  value,
3759
4096
  { [last]: value },
3760
4097
  void 0,
3761
- meta
4098
+ meta,
4099
+ writeStamp
3762
4100
  );
3763
4101
  }
3764
4102
  }
@@ -3782,7 +4120,8 @@ function setValueAtPath(st, path, value, meta) {
3782
4120
  discValue,
3783
4121
  variantDefault,
3784
4122
  valueRecord,
3785
- meta
4123
+ meta,
4124
+ writeStamp
3786
4125
  );
3787
4126
  }
3788
4127
  return reshapeUnionVariant(
@@ -3792,10 +4131,20 @@ function setValueAtPath(st, path, value, meta) {
3792
4131
  discValue,
3793
4132
  { [discKey]: discValue },
3794
4133
  void 0,
3795
- meta
4134
+ meta,
4135
+ writeStamp
3796
4136
  );
3797
4137
  }
3798
- return reshapeUnionVariant(st, path, oldDiscValue, void 0, {}, void 0, meta);
4138
+ return reshapeUnionVariant(
4139
+ st,
4140
+ path,
4141
+ oldDiscValue,
4142
+ void 0,
4143
+ {},
4144
+ void 0,
4145
+ meta,
4146
+ writeStamp
4147
+ );
3799
4148
  }
3800
4149
  }
3801
4150
  }
@@ -3845,16 +4194,17 @@ function setValueAtPath(st, path, value, meta) {
3845
4194
  if (arrayOpRemap === null && Array.isArray(value) && Array.isArray(currentValue)) {
3846
4195
  st.arrayIdentity.realign(path);
3847
4196
  }
3848
- applyTargetedWrite(st, path, completedValue, meta);
3849
- if (arrayOpRemap !== null) {
3850
- st.arrayBookkeeping.applyStructuralOp(path, arrayOpRemap);
3851
- } else if (Array.isArray(value) && Array.isArray(currentValue)) {
4197
+ const now = writeStamp ?? writeInstant(st);
4198
+ applyTargetedWrite(
4199
+ st,
4200
+ path,
4201
+ completedValue,
4202
+ meta,
4203
+ arrayOpRemap !== null ? { path, remap: arrayOpRemap } : null,
4204
+ now
4205
+ );
4206
+ if (arrayOpRemap === null && Array.isArray(value) && Array.isArray(currentValue)) {
3852
4207
  st.variantMemory.clearUnderPath(path);
3853
- st.arrayIdentity.realign(path);
3854
- } else if (isContainer(currentValue) && !isContainer(value)) {
3855
- if (subtreeHadRealBaseline(st, path, currentValue)) {
3856
- st.removedSubtrees.add(pathKey);
3857
- }
3858
4208
  }
3859
4209
  const effectiveModeAfterWrite = meta?.instance?.validateOn ?? st.fieldValidationMode;
3860
4210
  if (effectiveModeAfterWrite === "change") {
@@ -3862,7 +4212,7 @@ function setValueAtPath(st, path, value, meta) {
3862
4212
  }
3863
4213
  return true;
3864
4214
  }
3865
- function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variantDefault, consumerOverrides, meta) {
4215
+ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variantDefault, consumerOverrides, meta, writeStamp) {
3866
4216
  const sameDisc = Object.is(oldDiscValue, newDiscValue);
3867
4217
  const parentKey = canonicalizePath(parentPath).key;
3868
4218
  let baseline = variantDefault;
@@ -3928,7 +4278,7 @@ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variant
3928
4278
  appliedSync = true;
3929
4279
  }
3930
4280
  }
3931
- applyFormReplacement(st, nextForm, meta);
4281
+ applyFormReplacementWithPath(st, nextForm, meta, null, writeStamp ?? writeInstant(st));
3932
4282
  for (const k of newBlankPaths) st.blankPaths.add(k);
3933
4283
  if (reshapeMode === "change" && !appliedSync) {
3934
4284
  scheduleFieldValidation(st, parentPath, false, meta?.instance);
@@ -3949,7 +4299,9 @@ function scheduleFieldValidation(st, path, immediate, instance) {
3949
4299
  aborted: false,
3950
4300
  timer: null,
3951
4301
  settled: false,
3952
- released: false
4302
+ released: false,
4303
+ key,
4304
+ path
3953
4305
  };
3954
4306
  st.fieldValidationState.set(key, fresh);
3955
4307
  const myEpoch = ++st.scheduleEpoch;
@@ -3960,19 +4312,20 @@ function scheduleFieldValidation(st, path, immediate, instance) {
3960
4312
  try {
3961
4313
  st.activeValidations.value += 1;
3962
4314
  activeIncremented = true;
3963
- incFieldValidation(st, key);
4315
+ incFieldValidation(st, fresh.key);
3964
4316
  } catch (err) {
3965
4317
  if (activeIncremented) {
3966
4318
  st.activeValidations.value = Math.max(0, st.activeValidations.value - 1);
3967
4319
  }
3968
4320
  throw err;
3969
4321
  }
3970
- const subtreeScope = path.length > 0 && st.schema.hasContainerOrRootRefine?.() === false;
3971
- const scopePath = subtreeScope ? path : void 0;
3972
- const dataAtScope = subtreeScope ? getAtPath(st.form.value, path) : st.form.value;
3973
- const scopeKey = subtreeScope ? canonicalizePath(path).key : ROOT_PATH_KEY;
3974
- void Promise.resolve().then(() => st.schema.validateAtPath(dataAtScope, scopePath)).then((response) => {
4322
+ const startPath = fresh.path;
4323
+ const subtreeScope = startPath.length > 0 && st.schema.hasContainerOrRootRefine?.() === false;
4324
+ const dataAtScope = subtreeScope ? getAtPath(st.form.value, startPath) : st.form.value;
4325
+ void Promise.resolve().then(() => st.schema.validateAtPath(dataAtScope, subtreeScope ? startPath : void 0)).then((response) => {
3975
4326
  if (fresh.aborted) return;
4327
+ const scopePath = subtreeScope ? fresh.path : void 0;
4328
+ const scopeKey = subtreeScope ? fresh.key : ROOT_PATH_KEY;
3976
4329
  if (myEpoch <= st.lastCommittedEpoch) return;
3977
4330
  st.lastCommittedEpoch = myEpoch;
3978
4331
  if (effectiveMode === "blur") {
@@ -3983,14 +4336,14 @@ function scheduleFieldValidation(st, path, immediate, instance) {
3983
4336
  const filtered = filterAuthoredErrors(st, errors);
3984
4337
  const restamped = subtreeScope ? filtered.map((err) => ({
3985
4338
  ...err,
3986
- path: [...path, ...err.path]
4339
+ path: [...scopePath ?? [], ...err.path]
3987
4340
  })) : filtered;
3988
4341
  applySchemaErrorsForSubtree(st, scopePath ?? [], restamped);
3989
4342
  }).catch(() => {
3990
4343
  }).finally(() => {
3991
4344
  if (!fresh.released) {
3992
4345
  st.activeValidations.value = Math.max(0, st.activeValidations.value - 1);
3993
- decFieldValidation(st, key);
4346
+ decFieldValidation(st, fresh.key);
3994
4347
  }
3995
4348
  fresh.settled = true;
3996
4349
  });
@@ -4029,6 +4382,19 @@ function cancelFieldValidationUnder(st, prefix) {
4029
4382
  st.fieldValidationState.delete(key);
4030
4383
  }
4031
4384
  }
4385
+ function abortValidationAt(st, key) {
4386
+ const entry = st.fieldValidationState.get(key);
4387
+ if (entry === void 0) return;
4388
+ if (entry.timer !== null) {
4389
+ clearTimeout(entry.timer);
4390
+ } else if (!entry.settled && !entry.released) {
4391
+ st.activeValidations.value = Math.max(0, st.activeValidations.value - 1);
4392
+ decFieldValidation(st, key);
4393
+ entry.released = true;
4394
+ }
4395
+ entry.aborted = true;
4396
+ st.fieldValidationState.delete(key);
4397
+ }
4032
4398
  function onFormChange(st, listener) {
4033
4399
  st.formChangeListeners.add(listener);
4034
4400
  return () => {
@@ -4156,6 +4522,36 @@ function restoreErrorCells(st, entries) {
4156
4522
  st.errorCells().set(key, { schema: [...cell.schema], user: [...cell.user] });
4157
4523
  }
4158
4524
  }
4525
+ function captureStructure(st) {
4526
+ return {
4527
+ identity: st.arrayIdentity.snapshot(),
4528
+ originals: [...toRaw(st.originals)],
4529
+ originalBlank: [...st.originalBlankPaths],
4530
+ removed: [...st.removedPaths]
4531
+ };
4532
+ }
4533
+ function restoreStructure(st, snapshot) {
4534
+ const originals = new Map(snapshot.originals);
4535
+ const raw = toRaw(st.form.value);
4536
+ const held = /* @__PURE__ */ new Map();
4537
+ for (const [key, { segments }] of toRaw(st.originals)) {
4538
+ if (!originals.has(key) && hasAtPath(raw, segments)) {
4539
+ noteHold(st, held, raw, segments, segments.length - 1, segments);
4540
+ }
4541
+ }
4542
+ applyHolds(st, held);
4543
+ st.arrayIdentity.restore(snapshot.identity);
4544
+ replaceOriginals(st, originals);
4545
+ st.originalBlankPaths.clear();
4546
+ for (const key of snapshot.originalBlank) st.originalBlankPaths.add(key);
4547
+ const pulsed = [...st.removedPaths.values()];
4548
+ st.removedPaths.clear();
4549
+ for (const [key, segments] of snapshot.removed) {
4550
+ st.removedPaths.set(key, segments);
4551
+ pulsed.push(segments);
4552
+ }
4553
+ if (pulsed.length > 0) pulseStructure(st.structureSignal, pulsed);
4554
+ }
4159
4555
  function getErrorsForPath(st, path) {
4160
4556
  const { key } = canonicalizePath(path);
4161
4557
  const cell = st.errorCells().get(key);
@@ -4180,6 +4576,7 @@ function noteDomConnected(st, path) {
4180
4576
  }
4181
4577
  function noteDomDisconnected(st, path) {
4182
4578
  const { key } = canonicalizePath(path);
4579
+ if (!st.fields.has(key)) return;
4183
4580
  touchFieldRecord(st, key, path, { connected: false, focused: null, blurred: null });
4184
4581
  }
4185
4582
  function markConnectedOptimistically(st, path) {
@@ -4242,7 +4639,7 @@ function markInteracted(st, path) {
4242
4639
  function touchAtPath(st, segments) {
4243
4640
  const formValue = st.form.value;
4244
4641
  for (const [leafKey, entry] of st.originals) {
4245
- if (!isPathPrefix(segments, entry.segments)) continue;
4642
+ if (!isPathPrefix(segments, entry.segments) || isDescendable(entry.value)) continue;
4246
4643
  if (!hasAtPath(formValue, entry.segments)) continue;
4247
4644
  const current = st.fields.get(leafKey);
4248
4645
  if (current?.touched === true) continue;
@@ -4254,7 +4651,7 @@ function interactAtPath(st, segments) {
4254
4651
  const formValue = st.form.value;
4255
4652
  let interactedAny = false;
4256
4653
  for (const [leafKey, entry] of st.originals) {
4257
- if (!isPathPrefix(segments, entry.segments)) continue;
4654
+ if (!isPathPrefix(segments, entry.segments) || isDescendable(entry.value)) continue;
4258
4655
  if (!hasAtPath(formValue, entry.segments)) continue;
4259
4656
  interactedAny = true;
4260
4657
  const current = st.fields.get(leafKey);
@@ -4330,15 +4727,20 @@ function reset(st, nextDefaultValues) {
4330
4727
  st.schema.getDefaultValues({ useDefaultSchemaValues: true })
4331
4728
  );
4332
4729
  rebuildAuthoredPaths(st, resetSource, next);
4333
- applyFormReplacement(st, next);
4334
- st.arrayIdentity.rebaselineAll();
4335
- st.removedSubtrees.clear();
4336
- seedOriginalsFromBaseline(st, next);
4337
4730
  if (nextDefaultValues !== void 0) {
4338
4731
  const mentioned = /* @__PURE__ */ new Set();
4339
4732
  walkAuthoredFromConstraints(nextDefaultValues, [], mentioned);
4340
4733
  for (const key of mentioned) st.originalBlankPaths.delete(key);
4341
4734
  }
4735
+ const now = writeInstant(st);
4736
+ applyFormReplacementWithPath(st, next, void 0, null, now);
4737
+ st.arrayIdentity.rebaselineAll();
4738
+ if (st.removedPaths.size > 0) {
4739
+ const cleared = [...st.removedPaths.values()];
4740
+ st.removedPaths.clear();
4741
+ pulseStructure(st.structureSignal, cleared);
4742
+ }
4743
+ seedOriginalsFromBaseline(st, next);
4342
4744
  st.blankPaths.clear();
4343
4745
  for (const key of st.originalBlankPaths) {
4344
4746
  st.blankPaths.add(key);
@@ -4347,7 +4749,7 @@ function reset(st, nextDefaultValues) {
4347
4749
  replaceErrorChannel(st, "schema", st.schema.validateSync(next));
4348
4750
  st.firstValidationDone.value = initialFirstValidationGate(st.schema);
4349
4751
  queueInitialAsyncValidation(st);
4350
- const now = (/* @__PURE__ */ new Date()).toISOString();
4752
+ noteStamp(st, now);
4351
4753
  for (const [pathKey, record] of st.fields) {
4352
4754
  st.fields.set(pathKey, withClearedHistoryFlags(record, now));
4353
4755
  }
@@ -4376,6 +4778,7 @@ function reset(st, nextDefaultValues) {
4376
4778
  }
4377
4779
  function resetField(st, path) {
4378
4780
  const { key: targetKey, segments: targetSegments } = canonicalizePath(path);
4781
+ const now = writeInstant(st);
4379
4782
  st.variantMemory.clearUnderPath(targetSegments);
4380
4783
  cancelFieldValidationUnder(st, targetSegments);
4381
4784
  cancelTransformsUnder(st, targetSegments);
@@ -4384,9 +4787,21 @@ function resetField(st, path) {
4384
4787
  if (segs === null) continue;
4385
4788
  if (isPathPrefix(targetSegments, segs)) st.pathSnapshots.delete(snapKey);
4386
4789
  }
4790
+ const cleared = [];
4791
+ for (const [fieldKey, record] of Array.from(st.fields.entries())) {
4792
+ if (!isPathPrefix(targetSegments, record.path)) continue;
4793
+ st.fields.set(fieldKey, withClearedHistoryFlags(record, record.updatedAt));
4794
+ cleared.push(fieldKey);
4795
+ }
4387
4796
  const leafEntry = st.originals.get(targetKey);
4388
4797
  if (leafEntry !== void 0) {
4389
- const wrote = setValueAtPath(st, targetSegments, leafEntry.value);
4798
+ const wrote = setValueAtPath(
4799
+ st,
4800
+ targetSegments,
4801
+ structuralSnapshot(leafEntry.value),
4802
+ void 0,
4803
+ now
4804
+ );
4390
4805
  if (!wrote) {
4391
4806
  console.error(
4392
4807
  `[attaform] AF11 attaform.dev/e/af11 '${targetKey}'`
@@ -4404,10 +4819,10 @@ function resetField(st, path) {
4404
4819
  if (subtree === void 0) {
4405
4820
  subtree = typeof relative[0] === "number" ? [] : {};
4406
4821
  }
4407
- subtree = setAtPath(subtree, relative, entry.value);
4822
+ subtree = setAtPath(subtree, relative, structuralSnapshot(entry.value));
4408
4823
  }
4409
4824
  if (anyMatch) {
4410
- const wroteSubtree = setValueAtPath(st, targetSegments, subtree);
4825
+ const wroteSubtree = setValueAtPath(st, targetSegments, subtree, void 0, now);
4411
4826
  if (!wroteSubtree) {
4412
4827
  console.error(
4413
4828
  `[attaform] AF12 attaform.dev/e/af12 '${targetKey}'`
@@ -4416,8 +4831,14 @@ function resetField(st, path) {
4416
4831
  }
4417
4832
  }
4418
4833
  deleteErrorCellsUnderPrefix(st, targetSegments);
4419
- for (const [fieldKey, record] of Array.from(st.fields.entries())) {
4420
- if (isPathPrefix(targetSegments, record.path)) clearFieldRecordFlags(st, fieldKey);
4834
+ const raw = toRaw(st.form.value);
4835
+ for (const fieldKey of cleared) {
4836
+ const record = st.fields.get(fieldKey);
4837
+ if (record === void 0 || !hasAtPath(raw, record.path)) continue;
4838
+ raiseStamp(st, fieldKey, record.path, now);
4839
+ }
4840
+ if (cleared.length > 0 && hasAtPath(raw, targetSegments)) {
4841
+ stampContainers(st, [targetSegments], now);
4421
4842
  }
4422
4843
  }
4423
4844
  function deleteErrorCellsUnderPrefix(st, prefix) {
@@ -4430,36 +4851,35 @@ function deleteErrorCellsUnderPrefix(st, prefix) {
4430
4851
  }
4431
4852
  }
4432
4853
  }
4433
- function clearFieldRecordFlags(st, pathKey) {
4434
- const record = st.fields.get(pathKey);
4435
- if (record === void 0) return;
4436
- st.fields.set(pathKey, withClearedHistoryFlags(record, (/* @__PURE__ */ new Date()).toISOString()));
4437
- }
4438
4854
  function isPristineAtPathByKey(st, key, segments) {
4439
4855
  if (st.blankPaths.has(key) !== st.originalBlankPaths.has(key)) return false;
4440
4856
  const entry = st.originals.get(key);
4441
4857
  if (entry === void 0) return true;
4442
4858
  return Object.is(getAtPath(st.form.value, segments), entry.value);
4443
4859
  }
4444
- function hasStructuralChangeUnder(st, path) {
4860
+ function hasStructuralChangeUnder(st, path, key) {
4861
+ subscribeStructure(st.structureSignal, key);
4445
4862
  return st.arrayIdentity.hasStructuralChangeUnder(path);
4446
4863
  }
4447
- function subtreeHadRealBaseline(st, prefix, removedValue) {
4448
- let had = false;
4449
- diffAndApply(removedValue, void 0, prefix, (patch) => {
4450
- if (had || patch.kind !== "removed") return;
4451
- const record = st.originals.get(canonicalizePath(patch.path).key);
4452
- if (record?.value !== void 0) had = true;
4864
+ function pulseStructure(signal, paths) {
4865
+ const keys = signal.keys;
4866
+ if (keys === null) return;
4867
+ eachAncestorOnce(paths, (key) => {
4868
+ keys.add(key);
4869
+ keys.delete(key);
4453
4870
  });
4454
- return had;
4455
4871
  }
4456
- function hasRemovedSubtreeUnder(st, prefix) {
4457
- if (st.removedSubtrees.size === 0) return false;
4458
- for (const key of st.removedSubtrees) {
4459
- const segments = segmentsForPathKey(key);
4460
- if (segments === null) continue;
4872
+ function subscribeStructure(signal, key) {
4873
+ signal.keys ?? (signal.keys = shallowReactive(/* @__PURE__ */ new Set()));
4874
+ void signal.keys.has(key);
4875
+ }
4876
+ function hasRemovedSubtreeUnder(st, prefix, key) {
4877
+ subscribeStructure(st.structureSignal, key);
4878
+ if (st.removedPaths.size === 0) return false;
4879
+ const raw = toRaw(st.form.value);
4880
+ for (const segments of st.removedPaths.values()) {
4461
4881
  if (!isPathPrefix(prefix, segments)) continue;
4462
- if (isContainer(getAtPath(toRaw(st.form.value), segments))) continue;
4882
+ if (hasAtPath(raw, segments)) continue;
4463
4883
  return true;
4464
4884
  }
4465
4885
  return false;
@@ -4495,10 +4915,14 @@ function createFormStore(options) {
4495
4915
  warn: true
4496
4916
  }) : initialData;
4497
4917
  const form = ref(stubbedInitialData);
4498
- const arrayIdentity = createArrayIdentity((arraySegs) => {
4499
- const v = getAtPath(toRaw(form.value), arraySegs);
4500
- return Array.isArray(v) ? v.length : 0;
4501
- });
4918
+ const structureSignal = { keys: null };
4919
+ const arrayIdentity = createArrayIdentity(
4920
+ (arraySegs) => {
4921
+ const v = getAtPath(toRaw(form.value), arraySegs);
4922
+ return Array.isArray(v) ? v.length : 0;
4923
+ },
4924
+ (arrayPaths) => pulseStructure(structureSignal, arrayPaths)
4925
+ );
4502
4926
  const fields = shallowReactive(/* @__PURE__ */ new Map());
4503
4927
  const domBinding = shallowRef(null);
4504
4928
  const errorStore = createErrorCells(
@@ -4507,7 +4931,7 @@ function createFormStore(options) {
4507
4931
  );
4508
4932
  const errorCells = () => errorStore(true);
4509
4933
  const originals = shallowReactive(/* @__PURE__ */ new Map());
4510
- const removedSubtrees = /* @__PURE__ */ new Set();
4934
+ const removedPaths = /* @__PURE__ */ new Map();
4511
4935
  const blankPaths = reactive(/* @__PURE__ */ new Set());
4512
4936
  const originalBlankPaths = /* @__PURE__ */ new Set();
4513
4937
  const seededBlankPaths = hydration !== void 0 ? (hydration.blankPaths ?? []).map((dotted) => canonicalizePath(dotted).key) : options.initialBlankPaths ?? [];
@@ -4608,6 +5032,8 @@ function createFormStore(options) {
4608
5032
  blankPaths,
4609
5033
  originalBlankPaths,
4610
5034
  authoredPaths,
5035
+ removedPaths,
5036
+ notifyStructure: (paths) => pulseStructure(structureSignal, paths),
4611
5037
  fieldValidationCounts,
4612
5038
  fieldValidatingSince,
4613
5039
  fieldValidationState,
@@ -4615,6 +5041,9 @@ function createFormStore(options) {
4615
5041
  arrayIdentity,
4616
5042
  variantMemory,
4617
5043
  touchFieldRecord: (pathKey, path, patch) => touchFieldRecord(st, pathKey, path, patch),
5044
+ stampContainers: (containers, now) => stampContainers(st, containers, now),
5045
+ stampBareContainers: (patches, bare, now) => stampBareContainers(st, patches, bare, now),
5046
+ foldInteractionHistory: (path, released) => foldInteractionHistory(st, path, released),
4618
5047
  decFieldValidation: (key) => decFieldValidation(st, key)
4619
5048
  });
4620
5049
  const bind = (fn) => (...args) => fn(st, ...args);
@@ -4678,7 +5107,8 @@ function createFormStore(options) {
4678
5107
  cleanupHooks,
4679
5108
  authoredPaths,
4680
5109
  arrayIdentity,
4681
- removedSubtrees,
5110
+ removedPaths,
5111
+ structureSignal,
4682
5112
  variantMemory,
4683
5113
  pathOrdinals,
4684
5114
  pathSnapshots,
@@ -4688,6 +5118,7 @@ function createFormStore(options) {
4688
5118
  arrayBookkeeping,
4689
5119
  skipErrorSeed: () => errorStore(false),
4690
5120
  nextOrdinal: 0,
5121
+ latestStamp: "",
4691
5122
  scheduleEpoch: 0,
4692
5123
  lastCommittedEpoch: 0,
4693
5124
  transformTokenSeq: 0,
@@ -4725,6 +5156,8 @@ function createFormStore(options) {
4725
5156
  ),
4726
5157
  clearUserErrors: (path) => clearErrorChannel(st, "user", path),
4727
5158
  restoreErrorCells: bind(restoreErrorCells),
5159
+ captureStructure: bind(captureStructure),
5160
+ restoreStructure: bind(restoreStructure),
4728
5161
  getErrorsForPath: bind(getErrorsForPath),
4729
5162
  ensurePathOrdinal: bind(ensurePathOrdinal),
4730
5163
  noteDomConnected: bind(noteDomConnected),
@@ -4758,7 +5191,7 @@ function createFormStore(options) {
4758
5191
  diffAndApply({}, schemaInitialData, [], (patch) => {
4759
5192
  if (patch.kind !== "added") return;
4760
5193
  const { key } = canonicalizePath(patch.path);
4761
- originals.set(key, { segments: patch.path, value: patch.newValue });
5194
+ if (seedBaseline(originals, key, patch)) return;
4762
5195
  ensurePathOrdinal(st, key);
4763
5196
  if (hydration === void 0) {
4764
5197
  fields.set(key, {
@@ -4773,12 +5206,14 @@ function createFormStore(options) {
4773
5206
  });
4774
5207
  }
4775
5208
  });
5209
+ if (fields.size > 0) noteStamp(st, initStamp);
4776
5210
  if (hydration !== void 0) {
4777
5211
  for (const [rawKey, record] of hydration.fields) {
4778
5212
  if (typeof rawKey !== "string" || !isHydratedFieldRecord(record)) {
4779
5213
  continue;
4780
5214
  }
4781
5215
  fields.set(rawKey, record);
5216
+ noteStamp(st, record.updatedAt);
4782
5217
  }
4783
5218
  for (const [rawKey, errs] of hydration.schemaErrors) {
4784
5219
  if (typeof rawKey !== "string" || !isHydratedValidationErrorArray(errs)) {
@@ -5282,7 +5717,7 @@ function buildWizardStatusesProxy(statuses) {
5282
5717
  // resolves to `undefined` (consistent with property-access).
5283
5718
  resolveCall: (arg) => statuses[String(arg)]?.value,
5284
5719
  ownKeys: () => Object.keys(statuses),
5285
- hasKey: (key) => Object.hasOwn(statuses, key)
5720
+ hasKey: (key) => safeOwnHas(statuses, key)
5286
5721
  });
5287
5722
  }
5288
5723