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,8 +1,9 @@
1
1
  import { computed, readonly, toRaw, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, nextTick, warn, reactive, shallowReactive, shallowRef, toValue, watch, triggerRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, effectScope, onBeforeMount, onBeforeUpdate, onMounted } from 'vue';
2
- 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 reportConsumerThrow, u as ANONYMOUS_WIZARD_KEY_PREFIX } from './attaform-dev.CZz4GYZ6.mjs';
3
- import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform-dev.B1q-x9R9.mjs';
4
- import { R as REGISTER_OWNER_MARKER, V as V_REGISTER_MARKER, d as armDomBinding, r as recordInheritedModifiers, w as withInheritedModifiers } from './attaform-dev.k5X47GMD.mjs';
5
- 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-dev.zlvDr0WB.mjs';
2
+ 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-dev.n6n00owJ.mjs';
3
+ import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform-dev.Bu6wgrA5.mjs';
4
+ import { R as REGISTER_OWNER_MARKER, V as V_REGISTER_MARKER, d as armDomBinding, r as recordInheritedModifiers, w as withInheritedModifiers } from './attaform-dev.Cbx0AiQF.mjs';
5
+ 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-dev.04aupFBW.mjs';
6
+ 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, k as reportConsumerThrow } from './attaform-dev.CwYTWyPX.mjs';
6
7
 
7
8
  const AttaformErrorCode = {
8
9
  /** A required field is in the blank set: no value was supplied. */
@@ -141,7 +142,7 @@ function hashStableString(input, seed = 0) {
141
142
  const ANON_STEM = "atta";
142
143
  function readableFormKeyStem(formKey) {
143
144
  if (formKey === "" || formKey.startsWith(ANONYMOUS_FORM_KEY_PREFIX)) return ANON_STEM;
144
- const sanitized = formKey.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|(?<!-)-+$/g, "");
145
+ const sanitized = formKey.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|([^-])-+$/g, "$1");
145
146
  return sanitized === "" ? ANON_STEM : sanitized;
146
147
  }
147
148
  function fieldIdToken(formInstanceId, pathKey) {
@@ -645,6 +646,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
645
646
  let asyncPending = false;
646
647
  const submissionAttempts = state.submissionAttempts.value;
647
648
  const blurredLeafSegments = [];
649
+ const errorsByKey = errorBucketsAt(state, segments, key);
648
650
  const descendantLeaves = [];
649
651
  visitActiveLeafPaths(value, segments, (leafSegments) => {
650
652
  const { key: leafKey } = keyForSegments(leafSegments);
@@ -654,6 +656,8 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
654
656
  });
655
657
  for (const { key: leafKey, segments: leafSeg } of descendantLeaves) {
656
658
  const leafRecord = state.fields.get(leafKey);
659
+ const leafErrors = errorsByKey.get(leafKey);
660
+ if (leafErrors !== void 0) leafErrors.walked = true;
657
661
  if (!state.isPristineAtPathByKey(leafKey, leafSeg)) {
658
662
  pristine = false;
659
663
  dirty = true;
@@ -688,22 +692,28 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
688
692
  if (updatedAt === null || ts > updatedAt) updatedAt = ts;
689
693
  }
690
694
  }
691
- if (!dirty && state.hasStructuralChangeUnder(segments)) {
695
+ if (!dirty && !(Array.isArray(value) || isPlainRecord(value)) && !state.isPristineAtPathByKey(key, segments)) {
692
696
  pristine = false;
693
697
  dirty = true;
694
698
  }
695
- if (!dirty && state.hasRemovedSubtreeUnder(segments)) {
699
+ if (!dirty && state.hasStructuralChangeUnder(segments, key)) {
696
700
  pristine = false;
697
701
  dirty = true;
698
702
  }
699
- const errors = aggregateErrorsAt(state, segments, key);
700
- const revealedDescendantError = errors.length > 0 && errors.some((e) => {
701
- const ePath = e.path;
702
- if (ePath.length === segments.length && ePath.every((s, i) => s === segments[i])) return false;
703
- if (submissionAttempts > 0) return true;
704
- if (ePath.length === 1 && ePath[0] === "") return blurredAfterInteraction;
705
- return blurredLeafSegments.some((s) => isPathPrefix(ePath, s));
706
- });
703
+ if (!dirty && state.hasRemovedSubtreeUnder(segments, key)) {
704
+ pristine = false;
705
+ dirty = true;
706
+ }
707
+ const errorBuckets = sortErrorBuckets(errorsByKey);
708
+ const errors = flattenErrorBuckets(errorBuckets);
709
+ const revealedDescendantError = errors.length > 0 && descendantErrorRevealed(
710
+ state,
711
+ segments,
712
+ errorBuckets,
713
+ submissionAttempts,
714
+ blurredAfterInteraction,
715
+ blurredLeafSegments
716
+ );
707
717
  if (!asyncPending && state.pathHasAsyncValidationByKey(key, segments)) asyncPending = true;
708
718
  if ((state.fieldValidationCounts.get(key) ?? 0) > 0) {
709
719
  validating = true;
@@ -725,6 +735,8 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
725
735
  if (ownRecord.interacted === true) interacted = true;
726
736
  if (ownRecord.blurredAfterInteraction === true) blurredAfterInteraction = true;
727
737
  if (ownRecord.connected === true) connected = true;
738
+ const ts = ownRecord.updatedAt;
739
+ if (ts !== null && (updatedAt === null || ts > updatedAt)) updatedAt = ts;
728
740
  }
729
741
  const ownTransformError = state.transformErrors.get(key) ?? null;
730
742
  const gated = asyncPending && !state.firstValidationDone.value;
@@ -816,9 +828,41 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
816
828
  firstOwnError
817
829
  };
818
830
  }
831
+ function descendantErrorRevealed(state, segments, buckets, submissionAttempts, blurredAfterInteraction, blurredLeafSegments) {
832
+ for (const bucket of buckets) {
833
+ let ownHistory;
834
+ for (const e of bucket.errors) {
835
+ const ePath = e.path;
836
+ if (pathsEqual(ePath, segments)) continue;
837
+ if (submissionAttempts > 0) return true;
838
+ if (ePath.length === 1 && ePath[0] === "") {
839
+ if (blurredAfterInteraction) return true;
840
+ continue;
841
+ }
842
+ for (const leaf of blurredLeafSegments) if (isPathPrefix(ePath, leaf)) return true;
843
+ if (bucket.walked) continue;
844
+ ownHistory ?? (ownHistory = state.fields.get(bucket.key)?.blurredAfterInteraction === true);
845
+ if (ownHistory) return true;
846
+ }
847
+ }
848
+ return false;
849
+ }
819
850
  function aggregateErrorsAt(state, prefix, prefixKey) {
851
+ return flattenErrorBuckets(sortErrorBuckets(errorBucketsAt(state, prefix, prefixKey)));
852
+ }
853
+ const NO_ERROR_BUCKETS = /* @__PURE__ */ new Map();
854
+ function sortErrorBuckets(buckets) {
855
+ if (buckets.size <= 1) return [...buckets.values()];
856
+ return [...buckets.values()].sort((a, b) => a.ordinal - b.ordinal);
857
+ }
858
+ function flattenErrorBuckets(buckets) {
859
+ if (buckets.length === 0) return [];
860
+ if (buckets.length === 1) return buckets[0]?.errors ?? [];
861
+ return buckets.flatMap((bucket) => bucket.errors);
862
+ }
863
+ function errorBucketsAt(state, prefix, prefixKey) {
820
864
  const candidates = state.errorWindowAt(prefix, prefixKey);
821
- if (candidates.length === 0) return [];
865
+ if (candidates.length === 0) return NO_ERROR_BUCKETS;
822
866
  const formValue = state.form.value;
823
867
  const cells = state.errorCells();
824
868
  const buckets = /* @__PURE__ */ new Map();
@@ -831,19 +875,16 @@ function aggregateErrorsAt(state, prefix, prefixKey) {
831
875
  const userList = cell?.user;
832
876
  const total = (schemaList?.length ?? 0) + (blankList?.length ?? 0) + (userList?.length ?? 0);
833
877
  if (total === 0) continue;
834
- const ordinal = state.ensurePathOrdinal(key);
835
- let bucket = buckets.get(ordinal);
878
+ let bucket = buckets.get(key);
836
879
  if (bucket === void 0) {
837
- bucket = [];
838
- buckets.set(ordinal, bucket);
880
+ bucket = { key, ordinal: state.ensurePathOrdinal(key), errors: [], walked: false };
881
+ buckets.set(key, bucket);
839
882
  }
840
- if (schemaList !== void 0) bucket.push(...schemaList);
841
- if (blankList !== void 0) bucket.push(...blankList);
842
- if (userList !== void 0) bucket.push(...userList);
883
+ if (schemaList !== void 0) bucket.errors.push(...schemaList);
884
+ if (blankList !== void 0) bucket.errors.push(...blankList);
885
+ if (userList !== void 0) bucket.errors.push(...userList);
843
886
  }
844
- if (buckets.size === 0) return [];
845
- if (buckets.size === 1) return [...buckets.values()][0];
846
- return [...buckets.entries()].sort(([a], [b]) => a - b).flatMap(([, errs]) => errs);
887
+ return buckets;
847
888
  }
848
889
  const EMPTY_ELEMENTS = Object.freeze([]);
849
890
 
@@ -875,7 +916,7 @@ function liveContainerHasKey(state, segments, key) {
875
916
  return Number.isInteger(index) && index >= 0 && String(index) === key && value.has(index);
876
917
  }
877
918
  if (value instanceof Set) return false;
878
- return Object.hasOwn(value, key);
919
+ return safeOwnHas(value, key);
879
920
  }
880
921
  function isArrayPath(state, segments) {
881
922
  if (segments.length === 0) return false;
@@ -1542,7 +1583,7 @@ function deleteKeysAtIndices(keys, del, arrayPath, indices) {
1542
1583
  del(hit.key);
1543
1584
  }
1544
1585
  }
1545
- function createArrayIdentity(getArrayLength) {
1586
+ function createArrayIdentity(getArrayLength, onChange) {
1546
1587
  const tokens = /* @__PURE__ */ new Map();
1547
1588
  const baselines = /* @__PURE__ */ new Map();
1548
1589
  let counter = 0;
@@ -1554,7 +1595,13 @@ function createArrayIdentity(getArrayLength) {
1554
1595
  ids = [];
1555
1596
  tokens.set(arrayKey, ids);
1556
1597
  }
1557
- while (ids.length < expectedLen) ids.push(allocate());
1598
+ if (ids.length < expectedLen) {
1599
+ const baseline = baselines.get(arrayKey);
1600
+ while (ids.length < expectedLen) {
1601
+ const anchored = baseline?.[ids.length];
1602
+ ids.push(anchored !== void 0 && !ids.includes(anchored) ? anchored : allocate());
1603
+ }
1604
+ }
1558
1605
  if (ids.length > expectedLen) ids.length = expectedLen;
1559
1606
  if (firstTrack) baselines.set(arrayKey, [...ids]);
1560
1607
  return ids;
@@ -1580,15 +1627,39 @@ function createArrayIdentity(getArrayLength) {
1580
1627
  const arrayKey = canonicalizePath(arraySegs).key;
1581
1628
  const ids = ensure(arrayKey, remap.oldLen);
1582
1629
  tokens.set(arrayKey, permuteList(ids, remap, allocate));
1630
+ onChange([arraySegs]);
1583
1631
  },
1584
1632
  applyRemap(arrayPath, remap) {
1585
1633
  if (remap.moved.size === 0 && remap.vacated.size === 0 && remap.fresh.size === 0) return;
1586
- migrateMapSubtree(tokens, arrayPath, remap, (value) => value);
1634
+ const moved = [];
1635
+ for (const hit of collectKeysAtIndices(tokens.keys(), arrayPath, remapAffects(remap))) {
1636
+ moved.push(hit.segments);
1637
+ }
1638
+ migrateMapSubtree(tokens, arrayPath, remap, (value, segments) => {
1639
+ moved.push(segments);
1640
+ return value;
1641
+ });
1587
1642
  migrateMapSubtree(baselines, arrayPath, remap, (value) => value);
1643
+ if (moved.length > 0) onChange(moved);
1588
1644
  },
1589
1645
  realign(arraySegs) {
1590
1646
  ensure(canonicalizePath(arraySegs).key, getArrayLength(arraySegs));
1591
1647
  },
1648
+ realignContaining(paths) {
1649
+ if (tokens.size === 0 || paths.length === 0) return;
1650
+ const resized = [];
1651
+ for (const [arrayKey, ids] of tokens) {
1652
+ const segs = segmentsForPathKey(arrayKey);
1653
+ if (segs === null || !paths.some((path) => isPathPrefix(segs, path) || isPathPrefix(path, segs))) {
1654
+ continue;
1655
+ }
1656
+ const len = getArrayLength(segs);
1657
+ if (ids.length === len) continue;
1658
+ ensure(arrayKey, len);
1659
+ resized.push(segs);
1660
+ }
1661
+ if (resized.length > 0) onChange(resized);
1662
+ },
1592
1663
  hasStructuralChangeUnder(prefix) {
1593
1664
  for (const arrayKey of tokens.keys()) {
1594
1665
  if (orderPristineForKey(arrayKey)) continue;
@@ -1599,15 +1670,39 @@ function createArrayIdentity(getArrayLength) {
1599
1670
  return false;
1600
1671
  },
1601
1672
  rebaselineAll() {
1673
+ const rebased = [];
1602
1674
  for (const arrayKey of [...tokens.keys()]) {
1603
1675
  const segs = segmentsForPathKey(arrayKey);
1604
1676
  if (segs === null) continue;
1605
1677
  const ids = ensure(arrayKey, getArrayLength(segs));
1606
1678
  baselines.set(arrayKey, [...ids]);
1679
+ rebased.push(segs);
1607
1680
  }
1681
+ if (rebased.length > 0) onChange(rebased);
1682
+ },
1683
+ snapshot() {
1684
+ return { tokens: copyLists(tokens), baselines: copyLists(baselines) };
1685
+ },
1686
+ restore(orders) {
1687
+ const keys = /* @__PURE__ */ new Set([...tokens.keys(), ...orders.tokens.keys()]);
1688
+ tokens.clear();
1689
+ for (const [key, ids] of orders.tokens) tokens.set(key, [...ids]);
1690
+ baselines.clear();
1691
+ for (const [key, ids] of orders.baselines) baselines.set(key, [...ids]);
1692
+ const restored = [];
1693
+ for (const key of keys) {
1694
+ const segs = segmentsForPathKey(key);
1695
+ if (segs !== null) restored.push(segs);
1696
+ }
1697
+ if (restored.length > 0) onChange(restored);
1608
1698
  }
1609
1699
  };
1610
1700
  }
1701
+ function copyLists(lists) {
1702
+ const out = /* @__PURE__ */ new Map();
1703
+ for (const [key, ids] of lists) out.set(key, [...ids]);
1704
+ return out;
1705
+ }
1611
1706
  function createVariantMemory() {
1612
1707
  const memory = /* @__PURE__ */ new Map();
1613
1708
  return {
@@ -1674,6 +1769,8 @@ function createArrayBookkeeping(deps) {
1674
1769
  blankPaths,
1675
1770
  originalBlankPaths,
1676
1771
  authoredPaths,
1772
+ removedPaths,
1773
+ notifyStructure,
1677
1774
  fieldValidationCounts,
1678
1775
  fieldValidatingSince,
1679
1776
  fieldValidationState,
@@ -1681,10 +1778,35 @@ function createArrayBookkeeping(deps) {
1681
1778
  arrayIdentity,
1682
1779
  variantMemory,
1683
1780
  touchFieldRecord,
1781
+ stampContainers,
1782
+ stampBareContainers,
1783
+ foldInteractionHistory,
1684
1784
  decFieldValidation
1685
1785
  } = deps;
1686
1786
  function migrateElementState(arrayPath, remap) {
1687
1787
  if (remap.moved.size === 0 && remap.vacated.size === 0) return;
1788
+ migrateSetSubtree(originalBlankPaths, arrayPath, remap);
1789
+ migrateSetSubtree(authoredPaths, arrayPath, remap);
1790
+ const removedMoved = [];
1791
+ for (const hit of collectKeysAtIndices(removedPaths.keys(), arrayPath, remapAffects(remap))) {
1792
+ removedMoved.push(hit.segments);
1793
+ }
1794
+ migrateMapSubtree(removedPaths, arrayPath, remap, (_, segments) => {
1795
+ removedMoved.push(segments);
1796
+ return segments;
1797
+ });
1798
+ if (remap.vacated.size > 0) {
1799
+ const released = [];
1800
+ for (const { key } of collectKeysAtIndices(
1801
+ fields.keys(),
1802
+ arrayPath,
1803
+ (index) => remap.vacated.has(index)
1804
+ )) {
1805
+ const record = fields.get(key);
1806
+ if (record !== void 0) released.push(record);
1807
+ }
1808
+ foldInteractionHistory(arrayPath, released);
1809
+ }
1688
1810
  migrateMapSubtree(fields, arrayPath, remap, (record, segments) => ({
1689
1811
  ...record,
1690
1812
  path: segments
@@ -1698,21 +1820,37 @@ function createArrayBookkeeping(deps) {
1698
1820
  value: record.value
1699
1821
  }));
1700
1822
  migrateSetSubtree(blankPaths, arrayPath, remap);
1701
- migrateSetSubtree(originalBlankPaths, arrayPath, remap);
1702
- migrateSetSubtree(authoredPaths, arrayPath, remap);
1703
1823
  migrateMapSubtree(fieldValidatingSince, arrayPath, remap, (since) => since);
1704
1824
  migrateMapSubtree(fieldValidationCounts, arrayPath, remap, (count) => count);
1825
+ migrateMapSubtree(fieldValidationState, arrayPath, remap, (entry, segments) => {
1826
+ entry.key = keyForSegments(segments).key;
1827
+ entry.path = segments;
1828
+ return entry;
1829
+ });
1705
1830
  arrayIdentity.applyRemap(arrayPath, remap);
1831
+ if (removedMoved.length > 0) notifyStructure(removedMoved);
1706
1832
  }
1707
- function seedFreshElement(arrayPath, freshIndex) {
1833
+ function seedFreshElement(arrayPath, freshIndex, now) {
1708
1834
  const elementPath = [...arrayPath, freshIndex];
1709
- const now = (/* @__PURE__ */ new Date()).toISOString();
1835
+ const patches = [];
1710
1836
  diffAndApply(void 0, getAtPath(form.value, elementPath), elementPath, (patch) => {
1837
+ patches.push(patch);
1838
+ });
1839
+ const bare = [];
1840
+ patches.forEach((patch, index) => {
1711
1841
  if (patch.kind !== "added") return;
1712
- const { key } = canonicalizePath(patch.path);
1842
+ if (isBarePatch(patch)) {
1843
+ bare.push(index);
1844
+ return;
1845
+ }
1846
+ const { key, segments } = canonicalizePath(patch.path);
1713
1847
  if (!originals.has(key)) originals.set(key, { segments: patch.path, value: void 0 });
1714
- touchFieldRecord(key, patch.path, { updatedAt: now });
1848
+ touchFieldRecord(key, segments, { updatedAt: now });
1715
1849
  });
1850
+ if (bare.length > 0) stampBareContainers(patches, bare, now);
1851
+ else if (patches.length === 0 && hasAtPath(form.value, elementPath)) {
1852
+ stampContainers([elementPath], now);
1853
+ }
1716
1854
  }
1717
1855
  function abortValidationAtVacatedIndices(arrayPath, remap) {
1718
1856
  if (remap.vacated.size === 0) return;
@@ -1726,21 +1864,22 @@ function createArrayBookkeeping(deps) {
1726
1864
  if (entry === void 0) continue;
1727
1865
  if (entry.timer !== null) {
1728
1866
  clearTimeout(entry.timer);
1729
- } else if (!entry.settled) {
1867
+ } else if (!entry.settled && !entry.released) {
1730
1868
  activeValidations.value = Math.max(0, activeValidations.value - 1);
1731
1869
  decFieldValidation(hit.key);
1870
+ entry.released = true;
1732
1871
  }
1733
1872
  entry.aborted = true;
1734
1873
  fieldValidationState.delete(hit.key);
1735
1874
  }
1736
1875
  }
1737
1876
  return {
1738
- applyStructuralOp(arrayPath, remap) {
1877
+ applyStructuralOp(arrayPath, remap, now) {
1878
+ abortValidationAtVacatedIndices(arrayPath, remap);
1739
1879
  migrateElementState(arrayPath, remap);
1740
- for (const freshIndex of remap.fresh) seedFreshElement(arrayPath, freshIndex);
1880
+ for (const freshIndex of remap.fresh) seedFreshElement(arrayPath, freshIndex, now);
1741
1881
  const changed = changedIndices(remap);
1742
1882
  evictSchemaVerdictsAtIndices(errorCells(), arrayPath, changed);
1743
- abortValidationAtVacatedIndices(arrayPath, remap);
1744
1883
  variantMemory.dropAtIndices(arrayPath, changed);
1745
1884
  arrayIdentity.applyOp(arrayPath, remap);
1746
1885
  }
@@ -2552,12 +2691,12 @@ function isPrimitiveOrEmpty(value) {
2552
2691
  return t === "string" || t === "number" || t === "boolean" || t === "bigint";
2553
2692
  }
2554
2693
  function isSlimNumericPrimitive(value) {
2555
- return value === 0 || value === 0n;
2694
+ return value === 0 || typeof value === "bigint" && !value;
2556
2695
  }
2557
2696
  function blankForKind(slimDefault) {
2558
2697
  if (typeof slimDefault === "string") return "";
2559
2698
  if (typeof slimDefault === "number") return 0;
2560
- if (typeof slimDefault === "bigint") return 0n;
2699
+ if (typeof slimDefault === "bigint") return typeof BigInt === "function" ? BigInt(0) : void 0;
2561
2700
  if (typeof slimDefault === "boolean") return false;
2562
2701
  if (slimDefault === null) return null;
2563
2702
  return void 0;
@@ -2926,7 +3065,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2926
3065
  };
2927
3066
  const metaTarget = buildMetaProxy(META_KEYS, (key) => {
2928
3067
  if (key === "errorCount") return metaErrors.value.length;
2929
- if (Object.hasOwn(metaOwn, key)) return metaOwn[key];
3068
+ if (safeOwnHas(metaOwn, key)) return metaOwn[key];
2930
3069
  return rootFieldState.value[key];
2931
3070
  });
2932
3071
  const formMeta = readonly(reactive(metaTarget));
@@ -2941,8 +3080,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
2941
3080
  );
2942
3081
  state.reset(walked.cleanedValues);
2943
3082
  for (const pathKey of walked.paths) {
2944
- state.blankPaths.add(pathKey);
2945
3083
  state.originalBlankPaths.add(pathKey);
3084
+ state.blankPaths.add(pathKey);
2946
3085
  }
2947
3086
  }
2948
3087
  };
@@ -3427,16 +3566,15 @@ function appendHydrationFailedEntry(st, error) {
3427
3566
  return entry;
3428
3567
  }
3429
3568
 
3430
- const isContainer = (value) => Array.isArray(value) || isPlainRecord(value);
3431
3569
  function isHydratedFieldRecord(value) {
3432
3570
  if (typeof value !== "object" || value === null) return false;
3433
3571
  const r = value;
3434
3572
  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";
3435
3573
  }
3436
- function withClearedHistoryFlags(record, now) {
3574
+ function withClearedHistoryFlags(record, updatedAt) {
3437
3575
  return {
3438
3576
  path: record.path,
3439
- updatedAt: now,
3577
+ updatedAt,
3440
3578
  connected: record.connected,
3441
3579
  focused: record.focused,
3442
3580
  blurred: record.blurred,
@@ -3485,7 +3623,7 @@ function walkDuStubs(schema, value, path, warned) {
3485
3623
  if (du !== void 0) {
3486
3624
  const discValue = rec[du.discriminatorKey];
3487
3625
  if (discValue !== void 0 && !du.isVariantSelected(discValue)) {
3488
- const isKindBlank = discValue === "" || discValue === 0 || discValue === 0n || discValue === false || discValue === null;
3626
+ const isKindBlank = discValue === "" || discValue === 0 || typeof discValue === "bigint" && !discValue || discValue === false || discValue === null;
3489
3627
  if (!isKindBlank && warned !== void 0 && true) {
3490
3628
  const dotted = path.map((s) => String(s)).join(".") || "(root)";
3491
3629
  const key = `${dotted}::${String(discValue)}`;
@@ -3567,14 +3705,27 @@ function initialFirstValidationGate(schema) {
3567
3705
  return schema.needsAsyncValidation?.() !== true;
3568
3706
  }
3569
3707
  function seedOriginalsFromBaseline(st, baseline) {
3570
- st.originals.clear();
3708
+ const seeded = /* @__PURE__ */ new Map();
3571
3709
  diffAndApply({}, baseline, [], (patch) => {
3572
- if (patch.kind !== "added") return;
3573
- st.originals.set(canonicalizePath(patch.path).key, {
3574
- segments: patch.path,
3575
- value: patch.newValue
3576
- });
3710
+ if (patch.kind === "added") seedBaseline(seeded, canonicalizePath(patch.path).key, patch);
3577
3711
  });
3712
+ replaceOriginals(st, seeded);
3713
+ }
3714
+ function replaceOriginals(st, next) {
3715
+ for (const [key, entry] of next) st.originals.set(key, entry);
3716
+ for (const key of [...toRaw(st.originals).keys()]) {
3717
+ if (!next.has(key)) st.originals.delete(key);
3718
+ }
3719
+ }
3720
+ function seedBaseline(originals, key, patch) {
3721
+ const value = patch.newValue;
3722
+ if (!isDescendable(value)) {
3723
+ originals.set(key, { segments: patch.path, value });
3724
+ return false;
3725
+ }
3726
+ if (!(value instanceof Map))
3727
+ originals.set(key, { segments: patch.path, value: Array.isArray(value) ? [] : {} });
3728
+ return true;
3578
3729
  }
3579
3730
  function queueInitialAsyncValidation(st) {
3580
3731
  if (!st.ssr && st.schema.needsAsyncValidation?.() === true) {
@@ -3736,8 +3887,18 @@ function settleTransforms(st, path) {
3736
3887
  st.transformWaiters.push({ key, resolve });
3737
3888
  });
3738
3889
  }
3890
+ function writeInstant(st) {
3891
+ const clock = (/* @__PURE__ */ new Date()).toISOString();
3892
+ if (clock > st.latestStamp) return clock;
3893
+ const after = new Date(new Date(st.latestStamp).getTime() + 1);
3894
+ return Number.isFinite(after.getTime()) ? after.toISOString() : clock;
3895
+ }
3896
+ function noteStamp(st, stamp) {
3897
+ if (stamp !== null && stamp > st.latestStamp) st.latestStamp = stamp;
3898
+ }
3739
3899
  function touchFieldRecord(st, pathKey, path, patch) {
3740
3900
  const current = st.fields.get(pathKey);
3901
+ if (patch.updatedAt !== void 0) noteStamp(st, patch.updatedAt);
3741
3902
  st.fields.set(pathKey, {
3742
3903
  path,
3743
3904
  updatedAt: patch.updatedAt ?? current?.updatedAt ?? null,
@@ -3756,19 +3917,188 @@ function touchFieldRecord(st, pathKey, path, patch) {
3756
3917
  blurredAfterInteraction: patch.blurredAfterInteraction ?? current?.blurredAfterInteraction ?? false
3757
3918
  });
3758
3919
  }
3759
- function commitWritePatches(st, patches, meta) {
3760
- const now = (/* @__PURE__ */ new Date()).toISOString();
3920
+ function stampContainers(st, containers, now) {
3921
+ eachAncestorOnce(containers, (key, segments) => raiseStamp(st, key, segments, now));
3922
+ }
3923
+ function raiseStamp(st, key, segments, stamp) {
3924
+ if ((st.fields.get(key)?.updatedAt ?? "") < stamp) {
3925
+ touchFieldRecord(st, key, segments, { updatedAt: stamp });
3926
+ }
3927
+ }
3928
+ function holdRemovedStamps(st, patches, next) {
3929
+ const held = /* @__PURE__ */ new Map();
3930
+ const hold = (path, depth, leaf) => noteHold(st, held, next, path, depth, leaf);
3761
3931
  for (const patch of patches) {
3762
- const { key } = canonicalizePath(patch.path);
3763
- if (!st.originals.has(key)) {
3932
+ if (patch.kind === "added") continue;
3933
+ const { oldValue, path } = patch;
3934
+ if (Array.isArray(oldValue) || isPlainRecord(oldValue)) {
3935
+ if (patch.kind === "changed") {
3936
+ visitActiveLeafPaths(oldValue, path, (leaf) => hold(path, path.length, leaf));
3937
+ }
3938
+ } else if (patch.kind === "removed" ? !hasAtPath(next, path) : Array.isArray(patch.newValue) || isPlainRecord(patch.newValue)) {
3939
+ hold(path, path.length - 1, path);
3940
+ }
3941
+ }
3942
+ applyHolds(st, held);
3943
+ }
3944
+ function noteHold(st, held, next, path, depth, leaf) {
3945
+ const { key: leafKey } = keyForSegments(leaf);
3946
+ const stamp = toRaw(st.originals).has(leafKey) ? toRaw(st.fields).get(leafKey)?.updatedAt : null;
3947
+ if (stamp === null || stamp === void 0) return;
3948
+ let kept = false;
3949
+ for (let at = depth; at >= 0; at--) {
3950
+ const segments = path.slice(0, at);
3951
+ if (!kept && !hasAtPath(next, segments)) continue;
3952
+ kept = true;
3953
+ const { key } = keyForSegments(segments);
3954
+ const current = held.get(key);
3955
+ if (current === void 0) held.set(key, { segments, stamp });
3956
+ else if (stamp > current.stamp) current.stamp = stamp;
3957
+ }
3958
+ }
3959
+ function applyHolds(st, held) {
3960
+ for (const [key, { segments, stamp }] of held) raiseStamp(st, key, segments, stamp);
3961
+ }
3962
+ function stampBareContainers(st, patches, bare, now) {
3963
+ for (const index of bare) {
3964
+ const path = patches[index]?.path ?? [];
3965
+ for (let depth = path.length; depth >= 0; depth--) {
3966
+ const container = path.slice(0, depth);
3967
+ if (depth < path.length && reachedBesides(patches, index, container)) break;
3968
+ const { key, segments } = keyForSegments(container);
3969
+ raiseStamp(st, key, segments, now);
3970
+ }
3971
+ }
3972
+ }
3973
+ function reachedBesides(patches, index, container) {
3974
+ for (const step of [-1, 1]) {
3975
+ for (let i = index + step; ; i += step) {
3976
+ const patch = patches[i];
3977
+ if (patch === void 0 || !isPathPrefix(container, patch.path)) break;
3978
+ if (!isBarePatch(patch)) return true;
3979
+ }
3980
+ }
3981
+ return false;
3982
+ }
3983
+ function eachAncestorOnce(paths, visit) {
3984
+ const seen = /* @__PURE__ */ new Set();
3985
+ for (const path of paths) {
3986
+ for (let depth = path.length; depth >= 0; depth--) {
3987
+ const { key, segments } = keyForSegments(path.slice(0, depth));
3988
+ if (seen.has(key)) break;
3989
+ seen.add(key);
3990
+ visit(key, segments);
3991
+ }
3992
+ }
3993
+ }
3994
+ function foldInteractionHistory(st, path, released) {
3995
+ let touched = false;
3996
+ let interacted = false;
3997
+ let blurredAfterInteraction = false;
3998
+ for (const record of released) {
3999
+ touched || (touched = record.touched);
4000
+ interacted || (interacted = record.interacted);
4001
+ blurredAfterInteraction || (blurredAfterInteraction = record.blurredAfterInteraction);
4002
+ }
4003
+ if (!touched && !interacted && !blurredAfterInteraction) return;
4004
+ for (let depth = path.length; depth >= 0; depth--) {
4005
+ const { key, segments } = keyForSegments(path.slice(0, depth));
4006
+ const current = st.fields.get(key);
4007
+ touchFieldRecord(st, key, segments, {
4008
+ touched: touched || current?.touched === true,
4009
+ interacted: interacted || current?.interacted === true,
4010
+ blurredAfterInteraction: blurredAfterInteraction || current?.blurredAfterInteraction === true
4011
+ });
4012
+ }
4013
+ }
4014
+ function releaseRemovedRecords(st, segments, raw) {
4015
+ const released = [];
4016
+ let depth = segments.length;
4017
+ do {
4018
+ const { key } = keyForSegments(segments.slice(0, depth));
4019
+ abortValidationAt(st, key);
4020
+ const record = st.fields.get(key);
4021
+ if (record !== void 0) {
4022
+ released.push(record);
4023
+ if (record.connected) st.fields.set(key, withClearedHistoryFlags(record, null));
4024
+ else st.fields.delete(key);
4025
+ }
4026
+ depth--;
4027
+ } while (depth > 0 && !hasAtPath(raw, segments.slice(0, depth)));
4028
+ const present = segments.slice(0, depth);
4029
+ foldInteractionHistory(st, present, released);
4030
+ return present;
4031
+ }
4032
+ function noteRemovedBaseline(st, key, segments, notify) {
4033
+ if (st.originals.get(key)?.value === void 0) return;
4034
+ st.removedPaths.set(key, segments);
4035
+ notify.push(segments);
4036
+ }
4037
+ function trackForSweep(st, path, key) {
4038
+ st.pathSweep.track(path, key);
4039
+ for (let i = 1; i < path.length; i++) {
4040
+ const ancestor = path.slice(0, i);
4041
+ st.pathSweep.track(ancestor, canonicalizePath(ancestor).key);
4042
+ }
4043
+ }
4044
+ function commitWritePatches(st, patches, meta, structuralOp, now) {
4045
+ const arrayOpPath = structuralOp?.path;
4046
+ const reshaped = [];
4047
+ const removed = [];
4048
+ const resizing = [];
4049
+ const raw = toRaw(st.form.value);
4050
+ const bareAt = [];
4051
+ for (const [index, patch] of patches.entries()) {
4052
+ const { key, segments } = canonicalizePath(patch.path);
4053
+ const bare = isBarePatch(patch);
4054
+ if (!bare && !st.originals.has(key)) {
3764
4055
  st.originals.set(key, { segments: patch.path, value: void 0 });
3765
4056
  }
3766
- touchFieldRecord(st, key, patch.path, { updatedAt: now });
3767
- st.pathSweep.track(patch.path, key);
3768
- for (let i = 1; i < patch.path.length; i++) {
3769
- const ancestor = patch.path.slice(0, i);
3770
- st.pathSweep.track(ancestor, canonicalizePath(ancestor).key);
4057
+ const positional = arrayOpPath !== void 0 && segments.length > arrayOpPath.length && isPathPrefix(arrayOpPath, segments);
4058
+ if (structuralOp === null && (patch.kind !== "changed" || typeof patch.oldValue === "object" || typeof patch.newValue === "object")) {
4059
+ resizing.push(segments);
4060
+ }
4061
+ if (!positional) {
4062
+ if (patch.kind === "removed" && !hasAtPath(raw, segments)) {
4063
+ reshaped.push(releaseRemovedRecords(st, segments, raw));
4064
+ noteRemovedBaseline(st, key, segments, removed);
4065
+ } else {
4066
+ touchFieldRecord(st, key, segments, { updatedAt: now });
4067
+ if (bare) bareAt.push(index);
4068
+ if (patch.kind === "changed" && typeof patch.oldValue === "object" && patch.oldValue !== null) {
4069
+ diffAndApply(patch.oldValue, void 0, segments, (gone) => {
4070
+ if (!hasAtPath(raw, gone.path)) {
4071
+ reshaped.push(releaseRemovedRecords(st, gone.path, raw));
4072
+ const goneAt = canonicalizePath(gone.path);
4073
+ noteRemovedBaseline(st, goneAt.key, goneAt.segments, removed);
4074
+ }
4075
+ });
4076
+ }
4077
+ if (patch.kind === "changed" && isDescendable(patch.newValue)) {
4078
+ diffAndApply(void 0, patch.newValue, segments, (fresh) => {
4079
+ const at = canonicalizePath(fresh.path);
4080
+ trackForSweep(st, fresh.path, at.key);
4081
+ if (fresh.kind === "added" && isDescendable(fresh.newValue)) {
4082
+ reshaped.push(at.segments);
4083
+ return;
4084
+ }
4085
+ if (!st.originals.has(at.key)) {
4086
+ st.originals.set(at.key, { segments: fresh.path, value: void 0 });
4087
+ }
4088
+ touchFieldRecord(st, at.key, at.segments, { updatedAt: now });
4089
+ });
4090
+ }
4091
+ }
3771
4092
  }
4093
+ trackForSweep(st, patch.path, key);
4094
+ }
4095
+ if (arrayOpPath !== void 0 && patches.length > 0) reshaped.push(arrayOpPath);
4096
+ if (reshaped.length > 0) stampContainers(st, reshaped, now);
4097
+ if (bareAt.length > 0) stampBareContainers(st, patches, bareAt, now);
4098
+ if (removed.length > 0) pulseStructure(st.structureSignal, removed);
4099
+ if (resizing.length > 0) st.arrayIdentity.realignContaining(resizing);
4100
+ if (structuralOp !== null) {
4101
+ st.arrayBookkeeping.applyStructuralOp(structuralOp.path, structuralOp.remap, now);
3772
4102
  }
3773
4103
  for (const listener of st.formChangeListeners) {
3774
4104
  try {
@@ -3778,33 +4108,41 @@ function commitWritePatches(st, patches, meta) {
3778
4108
  }
3779
4109
  }
3780
4110
  }
3781
- function applyFormReplacementWithPath(st, next, meta, arrayOpPath) {
4111
+ function applyFormReplacementWithPath(st, next, meta, structuralOp, now) {
3782
4112
  const prev = st.form.value;
3783
4113
  if (Object.is(prev, next)) return;
3784
4114
  const patches = [];
3785
4115
  diffAndApply(prev, next, [], (patch) => {
3786
4116
  patches.push(patch);
3787
4117
  });
3788
- if (!applyChangedKeys(prev, next, arrayOpPath, [], patches)) {
4118
+ holdRemovedStamps(st, patches, next);
4119
+ const reconciled = callConsumerFn(
4120
+ () => applyChangedKeys(prev, next, structuralOp?.path ?? null, [], patches),
4121
+ null,
4122
+ "stored-value"
4123
+ );
4124
+ if (reconciled === null) return;
4125
+ if (!reconciled) {
3789
4126
  st.form.value = next;
3790
4127
  } else if (patches.some(
3791
4128
  (p) => p.path.length > 0 && typeof p.path[0] === "string" && isShadowedKey(p.path[0])
3792
4129
  )) {
3793
4130
  triggerRef(st.form);
3794
4131
  }
3795
- commitWritePatches(st, patches, meta);
4132
+ commitWritePatches(st, patches, meta, structuralOp, now);
3796
4133
  }
3797
4134
  function applyFormReplacement(st, next, meta) {
3798
- applyFormReplacementWithPath(st, next, meta, null);
4135
+ applyFormReplacementWithPath(st, next, meta, null, writeInstant(st));
3799
4136
  }
3800
- function applyTargetedWrite(st, path, completedValue, meta) {
4137
+ function applyTargetedWrite(st, path, completedValue, meta, structuralOp, now) {
3801
4138
  const result = tryInPlaceLeafWrite(st.form.value, path, completedValue);
3802
4139
  if (!result.applied) {
3803
4140
  applyFormReplacementWithPath(
3804
4141
  st,
3805
4142
  setAtPathWithSchemaFill(st.form.value, st.schema, path, completedValue),
3806
4143
  meta,
3807
- meta?.arrayOp !== void 0 ? path : null
4144
+ structuralOp,
4145
+ now
3808
4146
  );
3809
4147
  return;
3810
4148
  }
@@ -3812,9 +4150,9 @@ function applyTargetedWrite(st, path, completedValue, meta) {
3812
4150
  diffAndApply(result.old, completedValue, path, (patch) => {
3813
4151
  patches.push(patch);
3814
4152
  });
3815
- commitWritePatches(st, patches, meta);
4153
+ commitWritePatches(st, patches, meta, null, now);
3816
4154
  }
3817
- function setValueAtPath(st, path, value, meta) {
4155
+ function setValueAtPath(st, path, value, meta, writeStamp) {
3818
4156
  if (st.effectiveDisabled.value) {
3819
4157
  if (!st.warnedDisabledWrite) {
3820
4158
  st.warnedDisabledWrite = true;
@@ -3893,7 +4231,8 @@ function setValueAtPath(st, path, value, meta) {
3893
4231
  value,
3894
4232
  variantDefault,
3895
4233
  void 0,
3896
- meta
4234
+ meta,
4235
+ writeStamp
3897
4236
  );
3898
4237
  }
3899
4238
  return reshapeUnionVariant(
@@ -3903,7 +4242,8 @@ function setValueAtPath(st, path, value, meta) {
3903
4242
  value,
3904
4243
  { [last]: value },
3905
4244
  void 0,
3906
- meta
4245
+ meta,
4246
+ writeStamp
3907
4247
  );
3908
4248
  }
3909
4249
  }
@@ -3927,7 +4267,8 @@ function setValueAtPath(st, path, value, meta) {
3927
4267
  discValue,
3928
4268
  variantDefault,
3929
4269
  valueRecord,
3930
- meta
4270
+ meta,
4271
+ writeStamp
3931
4272
  );
3932
4273
  }
3933
4274
  return reshapeUnionVariant(
@@ -3937,10 +4278,20 @@ function setValueAtPath(st, path, value, meta) {
3937
4278
  discValue,
3938
4279
  { [discKey]: discValue },
3939
4280
  void 0,
3940
- meta
4281
+ meta,
4282
+ writeStamp
3941
4283
  );
3942
4284
  }
3943
- return reshapeUnionVariant(st, path, oldDiscValue, void 0, {}, void 0, meta);
4285
+ return reshapeUnionVariant(
4286
+ st,
4287
+ path,
4288
+ oldDiscValue,
4289
+ void 0,
4290
+ {},
4291
+ void 0,
4292
+ meta,
4293
+ writeStamp
4294
+ );
3944
4295
  }
3945
4296
  }
3946
4297
  }
@@ -3990,16 +4341,17 @@ function setValueAtPath(st, path, value, meta) {
3990
4341
  if (arrayOpRemap === null && Array.isArray(value) && Array.isArray(currentValue)) {
3991
4342
  st.arrayIdentity.realign(path);
3992
4343
  }
3993
- applyTargetedWrite(st, path, completedValue, meta);
3994
- if (arrayOpRemap !== null) {
3995
- st.arrayBookkeeping.applyStructuralOp(path, arrayOpRemap);
3996
- } else if (Array.isArray(value) && Array.isArray(currentValue)) {
4344
+ const now = writeStamp ?? writeInstant(st);
4345
+ applyTargetedWrite(
4346
+ st,
4347
+ path,
4348
+ completedValue,
4349
+ meta,
4350
+ arrayOpRemap !== null ? { path, remap: arrayOpRemap } : null,
4351
+ now
4352
+ );
4353
+ if (arrayOpRemap === null && Array.isArray(value) && Array.isArray(currentValue)) {
3997
4354
  st.variantMemory.clearUnderPath(path);
3998
- st.arrayIdentity.realign(path);
3999
- } else if (isContainer(currentValue) && !isContainer(value)) {
4000
- if (subtreeHadRealBaseline(st, path, currentValue)) {
4001
- st.removedSubtrees.add(pathKey);
4002
- }
4003
4355
  }
4004
4356
  const effectiveModeAfterWrite = meta?.instance?.validateOn ?? st.fieldValidationMode;
4005
4357
  if (effectiveModeAfterWrite === "change") {
@@ -4007,7 +4359,7 @@ function setValueAtPath(st, path, value, meta) {
4007
4359
  }
4008
4360
  return true;
4009
4361
  }
4010
- function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variantDefault, consumerOverrides, meta) {
4362
+ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variantDefault, consumerOverrides, meta, writeStamp) {
4011
4363
  const sameDisc = Object.is(oldDiscValue, newDiscValue);
4012
4364
  const parentKey = canonicalizePath(parentPath).key;
4013
4365
  let baseline = variantDefault;
@@ -4073,7 +4425,7 @@ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variant
4073
4425
  appliedSync = true;
4074
4426
  }
4075
4427
  }
4076
- applyFormReplacement(st, nextForm, meta);
4428
+ applyFormReplacementWithPath(st, nextForm, meta, null, writeStamp ?? writeInstant(st));
4077
4429
  for (const k of newBlankPaths) st.blankPaths.add(k);
4078
4430
  if (reshapeMode === "change" && !appliedSync) {
4079
4431
  scheduleFieldValidation(st, parentPath, false, meta?.instance);
@@ -4094,7 +4446,9 @@ function scheduleFieldValidation(st, path, immediate, instance) {
4094
4446
  aborted: false,
4095
4447
  timer: null,
4096
4448
  settled: false,
4097
- released: false
4449
+ released: false,
4450
+ key,
4451
+ path
4098
4452
  };
4099
4453
  st.fieldValidationState.set(key, fresh);
4100
4454
  const myEpoch = ++st.scheduleEpoch;
@@ -4105,19 +4459,20 @@ function scheduleFieldValidation(st, path, immediate, instance) {
4105
4459
  try {
4106
4460
  st.activeValidations.value += 1;
4107
4461
  activeIncremented = true;
4108
- incFieldValidation(st, key);
4462
+ incFieldValidation(st, fresh.key);
4109
4463
  } catch (err) {
4110
4464
  if (activeIncremented) {
4111
4465
  st.activeValidations.value = Math.max(0, st.activeValidations.value - 1);
4112
4466
  }
4113
4467
  throw err;
4114
4468
  }
4115
- const subtreeScope = path.length > 0 && st.schema.hasContainerOrRootRefine?.() === false;
4116
- const scopePath = subtreeScope ? path : void 0;
4117
- const dataAtScope = subtreeScope ? getAtPath(st.form.value, path) : st.form.value;
4118
- const scopeKey = subtreeScope ? canonicalizePath(path).key : ROOT_PATH_KEY;
4119
- void Promise.resolve().then(() => st.schema.validateAtPath(dataAtScope, scopePath)).then((response) => {
4469
+ const startPath = fresh.path;
4470
+ const subtreeScope = startPath.length > 0 && st.schema.hasContainerOrRootRefine?.() === false;
4471
+ const dataAtScope = subtreeScope ? getAtPath(st.form.value, startPath) : st.form.value;
4472
+ void Promise.resolve().then(() => st.schema.validateAtPath(dataAtScope, subtreeScope ? startPath : void 0)).then((response) => {
4120
4473
  if (fresh.aborted) return;
4474
+ const scopePath = subtreeScope ? fresh.path : void 0;
4475
+ const scopeKey = subtreeScope ? fresh.key : ROOT_PATH_KEY;
4121
4476
  if (myEpoch <= st.lastCommittedEpoch) return;
4122
4477
  st.lastCommittedEpoch = myEpoch;
4123
4478
  if (effectiveMode === "blur") {
@@ -4128,14 +4483,14 @@ function scheduleFieldValidation(st, path, immediate, instance) {
4128
4483
  const filtered = filterAuthoredErrors(st, errors);
4129
4484
  const restamped = subtreeScope ? filtered.map((err) => ({
4130
4485
  ...err,
4131
- path: [...path, ...err.path]
4486
+ path: [...scopePath ?? [], ...err.path]
4132
4487
  })) : filtered;
4133
4488
  applySchemaErrorsForSubtree(st, scopePath ?? [], restamped);
4134
4489
  }).catch(() => {
4135
4490
  }).finally(() => {
4136
4491
  if (!fresh.released) {
4137
4492
  st.activeValidations.value = Math.max(0, st.activeValidations.value - 1);
4138
- decFieldValidation(st, key);
4493
+ decFieldValidation(st, fresh.key);
4139
4494
  }
4140
4495
  fresh.settled = true;
4141
4496
  });
@@ -4174,6 +4529,19 @@ function cancelFieldValidationUnder(st, prefix) {
4174
4529
  st.fieldValidationState.delete(key);
4175
4530
  }
4176
4531
  }
4532
+ function abortValidationAt(st, key) {
4533
+ const entry = st.fieldValidationState.get(key);
4534
+ if (entry === void 0) return;
4535
+ if (entry.timer !== null) {
4536
+ clearTimeout(entry.timer);
4537
+ } else if (!entry.settled && !entry.released) {
4538
+ st.activeValidations.value = Math.max(0, st.activeValidations.value - 1);
4539
+ decFieldValidation(st, key);
4540
+ entry.released = true;
4541
+ }
4542
+ entry.aborted = true;
4543
+ st.fieldValidationState.delete(key);
4544
+ }
4177
4545
  function onFormChange(st, listener) {
4178
4546
  st.formChangeListeners.add(listener);
4179
4547
  return () => {
@@ -4301,6 +4669,36 @@ function restoreErrorCells(st, entries) {
4301
4669
  st.errorCells().set(key, { schema: [...cell.schema], user: [...cell.user] });
4302
4670
  }
4303
4671
  }
4672
+ function captureStructure(st) {
4673
+ return {
4674
+ identity: st.arrayIdentity.snapshot(),
4675
+ originals: [...toRaw(st.originals)],
4676
+ originalBlank: [...st.originalBlankPaths],
4677
+ removed: [...st.removedPaths]
4678
+ };
4679
+ }
4680
+ function restoreStructure(st, snapshot) {
4681
+ const originals = new Map(snapshot.originals);
4682
+ const raw = toRaw(st.form.value);
4683
+ const held = /* @__PURE__ */ new Map();
4684
+ for (const [key, { segments }] of toRaw(st.originals)) {
4685
+ if (!originals.has(key) && hasAtPath(raw, segments)) {
4686
+ noteHold(st, held, raw, segments, segments.length - 1, segments);
4687
+ }
4688
+ }
4689
+ applyHolds(st, held);
4690
+ st.arrayIdentity.restore(snapshot.identity);
4691
+ replaceOriginals(st, originals);
4692
+ st.originalBlankPaths.clear();
4693
+ for (const key of snapshot.originalBlank) st.originalBlankPaths.add(key);
4694
+ const pulsed = [...st.removedPaths.values()];
4695
+ st.removedPaths.clear();
4696
+ for (const [key, segments] of snapshot.removed) {
4697
+ st.removedPaths.set(key, segments);
4698
+ pulsed.push(segments);
4699
+ }
4700
+ if (pulsed.length > 0) pulseStructure(st.structureSignal, pulsed);
4701
+ }
4304
4702
  function getErrorsForPath(st, path) {
4305
4703
  const { key } = canonicalizePath(path);
4306
4704
  const cell = st.errorCells().get(key);
@@ -4325,6 +4723,7 @@ function noteDomConnected(st, path) {
4325
4723
  }
4326
4724
  function noteDomDisconnected(st, path) {
4327
4725
  const { key } = canonicalizePath(path);
4726
+ if (!st.fields.has(key)) return;
4328
4727
  touchFieldRecord(st, key, path, { connected: false, focused: null, blurred: null });
4329
4728
  }
4330
4729
  function markConnectedOptimistically(st, path) {
@@ -4388,7 +4787,7 @@ function touchAtPath(st, segments) {
4388
4787
  const formValue = st.form.value;
4389
4788
  let touchedAny = false;
4390
4789
  for (const [leafKey, entry] of st.originals) {
4391
- if (!isPathPrefix(segments, entry.segments)) continue;
4790
+ if (!isPathPrefix(segments, entry.segments) || isDescendable(entry.value)) continue;
4392
4791
  if (!hasAtPath(formValue, entry.segments)) continue;
4393
4792
  touchedAny = true;
4394
4793
  const current = st.fields.get(leafKey);
@@ -4406,7 +4805,7 @@ function interactAtPath(st, segments) {
4406
4805
  const formValue = st.form.value;
4407
4806
  let interactedAny = false;
4408
4807
  for (const [leafKey, entry] of st.originals) {
4409
- if (!isPathPrefix(segments, entry.segments)) continue;
4808
+ if (!isPathPrefix(segments, entry.segments) || isDescendable(entry.value)) continue;
4410
4809
  if (!hasAtPath(formValue, entry.segments)) continue;
4411
4810
  interactedAny = true;
4412
4811
  const current = st.fields.get(leafKey);
@@ -4487,15 +4886,20 @@ function reset(st, nextDefaultValues) {
4487
4886
  st.schema.getDefaultValues({ useDefaultSchemaValues: true })
4488
4887
  );
4489
4888
  rebuildAuthoredPaths(st, resetSource, next);
4490
- applyFormReplacement(st, next);
4491
- st.arrayIdentity.rebaselineAll();
4492
- st.removedSubtrees.clear();
4493
- seedOriginalsFromBaseline(st, next);
4494
4889
  if (nextDefaultValues !== void 0) {
4495
4890
  const mentioned = /* @__PURE__ */ new Set();
4496
4891
  walkAuthoredFromConstraints(nextDefaultValues, [], mentioned);
4497
4892
  for (const key of mentioned) st.originalBlankPaths.delete(key);
4498
4893
  }
4894
+ const now = writeInstant(st);
4895
+ applyFormReplacementWithPath(st, next, void 0, null, now);
4896
+ st.arrayIdentity.rebaselineAll();
4897
+ if (st.removedPaths.size > 0) {
4898
+ const cleared = [...st.removedPaths.values()];
4899
+ st.removedPaths.clear();
4900
+ pulseStructure(st.structureSignal, cleared);
4901
+ }
4902
+ seedOriginalsFromBaseline(st, next);
4499
4903
  st.blankPaths.clear();
4500
4904
  for (const key of st.originalBlankPaths) {
4501
4905
  st.blankPaths.add(key);
@@ -4504,7 +4908,7 @@ function reset(st, nextDefaultValues) {
4504
4908
  replaceErrorChannel(st, "schema", st.schema.validateSync(next));
4505
4909
  st.firstValidationDone.value = initialFirstValidationGate(st.schema);
4506
4910
  queueInitialAsyncValidation(st);
4507
- const now = (/* @__PURE__ */ new Date()).toISOString();
4911
+ noteStamp(st, now);
4508
4912
  for (const [pathKey, record] of st.fields) {
4509
4913
  st.fields.set(pathKey, withClearedHistoryFlags(record, now));
4510
4914
  }
@@ -4533,6 +4937,7 @@ function reset(st, nextDefaultValues) {
4533
4937
  }
4534
4938
  function resetField(st, path) {
4535
4939
  const { key: targetKey, segments: targetSegments } = canonicalizePath(path);
4940
+ const now = writeInstant(st);
4536
4941
  st.variantMemory.clearUnderPath(targetSegments);
4537
4942
  cancelFieldValidationUnder(st, targetSegments);
4538
4943
  cancelTransformsUnder(st, targetSegments);
@@ -4541,9 +4946,21 @@ function resetField(st, path) {
4541
4946
  if (segs === null) continue;
4542
4947
  if (isPathPrefix(targetSegments, segs)) st.pathSnapshots.delete(snapKey);
4543
4948
  }
4949
+ const cleared = [];
4950
+ for (const [fieldKey, record] of Array.from(st.fields.entries())) {
4951
+ if (!isPathPrefix(targetSegments, record.path)) continue;
4952
+ st.fields.set(fieldKey, withClearedHistoryFlags(record, record.updatedAt));
4953
+ cleared.push(fieldKey);
4954
+ }
4544
4955
  const leafEntry = st.originals.get(targetKey);
4545
4956
  if (leafEntry !== void 0) {
4546
- const wrote = setValueAtPath(st, targetSegments, leafEntry.value);
4957
+ const wrote = setValueAtPath(
4958
+ st,
4959
+ targetSegments,
4960
+ structuralSnapshot(leafEntry.value),
4961
+ void 0,
4962
+ now
4963
+ );
4547
4964
  if (!wrote) {
4548
4965
  console.error(
4549
4966
  `[attaform] resetField: leaf write rejected for path '${targetKey}'. Originals contain a value that doesn't satisfy the slim primitive shape. This is a bug in the construction pipeline.`
@@ -4561,10 +4978,10 @@ function resetField(st, path) {
4561
4978
  if (subtree === void 0) {
4562
4979
  subtree = typeof relative[0] === "number" ? [] : {};
4563
4980
  }
4564
- subtree = setAtPath(subtree, relative, entry.value);
4981
+ subtree = setAtPath(subtree, relative, structuralSnapshot(entry.value));
4565
4982
  }
4566
4983
  if (anyMatch) {
4567
- const wroteSubtree = setValueAtPath(st, targetSegments, subtree);
4984
+ const wroteSubtree = setValueAtPath(st, targetSegments, subtree, void 0, now);
4568
4985
  if (!wroteSubtree) {
4569
4986
  console.error(
4570
4987
  `[attaform] resetField: subtree write rejected at path '${targetKey}'. Originals contain values that don't satisfy the slim primitive shape. This is a bug in the construction pipeline.`
@@ -4573,8 +4990,14 @@ function resetField(st, path) {
4573
4990
  }
4574
4991
  }
4575
4992
  deleteErrorCellsUnderPrefix(st, targetSegments);
4576
- for (const [fieldKey, record] of Array.from(st.fields.entries())) {
4577
- if (isPathPrefix(targetSegments, record.path)) clearFieldRecordFlags(st, fieldKey);
4993
+ const raw = toRaw(st.form.value);
4994
+ for (const fieldKey of cleared) {
4995
+ const record = st.fields.get(fieldKey);
4996
+ if (record === void 0 || !hasAtPath(raw, record.path)) continue;
4997
+ raiseStamp(st, fieldKey, record.path, now);
4998
+ }
4999
+ if (cleared.length > 0 && hasAtPath(raw, targetSegments)) {
5000
+ stampContainers(st, [targetSegments], now);
4578
5001
  }
4579
5002
  }
4580
5003
  function deleteErrorCellsUnderPrefix(st, prefix) {
@@ -4587,36 +5010,35 @@ function deleteErrorCellsUnderPrefix(st, prefix) {
4587
5010
  }
4588
5011
  }
4589
5012
  }
4590
- function clearFieldRecordFlags(st, pathKey) {
4591
- const record = st.fields.get(pathKey);
4592
- if (record === void 0) return;
4593
- st.fields.set(pathKey, withClearedHistoryFlags(record, (/* @__PURE__ */ new Date()).toISOString()));
4594
- }
4595
5013
  function isPristineAtPathByKey(st, key, segments) {
4596
5014
  if (st.blankPaths.has(key) !== st.originalBlankPaths.has(key)) return false;
4597
5015
  const entry = st.originals.get(key);
4598
5016
  if (entry === void 0) return true;
4599
5017
  return Object.is(getAtPath(st.form.value, segments), entry.value);
4600
5018
  }
4601
- function hasStructuralChangeUnder(st, path) {
5019
+ function hasStructuralChangeUnder(st, path, key) {
5020
+ subscribeStructure(st.structureSignal, key);
4602
5021
  return st.arrayIdentity.hasStructuralChangeUnder(path);
4603
5022
  }
4604
- function subtreeHadRealBaseline(st, prefix, removedValue) {
4605
- let had = false;
4606
- diffAndApply(removedValue, void 0, prefix, (patch) => {
4607
- if (had || patch.kind !== "removed") return;
4608
- const record = st.originals.get(canonicalizePath(patch.path).key);
4609
- if (record?.value !== void 0) had = true;
5023
+ function pulseStructure(signal, paths) {
5024
+ const keys = signal.keys;
5025
+ if (keys === null) return;
5026
+ eachAncestorOnce(paths, (key) => {
5027
+ keys.add(key);
5028
+ keys.delete(key);
4610
5029
  });
4611
- return had;
4612
5030
  }
4613
- function hasRemovedSubtreeUnder(st, prefix) {
4614
- if (st.removedSubtrees.size === 0) return false;
4615
- for (const key of st.removedSubtrees) {
4616
- const segments = segmentsForPathKey(key);
4617
- if (segments === null) continue;
5031
+ function subscribeStructure(signal, key) {
5032
+ signal.keys ?? (signal.keys = shallowReactive(/* @__PURE__ */ new Set()));
5033
+ void signal.keys.has(key);
5034
+ }
5035
+ function hasRemovedSubtreeUnder(st, prefix, key) {
5036
+ subscribeStructure(st.structureSignal, key);
5037
+ if (st.removedPaths.size === 0) return false;
5038
+ const raw = toRaw(st.form.value);
5039
+ for (const segments of st.removedPaths.values()) {
4618
5040
  if (!isPathPrefix(prefix, segments)) continue;
4619
- if (isContainer(getAtPath(toRaw(st.form.value), segments))) continue;
5041
+ if (hasAtPath(raw, segments)) continue;
4620
5042
  return true;
4621
5043
  }
4622
5044
  return false;
@@ -4652,10 +5074,14 @@ function createFormStore(options) {
4652
5074
  warn: true
4653
5075
  }) : initialData;
4654
5076
  const form = ref(stubbedInitialData);
4655
- const arrayIdentity = createArrayIdentity((arraySegs) => {
4656
- const v = getAtPath(toRaw(form.value), arraySegs);
4657
- return Array.isArray(v) ? v.length : 0;
4658
- });
5077
+ const structureSignal = { keys: null };
5078
+ const arrayIdentity = createArrayIdentity(
5079
+ (arraySegs) => {
5080
+ const v = getAtPath(toRaw(form.value), arraySegs);
5081
+ return Array.isArray(v) ? v.length : 0;
5082
+ },
5083
+ (arrayPaths) => pulseStructure(structureSignal, arrayPaths)
5084
+ );
4659
5085
  const fields = shallowReactive(/* @__PURE__ */ new Map());
4660
5086
  const domBinding = shallowRef(null);
4661
5087
  const errorStore = createErrorCells(
@@ -4664,7 +5090,7 @@ function createFormStore(options) {
4664
5090
  );
4665
5091
  const errorCells = () => errorStore(true);
4666
5092
  const originals = shallowReactive(/* @__PURE__ */ new Map());
4667
- const removedSubtrees = /* @__PURE__ */ new Set();
5093
+ const removedPaths = /* @__PURE__ */ new Map();
4668
5094
  const blankPaths = reactive(/* @__PURE__ */ new Set());
4669
5095
  const originalBlankPaths = /* @__PURE__ */ new Set();
4670
5096
  const seededBlankPaths = hydration !== void 0 ? (hydration.blankPaths ?? []).map((dotted) => canonicalizePath(dotted).key) : options.initialBlankPaths ?? [];
@@ -4773,6 +5199,8 @@ function createFormStore(options) {
4773
5199
  blankPaths,
4774
5200
  originalBlankPaths,
4775
5201
  authoredPaths,
5202
+ removedPaths,
5203
+ notifyStructure: (paths) => pulseStructure(structureSignal, paths),
4776
5204
  fieldValidationCounts,
4777
5205
  fieldValidatingSince,
4778
5206
  fieldValidationState,
@@ -4780,6 +5208,9 @@ function createFormStore(options) {
4780
5208
  arrayIdentity,
4781
5209
  variantMemory,
4782
5210
  touchFieldRecord: (pathKey, path, patch) => touchFieldRecord(st, pathKey, path, patch),
5211
+ stampContainers: (containers, now) => stampContainers(st, containers, now),
5212
+ stampBareContainers: (patches, bare, now) => stampBareContainers(st, patches, bare, now),
5213
+ foldInteractionHistory: (path, released) => foldInteractionHistory(st, path, released),
4783
5214
  decFieldValidation: (key) => decFieldValidation(st, key)
4784
5215
  });
4785
5216
  const bind = (fn) => (...args) => fn(st, ...args);
@@ -4843,7 +5274,8 @@ function createFormStore(options) {
4843
5274
  cleanupHooks,
4844
5275
  authoredPaths,
4845
5276
  arrayIdentity,
4846
- removedSubtrees,
5277
+ removedPaths,
5278
+ structureSignal,
4847
5279
  variantMemory,
4848
5280
  pathOrdinals,
4849
5281
  pathSnapshots,
@@ -4853,6 +5285,7 @@ function createFormStore(options) {
4853
5285
  arrayBookkeeping,
4854
5286
  skipErrorSeed: () => errorStore(false),
4855
5287
  nextOrdinal: 0,
5288
+ latestStamp: "",
4856
5289
  scheduleEpoch: 0,
4857
5290
  lastCommittedEpoch: 0,
4858
5291
  transformTokenSeq: 0,
@@ -4890,6 +5323,8 @@ function createFormStore(options) {
4890
5323
  ),
4891
5324
  clearUserErrors: (path) => clearErrorChannel(st, "user", path),
4892
5325
  restoreErrorCells: bind(restoreErrorCells),
5326
+ captureStructure: bind(captureStructure),
5327
+ restoreStructure: bind(restoreStructure),
4893
5328
  getErrorsForPath: bind(getErrorsForPath),
4894
5329
  ensurePathOrdinal: bind(ensurePathOrdinal),
4895
5330
  noteDomConnected: bind(noteDomConnected),
@@ -4923,7 +5358,7 @@ function createFormStore(options) {
4923
5358
  diffAndApply({}, schemaInitialData, [], (patch) => {
4924
5359
  if (patch.kind !== "added") return;
4925
5360
  const { key } = canonicalizePath(patch.path);
4926
- originals.set(key, { segments: patch.path, value: patch.newValue });
5361
+ if (seedBaseline(originals, key, patch)) return;
4927
5362
  ensurePathOrdinal(st, key);
4928
5363
  if (hydration === void 0) {
4929
5364
  fields.set(key, {
@@ -4938,6 +5373,7 @@ function createFormStore(options) {
4938
5373
  });
4939
5374
  }
4940
5375
  });
5376
+ if (fields.size > 0) noteStamp(st, initStamp);
4941
5377
  if (hydration !== void 0) {
4942
5378
  for (const [rawKey, record] of hydration.fields) {
4943
5379
  if (typeof rawKey !== "string" || !isHydratedFieldRecord(record)) {
@@ -4945,6 +5381,7 @@ function createFormStore(options) {
4945
5381
  continue;
4946
5382
  }
4947
5383
  fields.set(rawKey, record);
5384
+ noteStamp(st, record.updatedAt);
4948
5385
  }
4949
5386
  for (const [rawKey, errs] of hydration.schemaErrors) {
4950
5387
  if (typeof rawKey !== "string" || !isHydratedValidationErrorArray(errs)) {
@@ -5522,7 +5959,7 @@ function buildWizardStatusesProxy(statuses) {
5522
5959
  // resolves to `undefined` (consistent with property-access).
5523
5960
  resolveCall: (arg) => statuses[String(arg)]?.value,
5524
5961
  ownKeys: () => Object.keys(statuses),
5525
- hasKey: (key) => Object.hasOwn(statuses, key)
5962
+ hasKey: (key) => safeOwnHas(statuses, key)
5526
5963
  });
5527
5964
  }
5528
5965