attaform 0.30.1 → 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 (55) 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 +3 -3
  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.DxHdkkPG.mjs → attaform-dev.3uTCYwy8.mjs} +770 -254
  11. package/dist/dev/shared/{attaform-dev.BJK1kqHY.mjs → attaform-dev.BpVGFSFa.mjs} +88 -115
  12. package/dist/dev/shared/{attaform-dev.Chm4D6SJ.mjs → attaform-dev.Bu6wgrA5.mjs} +3 -3
  13. package/dist/dev/shared/{attaform-dev.BMQ3GcgD.mjs → attaform-dev.Cbx0AiQF.mjs} +476 -337
  14. package/dist/dev/shared/attaform-dev.CwYTWyPX.mjs +120 -0
  15. package/dist/dev/shared/{attaform-dev.DuEE4GU1.mjs → attaform-dev.D7lKyM_7.mjs} +4 -4
  16. package/dist/dev/shared/{attaform-dev.CT7MDjPy.mjs → attaform-dev.OceE0X3v.mjs} +154 -229
  17. package/dist/{shared/attaform.DRsANMok.mjs → dev/shared/attaform-dev.PTGM9KE1.mjs} +16 -15
  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/components/AttaformDevtoolsPanel.vue +3 -3
  29. package/dist/runtime/plugins/attaform.mjs +1 -1
  30. package/dist/shared/{attaform.CO918TdU.mjs → attaform.B5b-HmhH.mjs} +88 -115
  31. package/dist/shared/{attaform.2FslhB9R.d.mts → attaform.B9PYKlhB.d.mts} +43 -19
  32. package/dist/shared/{attaform.D_f1WgYf.mjs → attaform.BPMOl562.mjs} +458 -319
  33. package/dist/{dev/shared/attaform-dev.CZz4GYZ6.mjs → shared/attaform.BPSqtU7a.mjs} +44 -156
  34. package/dist/shared/{attaform.CdZIEf7_.mjs → attaform.BhtAZysa.mjs} +3 -2
  35. package/dist/shared/{attaform.BcQwgWaq.d.mts → attaform.CYlF4P6X.d.mts} +58 -17
  36. package/dist/shared/{attaform.WiGdIqgx.mjs → attaform.CdA9bfRv.mjs} +3 -3
  37. package/dist/shared/{attaform.BIWicztt.mjs → attaform.DAf4ehIe.mjs} +765 -251
  38. package/dist/shared/{attaform.ZYn2ahzJ.mjs → attaform.DBCbxlyk.mjs} +59 -1
  39. package/dist/shared/{attaform.L0kUn3vL.d.mts → attaform.DZOynI6c.d.mts} +1 -1
  40. package/dist/shared/{attaform.B2iebkPA.mjs → attaform.KEfNRDot.mjs} +4 -4
  41. package/dist/shared/attaform._1Zp3mDG.mjs +96 -0
  42. package/dist/shared/{attaform.Br8EBn5B.d.mts → attaform.i13OEHJF.d.mts} +195 -38
  43. package/dist/{dev/shared/attaform-dev.BUIFcTYf.mjs → shared/attaform.j9xI_ObC.mjs} +16 -15
  44. package/dist/shared/{attaform.D_pt1gOj.mjs → attaform.u6jfHoed.mjs} +154 -229
  45. package/dist/transforms.mjs +1 -1
  46. package/dist/vite.mjs +1 -1
  47. package/dist/zod-v3.d.mts +4 -4
  48. package/dist/zod-v3.mjs +6 -6
  49. package/dist/zod-v4.d.mts +22 -16
  50. package/dist/zod-v4.mjs +6 -6
  51. package/dist/zod.d.mts +4 -4
  52. package/dist/zod.mjs +5 -5
  53. package/package.json +2 -1
  54. package/skills/attaform/SKILL.md +2 -1
  55. package/skills/attaform/references/custom-components.md +4 -0
@@ -1,8 +1,9 @@
1
- import { computed, readonly, toRaw, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, nextTick, warn, reactive, shallowReactive, shallowRef, toValue, watch, triggerRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, onBeforeMount, onBeforeUpdate, onMounted, effectScope } 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.Chm4D6SJ.mjs';
4
- import { R as REGISTER_OWNER_MARKER, d as armDomBinding, V as V_REGISTER_MARKER } from './attaform-dev.BMQ3GcgD.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';
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, 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) {
@@ -531,7 +532,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
531
532
  const value = state.getValueAtPath(segments);
532
533
  const original = state.originals.get(key)?.value;
533
534
  const pristine = state.isPristineAtPathByKey(key, segments);
534
- const cell = state.errorCells.get(key);
535
+ const cell = state.errorCells().get(key);
535
536
  const schemaForKey = cell !== void 0 && cell.schema.length > 0 ? cell.schema : void 0;
536
537
  const blankForKey = state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments) ? [makeBlankRequiredError(segments)] : void 0;
537
538
  const userForKey = cell !== void 0 && cell.user.length > 0 ? cell.user : void 0;
@@ -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,11 +828,43 @@ 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
- const cells = state.errorCells;
867
+ const cells = state.errorCells();
824
868
  const buckets = /* @__PURE__ */ new Map();
825
869
  for (const { key, segments } of candidates) {
826
870
  if (!isPathPrefix(prefix, segments)) continue;
@@ -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;
@@ -1102,7 +1143,7 @@ function buildErrorsSurface(state, sweep) {
1102
1143
  });
1103
1144
  }
1104
1145
  function collectErrorsAt(state, key, segments, active, into) {
1105
- const cell = state.errorCells.get(key);
1146
+ const cell = state.errorCells().get(key);
1106
1147
  if (active) {
1107
1148
  if (cell !== void 0) into.push(...cell.schema);
1108
1149
  if (state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments)) {
@@ -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,15 +1778,40 @@ 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
1691
1813
  }));
1692
- migrateMapSubtree(errorCells, arrayPath, remap, (cell, segments) => ({
1814
+ migrateMapSubtree(errorCells(), arrayPath, remap, (cell, segments) => ({
1693
1815
  schema: NO_ERRORS,
1694
1816
  user: cell.user.map((error) => ({ ...error, path: [...segments] }))
1695
1817
  }));
@@ -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
- evictSchemaVerdictsAtIndices(errorCells, arrayPath, changed);
1743
- abortValidationAtVacatedIndices(arrayPath, remap);
1882
+ evictSchemaVerdictsAtIndices(errorCells(), arrayPath, changed);
1744
1883
  variantMemory.dropAtIndices(arrayPath, changed);
1745
1884
  arrayIdentity.applyOp(arrayPath, remap);
1746
1885
  }
@@ -2060,7 +2199,7 @@ function adapterThrowMessage(err) {
2060
2199
  return "Adapter validateAtPath threw a non-Error value";
2061
2200
  }
2062
2201
  function hasUserErrorEntries(state) {
2063
- for (const cell of state.errorCells.values()) {
2202
+ for (const cell of state.errorCells().values()) {
2064
2203
  if (cell.user.length > 0) return true;
2065
2204
  }
2066
2205
  return false;
@@ -2171,9 +2310,9 @@ function reportRejection(store, path, kind, accepted) {
2171
2310
  if (kind === "string" && accepted.has("number")) {
2172
2311
  console.warn(
2173
2312
  `[attaform] Cannot write a string to '${dotted}': the schema expects ${expected}.
2174
- Fix: add type="number" to the input, OR use the .number modifier on v-register:
2175
- <input type="number" v-register="register('${dotted}')" />
2313
+ Fix: use the .number modifier on v-register, OR add type="number" to a native input:
2176
2314
  <input v-register.number="register('${dotted}')" />
2315
+ <input type="number" v-register="register('${dotted}')" />
2177
2316
  The write was a no-op.`
2178
2317
  );
2179
2318
  return;
@@ -2329,6 +2468,7 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2329
2468
  const isRequired = state.schema.isRequiredAtPath(segments);
2330
2469
  const ariaDisplayState = getDisplayStateAt !== void 0 ? computed(() => getDisplayStateAt(segments)) : void 0;
2331
2470
  const markBlank = () => state.setValueAtPath(segments, slimDefault, withInstanceMeta({ blank: true }));
2471
+ const commitFromHost = (value) => value === "" && !acceptsString || value === null && !slimTypes.has("null") || value === void 0 && !acceptsUndefined ? markBlank() : state.setValueAtPath(segments, value, withInstanceMeta(void 0));
2332
2472
  const internalRv = {
2333
2473
  innerRef,
2334
2474
  displayValue,
@@ -2345,7 +2485,7 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2345
2485
  },
2346
2486
  ensureDomBinding: (factory) => {
2347
2487
  var _a;
2348
- (_a = state.domBinding).value ?? (_a.value = factory(state));
2488
+ return (_a = state.domBinding).value ?? (_a.value = factory(state));
2349
2489
  },
2350
2490
  registerElement: (element) => {
2351
2491
  const dom = state.domBinding.value;
@@ -2365,10 +2505,10 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2365
2505
  setValueWithInternalPath: (value, meta) => {
2366
2506
  return state.setValueAtPath(segments, value, withInstanceMeta(meta));
2367
2507
  },
2368
- setValueFromHost: (value) => {
2508
+ commitFromHost,
2509
+ setValueFromHost: (value, modifiers) => {
2369
2510
  state.markInteracted(segments);
2370
- const isBlankSignal = value === "" && !acceptsString || value === null && !slimTypes.has("null") || value === void 0 && !acceptsUndefined;
2371
- const accepted = isBlankSignal ? markBlank() : state.setValueAtPath(segments, value, withInstanceMeta(void 0));
2511
+ const accepted = state.domBinding.value?.hostChannel.write(internalRv, value, modifiers) ?? commitFromHost(value);
2372
2512
  {
2373
2513
  const dedupeKey = `${formInstanceId}:${pathKey}`;
2374
2514
  const isWired = () => (state.domBinding.value?.elements.get(pathKey)?.elements.size ?? 0) > 0 || state.getFieldRecord(segments)?.connected === true;
@@ -2384,6 +2524,7 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2384
2524
  }
2385
2525
  return accepted;
2386
2526
  },
2527
+ setValueFromHostInput: (payload, modifiers) => state.domBinding.value?.hostChannel.writeInput(internalRv, payload, modifiers) ?? false,
2387
2528
  // Called by the `vRegisterHintTransform` compile-time transform's wrapping
2388
2529
  // IIFE on every server-side render of `<element v-register="…">`.
2389
2530
  // Without it, every SSR'd FieldState serialises `connected: false`
@@ -2457,25 +2598,24 @@ function isUnset(value) {
2457
2598
  return value === unset;
2458
2599
  }
2459
2600
 
2460
- function walkUnsetSentinels(values, schema) {
2601
+ function walkUnsetSentinels(values, schema, rootDefault) {
2461
2602
  const paths = [];
2462
2603
  if (values === void 0) {
2463
- const rootSlim = schema.getDefaultAtPath([]);
2464
- walkUnspecified(rootSlim, [], paths);
2604
+ walkUnspecified(rootDefault, [], paths);
2465
2605
  return { cleanedValues: void 0, paths };
2466
2606
  }
2467
- const cleaned = walkCore(values, [], schema, paths, true);
2607
+ const cleaned = walkCore(values, [], schema, paths, { rootDefault });
2468
2608
  return { cleanedValues: cleaned, paths };
2469
2609
  }
2470
2610
  function isRecursable(value) {
2471
2611
  return Array.isArray(value) || isPlainRecord(value);
2472
2612
  }
2473
- function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2613
+ function walkCore(input, segments, schema, paths, synthesis) {
2474
2614
  if (isUnset(input)) {
2475
2615
  return expandUnsetAt(segments, schema, paths);
2476
2616
  }
2477
2617
  if (input === void 0) {
2478
- if (synthesizeSchemaKeys) {
2618
+ if (synthesis !== null) {
2479
2619
  const slim = schema.getDefaultAtPath(segments);
2480
2620
  return walkUnspecified(slim, segments, paths);
2481
2621
  }
@@ -2488,7 +2628,7 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2488
2628
  let mutated = false;
2489
2629
  for (let i = 0; i < input.length; i++) {
2490
2630
  const original = readConsumerIndex(input, i);
2491
- const walked = walkCore(original, [...segments, i], schema, paths, synthesizeSchemaKeys);
2631
+ const walked = walkCore(original, [...segments, i], schema, paths, synthesis);
2492
2632
  out[i] = walked;
2493
2633
  if (walked !== original) mutated = true;
2494
2634
  }
@@ -2500,10 +2640,10 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2500
2640
  let keys = inputKeys;
2501
2641
  let mutated = false;
2502
2642
  let inputKeysSet = null;
2503
- if (synthesizeSchemaKeys) {
2643
+ if (synthesis !== null) {
2504
2644
  inputKeysSet = new Set(inputKeys);
2505
2645
  const allKeys = new Set(inputKeys);
2506
- const slim = schema.getDefaultAtPath(segments);
2646
+ const slim = segments.length === 0 ? synthesis.rootDefault : schema.getDefaultAtPath(segments);
2507
2647
  if (isPlainRecord(slim)) {
2508
2648
  for (const k of Object.keys(slim)) allKeys.add(k);
2509
2649
  }
@@ -2513,12 +2653,12 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2513
2653
  const out = {};
2514
2654
  for (const key of keys) {
2515
2655
  const orig = readConsumerProp(obj, key);
2516
- if (synthesizeSchemaKeys && orig === void 0 && inputKeysSet?.has(key) === true) {
2656
+ if (synthesis !== null && orig === void 0 && inputKeysSet?.has(key) === true) {
2517
2657
  safeAssign(out, key, void 0);
2518
2658
  mutated = true;
2519
2659
  continue;
2520
2660
  }
2521
- const walked = walkCore(orig, [...segments, key], schema, paths, synthesizeSchemaKeys);
2661
+ const walked = walkCore(orig, [...segments, key], schema, paths, synthesis);
2522
2662
  safeAssign(out, key, walked);
2523
2663
  if (walked !== orig) mutated = true;
2524
2664
  }
@@ -2542,7 +2682,7 @@ function walkUnspecified(slim, segments, paths) {
2542
2682
  }
2543
2683
  function substituteUnsetSentinels(value, prefix, schema) {
2544
2684
  const paths = [];
2545
- const cleaned = walkCore(value, [...prefix], schema, paths, false);
2685
+ const cleaned = walkCore(value, [...prefix], schema, paths, null);
2546
2686
  return { cleanedValues: cleaned, paths };
2547
2687
  }
2548
2688
  function isPrimitiveOrEmpty(value) {
@@ -2551,12 +2691,12 @@ function isPrimitiveOrEmpty(value) {
2551
2691
  return t === "string" || t === "number" || t === "boolean" || t === "bigint";
2552
2692
  }
2553
2693
  function isSlimNumericPrimitive(value) {
2554
- return value === 0 || value === 0n;
2694
+ return value === 0 || typeof value === "bigint" && !value;
2555
2695
  }
2556
2696
  function blankForKind(slimDefault) {
2557
2697
  if (typeof slimDefault === "string") return "";
2558
2698
  if (typeof slimDefault === "number") return 0;
2559
- if (typeof slimDefault === "bigint") return 0n;
2699
+ if (typeof slimDefault === "bigint") return typeof BigInt === "function" ? BigInt(0) : void 0;
2560
2700
  if (typeof slimDefault === "boolean") return false;
2561
2701
  if (slimDefault === null) return null;
2562
2702
  return void 0;
@@ -2707,7 +2847,18 @@ function buildFormApi(state, formInstanceId, options = {}) {
2707
2847
  void state.submitted.value;
2708
2848
  return metaBase;
2709
2849
  };
2710
- const pathSweep = state.pathSweep;
2850
+ const releases = [];
2851
+ const lease = (release) => {
2852
+ releases.push(release);
2853
+ return release;
2854
+ };
2855
+ onScopeDispose(() => {
2856
+ for (const release of releases) release();
2857
+ }, true);
2858
+ const pathSweep = {
2859
+ track: state.pathSweep.track,
2860
+ onEvict: (evict) => lease(state.pathSweep.onEvict(evict))
2861
+ };
2711
2862
  const getRootFieldStateAt = buildFieldStateAccessor(
2712
2863
  state,
2713
2864
  formInstanceId,
@@ -2765,7 +2916,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
2765
2916
  const next = typeof pathOrValue === "function" ? pathOrValue(structuralSnapshot(state.form.value)) : pathOrValue;
2766
2917
  const walked2 = walkUnsetSentinels(
2767
2918
  next,
2768
- state.schema
2919
+ state.schema,
2920
+ state.schema.getDefaultAtPath([])
2769
2921
  );
2770
2922
  const ok2 = state.setValueAtPath([], walked2.cleanedValues, writeMeta());
2771
2923
  if (!ok2) return false;
@@ -2830,7 +2982,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2830
2982
  const errorsProxy = buildErrorsSurface(state, pathSweep);
2831
2983
  function flattenUserErrors() {
2832
2984
  const all = [];
2833
- for (const cell of state.errorCells.values()) all.push(...cell.user);
2985
+ for (const cell of state.errorCells().values()) all.push(...cell.user);
2834
2986
  return all;
2835
2987
  }
2836
2988
  function setErrors(arg1, arg2) {
@@ -2838,7 +2990,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2838
2990
  if (isScoped) {
2839
2991
  const { segments, key } = canonicalizePath(arg1);
2840
2992
  const input2 = arg2;
2841
- const resolved2 = typeof input2 === "function" ? input2([...state.errorCells.get(key)?.user ?? []]) : input2;
2993
+ const resolved2 = typeof input2 === "function" ? input2([...state.errorCells().get(key)?.user ?? []]) : input2;
2842
2994
  state.setUserErrorsForPath(
2843
2995
  segments,
2844
2996
  normalizeErrorInputs(resolved2, segments, AttaformErrorCode.UserError)
@@ -2866,7 +3018,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2866
3018
  const departAttempts = computed(() => state.departAttempts.value);
2867
3019
  const validating = computed(() => state.activeValidations.value > 0);
2868
3020
  const valid = computed(
2869
- () => state.firstValidationDone.value && state.errorCells.size === 0 && state.derivedBlankErrors.value.size === 0 && !validating.value
3021
+ () => state.firstValidationDone.value && state.errorCells().size === 0 && state.derivedBlankErrors.value.size === 0 && !validating.value
2870
3022
  );
2871
3023
  const history = options.history;
2872
3024
  const formHistory = history === void 0 ? inertHistory() : readonly(
@@ -2913,7 +3065,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2913
3065
  };
2914
3066
  const metaTarget = buildMetaProxy(META_KEYS, (key) => {
2915
3067
  if (key === "errorCount") return metaErrors.value.length;
2916
- if (Object.hasOwn(metaOwn, key)) return metaOwn[key];
3068
+ if (safeOwnHas(metaOwn, key)) return metaOwn[key];
2917
3069
  return rootFieldState.value[key];
2918
3070
  });
2919
3071
  const formMeta = readonly(reactive(metaTarget));
@@ -2928,8 +3080,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
2928
3080
  );
2929
3081
  state.reset(walked.cleanedValues);
2930
3082
  for (const pathKey of walked.paths) {
2931
- state.blankPaths.add(pathKey);
2932
3083
  state.originalBlankPaths.add(pathKey);
3084
+ state.blankPaths.add(pathKey);
2933
3085
  }
2934
3086
  }
2935
3087
  };
@@ -2982,7 +3134,10 @@ function buildFormApi(state, formInstanceId, options = {}) {
2982
3134
  };
2983
3135
  return Object.freeze(view);
2984
3136
  });
2985
- const valuesProxy = buildValuesSurface(state.form, state.onFormChange);
3137
+ const valuesProxy = buildValuesSurface(
3138
+ state.form,
3139
+ (listener) => lease(state.onFormChange(listener))
3140
+ );
2986
3141
  const fieldStateProxy = buildFieldsSurface(state, getRootFieldStateAt, pathSweep);
2987
3142
  const needsLazyGate = state.defaultValuesFactory.value !== void 0 || state.hasSsrPrefetch;
2988
3143
  function gated(fn) {
@@ -3130,7 +3285,7 @@ function shortenSourceFrame(frame) {
3130
3285
  const SWEEP_SLICE = 8;
3131
3286
  function createDynamicPathSweep(deps) {
3132
3287
  const dynamicKeys = /* @__PURE__ */ new Set();
3133
- const evictors = [];
3288
+ const evictors = /* @__PURE__ */ new Set();
3134
3289
  const isDynamicPath = (segments) => {
3135
3290
  for (let i = 0; i < segments.length; i++) {
3136
3291
  if (typeof segments[i] === "number") return true;
@@ -3161,7 +3316,10 @@ function createDynamicPathSweep(deps) {
3161
3316
  if (isDynamicPath(segments)) dynamicKeys.add(key);
3162
3317
  },
3163
3318
  onEvict(evict) {
3164
- evictors.push(evict);
3319
+ evictors.add(evict);
3320
+ return () => {
3321
+ evictors.delete(evict);
3322
+ };
3165
3323
  }
3166
3324
  };
3167
3325
  }
@@ -3365,7 +3523,7 @@ function mergeObjectKeys(target, source, path, schema) {
3365
3523
  async function runFactoryAndApply(st, factory) {
3366
3524
  try {
3367
3525
  const value = await factory();
3368
- walkAuthoredFromConstraints(value, [], st.authoredPaths);
3526
+ if (st.hasPreprocessOrCoerce) walkAuthoredFromConstraints(value, [], st.authoredPaths);
3369
3527
  const full = mergeSparseHydration(
3370
3528
  toRaw(st.form.value),
3371
3529
  value,
@@ -3389,7 +3547,7 @@ async function runFactoryAndApply(st, factory) {
3389
3547
  }
3390
3548
  }
3391
3549
  function clearHydrationFailedEntry(st) {
3392
- const existing = st.errorCells.get(ROOT_PATH_KEY)?.schema;
3550
+ const existing = st.errorCells().get(ROOT_PATH_KEY)?.schema;
3393
3551
  if (existing === void 0 || existing.length === 0) return;
3394
3552
  const filtered = existing.filter((e) => e.code !== AttaformErrorCode.HydrationFailed);
3395
3553
  if (filtered.length !== existing.length) {
@@ -3403,21 +3561,20 @@ function appendHydrationFailedEntry(st, error) {
3403
3561
  path: [...ROOT_PATH],
3404
3562
  code: AttaformErrorCode.HydrationFailed
3405
3563
  };
3406
- const existing = st.errorCells.get(ROOT_PATH_KEY)?.schema ?? [];
3564
+ const existing = st.errorCells().get(ROOT_PATH_KEY)?.schema ?? [];
3407
3565
  st.setSchemaErrorsForPath([...ROOT_PATH], [...existing, entry]);
3408
3566
  return entry;
3409
3567
  }
3410
3568
 
3411
- const isContainer = (value) => Array.isArray(value) || isPlainRecord(value);
3412
3569
  function isHydratedFieldRecord(value) {
3413
3570
  if (typeof value !== "object" || value === null) return false;
3414
3571
  const r = value;
3415
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";
3416
3573
  }
3417
- function withClearedHistoryFlags(record, now) {
3574
+ function withClearedHistoryFlags(record, updatedAt) {
3418
3575
  return {
3419
3576
  path: record.path,
3420
- updatedAt: now,
3577
+ updatedAt,
3421
3578
  connected: record.connected,
3422
3579
  focused: record.focused,
3423
3580
  blurred: record.blurred,
@@ -3466,7 +3623,7 @@ function walkDuStubs(schema, value, path, warned) {
3466
3623
  if (du !== void 0) {
3467
3624
  const discValue = rec[du.discriminatorKey];
3468
3625
  if (discValue !== void 0 && !du.isVariantSelected(discValue)) {
3469
- 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;
3470
3627
  if (!isKindBlank && warned !== void 0 && true) {
3471
3628
  const dotted = path.map((s) => String(s)).join(".") || "(root)";
3472
3629
  const key = `${dotted}::${String(discValue)}`;
@@ -3537,24 +3694,38 @@ function walkAuthoredFromSchemaDiff(withDefaults, withoutDefaults, prefix, out)
3537
3694
  out.add(canonicalizePath(prefix).key);
3538
3695
  }
3539
3696
  }
3540
- function computeBaselineResponse(schema, source) {
3541
- const completed = source === void 0 ? void 0 : mergeStructural(schema, [], source);
3697
+ function computeBaseline(schema, source, schemaDefaults) {
3698
+ if (source === void 0) return schemaDefaults;
3542
3699
  return schema.getDefaultValues({
3543
3700
  useDefaultSchemaValues: true,
3544
- constraints: completed
3701
+ constraints: mergeStructural(schema, [], source, schemaDefaults)
3545
3702
  });
3546
3703
  }
3547
3704
  function initialFirstValidationGate(schema) {
3548
3705
  return schema.needsAsyncValidation?.() !== true;
3549
3706
  }
3550
- function seedOriginalsFromBaseline(st, baseline, ensureOrdinals) {
3551
- st.originals.clear();
3707
+ function seedOriginalsFromBaseline(st, baseline) {
3708
+ const seeded = /* @__PURE__ */ new Map();
3552
3709
  diffAndApply({}, baseline, [], (patch) => {
3553
- if (patch.kind !== "added") return;
3554
- const { key } = canonicalizePath(patch.path);
3555
- st.originals.set(key, { segments: patch.path, value: patch.newValue });
3556
- if (ensureOrdinals) ensurePathOrdinal(st, key);
3710
+ if (patch.kind === "added") seedBaseline(seeded, canonicalizePath(patch.path).key, patch);
3557
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;
3558
3729
  }
3559
3730
  function queueInitialAsyncValidation(st) {
3560
3731
  if (!st.ssr && st.schema.needsAsyncValidation?.() === true) {
@@ -3567,6 +3738,7 @@ function queueInitialAsyncValidation(st) {
3567
3738
  }
3568
3739
  }
3569
3740
  function rebuildAuthoredPaths(st, constraints, schemaWithDefaultsData) {
3741
+ if (!st.hasPreprocessOrCoerce) return;
3570
3742
  st.authoredPaths.clear();
3571
3743
  if (constraints !== void 0) {
3572
3744
  walkAuthoredFromConstraints(constraints, [], st.authoredPaths);
@@ -3600,6 +3772,7 @@ function ensurePathOrdinal(st, key) {
3600
3772
  return ordinal;
3601
3773
  }
3602
3774
  function pathHasAsyncValidationByKey(st, key, segments) {
3775
+ if (st.schema.needsAsyncValidation?.() === false) return false;
3603
3776
  const cached = st.pathAsyncCache.get(key);
3604
3777
  if (cached !== void 0) return cached;
3605
3778
  const candidates = st.schema.getSchemasAtPath(segments);
@@ -3714,8 +3887,18 @@ function settleTransforms(st, path) {
3714
3887
  st.transformWaiters.push({ key, resolve });
3715
3888
  });
3716
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
+ }
3717
3899
  function touchFieldRecord(st, pathKey, path, patch) {
3718
3900
  const current = st.fields.get(pathKey);
3901
+ if (patch.updatedAt !== void 0) noteStamp(st, patch.updatedAt);
3719
3902
  st.fields.set(pathKey, {
3720
3903
  path,
3721
3904
  updatedAt: patch.updatedAt ?? current?.updatedAt ?? null,
@@ -3734,19 +3917,188 @@ function touchFieldRecord(st, pathKey, path, patch) {
3734
3917
  blurredAfterInteraction: patch.blurredAfterInteraction ?? current?.blurredAfterInteraction ?? false
3735
3918
  });
3736
3919
  }
3737
- function commitWritePatches(st, patches, meta) {
3738
- 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);
3739
3931
  for (const patch of patches) {
3740
- const { key } = canonicalizePath(patch.path);
3741
- 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)) {
3742
4055
  st.originals.set(key, { segments: patch.path, value: void 0 });
3743
4056
  }
3744
- touchFieldRecord(st, key, patch.path, { updatedAt: now });
3745
- st.pathSweep.track(patch.path, key);
3746
- for (let i = 1; i < patch.path.length; i++) {
3747
- const ancestor = patch.path.slice(0, i);
3748
- 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);
3749
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
+ }
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);
3750
4102
  }
3751
4103
  for (const listener of st.formChangeListeners) {
3752
4104
  try {
@@ -3756,33 +4108,41 @@ function commitWritePatches(st, patches, meta) {
3756
4108
  }
3757
4109
  }
3758
4110
  }
3759
- function applyFormReplacementWithPath(st, next, meta, arrayOpPath) {
4111
+ function applyFormReplacementWithPath(st, next, meta, structuralOp, now) {
3760
4112
  const prev = st.form.value;
3761
4113
  if (Object.is(prev, next)) return;
3762
4114
  const patches = [];
3763
4115
  diffAndApply(prev, next, [], (patch) => {
3764
4116
  patches.push(patch);
3765
4117
  });
3766
- 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) {
3767
4126
  st.form.value = next;
3768
4127
  } else if (patches.some(
3769
4128
  (p) => p.path.length > 0 && typeof p.path[0] === "string" && isShadowedKey(p.path[0])
3770
4129
  )) {
3771
4130
  triggerRef(st.form);
3772
4131
  }
3773
- commitWritePatches(st, patches, meta);
4132
+ commitWritePatches(st, patches, meta, structuralOp, now);
3774
4133
  }
3775
4134
  function applyFormReplacement(st, next, meta) {
3776
- applyFormReplacementWithPath(st, next, meta, null);
4135
+ applyFormReplacementWithPath(st, next, meta, null, writeInstant(st));
3777
4136
  }
3778
- function applyTargetedWrite(st, path, completedValue, meta) {
4137
+ function applyTargetedWrite(st, path, completedValue, meta, structuralOp, now) {
3779
4138
  const result = tryInPlaceLeafWrite(st.form.value, path, completedValue);
3780
4139
  if (!result.applied) {
3781
4140
  applyFormReplacementWithPath(
3782
4141
  st,
3783
4142
  setAtPathWithSchemaFill(st.form.value, st.schema, path, completedValue),
3784
4143
  meta,
3785
- meta?.arrayOp !== void 0 ? path : null
4144
+ structuralOp,
4145
+ now
3786
4146
  );
3787
4147
  return;
3788
4148
  }
@@ -3790,9 +4150,9 @@ function applyTargetedWrite(st, path, completedValue, meta) {
3790
4150
  diffAndApply(result.old, completedValue, path, (patch) => {
3791
4151
  patches.push(patch);
3792
4152
  });
3793
- commitWritePatches(st, patches, meta);
4153
+ commitWritePatches(st, patches, meta, null, now);
3794
4154
  }
3795
- function setValueAtPath(st, path, value, meta) {
4155
+ function setValueAtPath(st, path, value, meta, writeStamp) {
3796
4156
  if (st.effectiveDisabled.value) {
3797
4157
  if (!st.warnedDisabledWrite) {
3798
4158
  st.warnedDisabledWrite = true;
@@ -3871,7 +4231,8 @@ function setValueAtPath(st, path, value, meta) {
3871
4231
  value,
3872
4232
  variantDefault,
3873
4233
  void 0,
3874
- meta
4234
+ meta,
4235
+ writeStamp
3875
4236
  );
3876
4237
  }
3877
4238
  return reshapeUnionVariant(
@@ -3881,7 +4242,8 @@ function setValueAtPath(st, path, value, meta) {
3881
4242
  value,
3882
4243
  { [last]: value },
3883
4244
  void 0,
3884
- meta
4245
+ meta,
4246
+ writeStamp
3885
4247
  );
3886
4248
  }
3887
4249
  }
@@ -3905,7 +4267,8 @@ function setValueAtPath(st, path, value, meta) {
3905
4267
  discValue,
3906
4268
  variantDefault,
3907
4269
  valueRecord,
3908
- meta
4270
+ meta,
4271
+ writeStamp
3909
4272
  );
3910
4273
  }
3911
4274
  return reshapeUnionVariant(
@@ -3915,10 +4278,20 @@ function setValueAtPath(st, path, value, meta) {
3915
4278
  discValue,
3916
4279
  { [discKey]: discValue },
3917
4280
  void 0,
3918
- meta
4281
+ meta,
4282
+ writeStamp
3919
4283
  );
3920
4284
  }
3921
- 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
+ );
3922
4295
  }
3923
4296
  }
3924
4297
  }
@@ -3934,16 +4307,19 @@ function setValueAtPath(st, path, value, meta) {
3934
4307
  }
3935
4308
  }
3936
4309
  }
3937
- const wasAuthoredBefore = st.authoredPaths.has(pathKey);
3938
- if (arrayOpRemap !== null && Array.isArray(value)) {
3939
- if (path.length > 0) st.authoredPaths.add(pathKey);
3940
- for (const idx of arrayOpRemap.fresh) {
3941
- walkAuthoredFromConstraints(value[idx], [...path, idx], st.authoredPaths);
4310
+ let newlyAuthored = false;
4311
+ if (st.hasPreprocessOrCoerce) {
4312
+ const wasAuthoredBefore = st.authoredPaths.has(pathKey);
4313
+ if (arrayOpRemap !== null && Array.isArray(value)) {
4314
+ if (path.length > 0) st.authoredPaths.add(pathKey);
4315
+ for (const idx of arrayOpRemap.fresh) {
4316
+ walkAuthoredFromConstraints(value[idx], [...path, idx], st.authoredPaths);
4317
+ }
4318
+ } else {
4319
+ walkAuthoredFromConstraints(value, path, st.authoredPaths);
3942
4320
  }
3943
- } else {
3944
- walkAuthoredFromConstraints(value, path, st.authoredPaths);
4321
+ newlyAuthored = !wasAuthoredBefore && st.authoredPaths.has(pathKey);
3945
4322
  }
3946
- const newlyAuthored = !wasAuthoredBefore && st.authoredPaths.has(pathKey);
3947
4323
  let completedValue;
3948
4324
  if (arrayOpRemap !== null && Array.isArray(value)) {
3949
4325
  for (const idx of arrayOpRemap.fresh) {
@@ -3965,16 +4341,17 @@ function setValueAtPath(st, path, value, meta) {
3965
4341
  if (arrayOpRemap === null && Array.isArray(value) && Array.isArray(currentValue)) {
3966
4342
  st.arrayIdentity.realign(path);
3967
4343
  }
3968
- applyTargetedWrite(st, path, completedValue, meta);
3969
- if (arrayOpRemap !== null) {
3970
- st.arrayBookkeeping.applyStructuralOp(path, arrayOpRemap);
3971
- } 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)) {
3972
4354
  st.variantMemory.clearUnderPath(path);
3973
- st.arrayIdentity.realign(path);
3974
- } else if (isContainer(currentValue) && !isContainer(value)) {
3975
- if (subtreeHadRealBaseline(st, path, currentValue)) {
3976
- st.removedSubtrees.add(pathKey);
3977
- }
3978
4355
  }
3979
4356
  const effectiveModeAfterWrite = meta?.instance?.validateOn ?? st.fieldValidationMode;
3980
4357
  if (effectiveModeAfterWrite === "change") {
@@ -3982,7 +4359,7 @@ function setValueAtPath(st, path, value, meta) {
3982
4359
  }
3983
4360
  return true;
3984
4361
  }
3985
- function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variantDefault, consumerOverrides, meta) {
4362
+ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variantDefault, consumerOverrides, meta, writeStamp) {
3986
4363
  const sameDisc = Object.is(oldDiscValue, newDiscValue);
3987
4364
  const parentKey = canonicalizePath(parentPath).key;
3988
4365
  let baseline = variantDefault;
@@ -4048,7 +4425,7 @@ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variant
4048
4425
  appliedSync = true;
4049
4426
  }
4050
4427
  }
4051
- applyFormReplacement(st, nextForm, meta);
4428
+ applyFormReplacementWithPath(st, nextForm, meta, null, writeStamp ?? writeInstant(st));
4052
4429
  for (const k of newBlankPaths) st.blankPaths.add(k);
4053
4430
  if (reshapeMode === "change" && !appliedSync) {
4054
4431
  scheduleFieldValidation(st, parentPath, false, meta?.instance);
@@ -4069,7 +4446,9 @@ function scheduleFieldValidation(st, path, immediate, instance) {
4069
4446
  aborted: false,
4070
4447
  timer: null,
4071
4448
  settled: false,
4072
- released: false
4449
+ released: false,
4450
+ key,
4451
+ path
4073
4452
  };
4074
4453
  st.fieldValidationState.set(key, fresh);
4075
4454
  const myEpoch = ++st.scheduleEpoch;
@@ -4080,19 +4459,20 @@ function scheduleFieldValidation(st, path, immediate, instance) {
4080
4459
  try {
4081
4460
  st.activeValidations.value += 1;
4082
4461
  activeIncremented = true;
4083
- incFieldValidation(st, key);
4462
+ incFieldValidation(st, fresh.key);
4084
4463
  } catch (err) {
4085
4464
  if (activeIncremented) {
4086
4465
  st.activeValidations.value = Math.max(0, st.activeValidations.value - 1);
4087
4466
  }
4088
4467
  throw err;
4089
4468
  }
4090
- const subtreeScope = path.length > 0 && st.schema.hasContainerOrRootRefine?.() === false;
4091
- const scopePath = subtreeScope ? path : void 0;
4092
- const dataAtScope = subtreeScope ? getAtPath(st.form.value, path) : st.form.value;
4093
- const scopeKey = subtreeScope ? canonicalizePath(path).key : ROOT_PATH_KEY;
4094
- 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) => {
4095
4473
  if (fresh.aborted) return;
4474
+ const scopePath = subtreeScope ? fresh.path : void 0;
4475
+ const scopeKey = subtreeScope ? fresh.key : ROOT_PATH_KEY;
4096
4476
  if (myEpoch <= st.lastCommittedEpoch) return;
4097
4477
  st.lastCommittedEpoch = myEpoch;
4098
4478
  if (effectiveMode === "blur") {
@@ -4103,14 +4483,14 @@ function scheduleFieldValidation(st, path, immediate, instance) {
4103
4483
  const filtered = filterAuthoredErrors(st, errors);
4104
4484
  const restamped = subtreeScope ? filtered.map((err) => ({
4105
4485
  ...err,
4106
- path: [...path, ...err.path]
4486
+ path: [...scopePath ?? [], ...err.path]
4107
4487
  })) : filtered;
4108
4488
  applySchemaErrorsForSubtree(st, scopePath ?? [], restamped);
4109
4489
  }).catch(() => {
4110
4490
  }).finally(() => {
4111
4491
  if (!fresh.released) {
4112
4492
  st.activeValidations.value = Math.max(0, st.activeValidations.value - 1);
4113
- decFieldValidation(st, key);
4493
+ decFieldValidation(st, fresh.key);
4114
4494
  }
4115
4495
  fresh.settled = true;
4116
4496
  });
@@ -4149,6 +4529,19 @@ function cancelFieldValidationUnder(st, prefix) {
4149
4529
  st.fieldValidationState.delete(key);
4150
4530
  }
4151
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
+ }
4152
4545
  function onFormChange(st, listener) {
4153
4546
  st.formChangeListeners.add(listener);
4154
4547
  return () => {
@@ -4200,22 +4593,38 @@ function getValueAtPath(st, path) {
4200
4593
  return getAtPath(st.form.value, path);
4201
4594
  }
4202
4595
  const ERROR_SOURCES = ["schema", "user"];
4596
+ function createErrorCells(schema, pristine) {
4597
+ const raw = /* @__PURE__ */ new Map();
4598
+ const cells = shallowReactive(raw);
4599
+ return (seed) => {
4600
+ const data = pristine;
4601
+ if (data !== void 0) {
4602
+ pristine = void 0;
4603
+ if (seed) {
4604
+ for (const [key, list] of groupErrorsByKey(schema.validateSync(data))) {
4605
+ raw.set(key, { schema: list, user: NO_ERRORS });
4606
+ }
4607
+ }
4608
+ }
4609
+ return cells;
4610
+ };
4611
+ }
4203
4612
  function setErrorChannelForKey(st, key, src, entries) {
4204
- const current = st.errorCells.get(key);
4613
+ const current = st.errorCells().get(key);
4205
4614
  const schema = src === "schema" ? entries : current?.schema ?? NO_ERRORS;
4206
4615
  const user = src === "user" ? entries : current?.user ?? NO_ERRORS;
4207
4616
  if (schema.length === 0 && user.length === 0) {
4208
- if (current !== void 0) st.errorCells.delete(key);
4617
+ if (current !== void 0) st.errorCells().delete(key);
4209
4618
  return;
4210
4619
  }
4211
- st.errorCells.set(key, { schema, user });
4620
+ st.errorCells().set(key, { schema, user });
4212
4621
  }
4213
4622
  function replaceErrorChannel(st, src, entries) {
4214
4623
  const other = src === "schema" ? "user" : "schema";
4215
4624
  const grouped = groupErrorsByKey(entries);
4216
- for (const [key, cell] of st.errorCells) {
4625
+ for (const [key, cell] of st.errorCells()) {
4217
4626
  if (cell[other].length === 0) {
4218
- st.errorCells.delete(key);
4627
+ st.errorCells().delete(key);
4219
4628
  continue;
4220
4629
  }
4221
4630
  const fresh = grouped.get(key);
@@ -4240,8 +4649,9 @@ function clearErrorChannel(st, src, path) {
4240
4649
  function applySchemaErrorsForSubtree(st, path, entries) {
4241
4650
  const parentKey = canonicalizePath(path).key;
4242
4651
  const grouped = groupErrorsByKey(entries);
4652
+ if (path.length === 0) st.skipErrorSeed();
4243
4653
  if (!grouped.has(parentKey)) setErrorChannelForKey(st, parentKey, "schema", NO_ERRORS);
4244
- for (const [existingKey, cell] of st.errorCells) {
4654
+ for (const [existingKey, cell] of st.errorCells()) {
4245
4655
  if (existingKey === parentKey) continue;
4246
4656
  if (cell.schema.length === 0) continue;
4247
4657
  if (isPathKeyUnder(existingKey, path) && !grouped.has(existingKey)) {
@@ -4253,15 +4663,45 @@ function applySchemaErrorsForSubtree(st, path, entries) {
4253
4663
  }
4254
4664
  }
4255
4665
  function restoreErrorCells(st, entries) {
4256
- st.errorCells.clear();
4666
+ st.skipErrorSeed().clear();
4257
4667
  for (const [key, cell] of entries) {
4258
4668
  if (cell.schema.length === 0 && cell.user.length === 0) continue;
4259
- st.errorCells.set(key, { schema: [...cell.schema], user: [...cell.user] });
4669
+ st.errorCells().set(key, { schema: [...cell.schema], user: [...cell.user] });
4670
+ }
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
+ }
4260
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);
4261
4701
  }
4262
4702
  function getErrorsForPath(st, path) {
4263
4703
  const { key } = canonicalizePath(path);
4264
- const cell = st.errorCells.get(key);
4704
+ const cell = st.errorCells().get(key);
4265
4705
  const blankForKey = st.derivedBlankErrors.value.get(key);
4266
4706
  if (cell === void 0 && blankForKey === void 0) {
4267
4707
  return [];
@@ -4283,6 +4723,7 @@ function noteDomConnected(st, path) {
4283
4723
  }
4284
4724
  function noteDomDisconnected(st, path) {
4285
4725
  const { key } = canonicalizePath(path);
4726
+ if (!st.fields.has(key)) return;
4286
4727
  touchFieldRecord(st, key, path, { connected: false, focused: null, blurred: null });
4287
4728
  }
4288
4729
  function markConnectedOptimistically(st, path) {
@@ -4346,7 +4787,7 @@ function touchAtPath(st, segments) {
4346
4787
  const formValue = st.form.value;
4347
4788
  let touchedAny = false;
4348
4789
  for (const [leafKey, entry] of st.originals) {
4349
- if (!isPathPrefix(segments, entry.segments)) continue;
4790
+ if (!isPathPrefix(segments, entry.segments) || isDescendable(entry.value)) continue;
4350
4791
  if (!hasAtPath(formValue, entry.segments)) continue;
4351
4792
  touchedAny = true;
4352
4793
  const current = st.fields.get(leafKey);
@@ -4364,7 +4805,7 @@ function interactAtPath(st, segments) {
4364
4805
  const formValue = st.form.value;
4365
4806
  let interactedAny = false;
4366
4807
  for (const [leafKey, entry] of st.originals) {
4367
- if (!isPathPrefix(segments, entry.segments)) continue;
4808
+ if (!isPathPrefix(segments, entry.segments) || isDescendable(entry.value)) continue;
4368
4809
  if (!hasAtPath(formValue, entry.segments)) continue;
4369
4810
  interactedAny = true;
4370
4811
  const current = st.fields.get(leafKey);
@@ -4423,7 +4864,14 @@ function adoptResolvedDefaults(st, value) {
4423
4864
  st.schema
4424
4865
  )
4425
4866
  );
4426
- seedOriginalsFromBaseline(st, computeBaselineResponse(st.schema, st.defaultValues).data, false);
4867
+ seedOriginalsFromBaseline(
4868
+ st,
4869
+ computeBaseline(
4870
+ st.schema,
4871
+ st.defaultValues,
4872
+ st.schema.getDefaultValues({ useDefaultSchemaValues: true })
4873
+ )
4874
+ );
4427
4875
  }
4428
4876
  function reset(st, nextDefaultValues) {
4429
4877
  const resetSource = nextDefaultValues === void 0 ? st.defaultValues : mergeSparseHydration(
@@ -4432,33 +4880,35 @@ function reset(st, nextDefaultValues) {
4432
4880
  st.schema
4433
4881
  );
4434
4882
  st.defaultValues = structuralSnapshot(resetSource);
4435
- const resetResponse = computeBaselineResponse(st.schema, resetSource);
4436
- const next = resetResponse.data;
4883
+ const next = computeBaseline(
4884
+ st.schema,
4885
+ resetSource,
4886
+ st.schema.getDefaultValues({ useDefaultSchemaValues: true })
4887
+ );
4437
4888
  rebuildAuthoredPaths(st, resetSource, next);
4438
- applyFormReplacement(st, next);
4439
- st.arrayIdentity.rebaselineAll();
4440
- st.removedSubtrees.clear();
4441
- seedOriginalsFromBaseline(st, next, false);
4442
4889
  if (nextDefaultValues !== void 0) {
4443
4890
  const mentioned = /* @__PURE__ */ new Set();
4444
4891
  walkAuthoredFromConstraints(nextDefaultValues, [], mentioned);
4445
4892
  for (const key of mentioned) st.originalBlankPaths.delete(key);
4446
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);
4447
4903
  st.blankPaths.clear();
4448
4904
  for (const key of st.originalBlankPaths) {
4449
4905
  st.blankPaths.add(key);
4450
4906
  }
4451
- st.errorCells.clear();
4452
- if (!resetResponse.success) {
4453
- replaceErrorChannel(st, "schema", resetResponse.errors);
4454
- }
4455
- const syncResult = st.schema.validateAtPath(st.form.value, void 0, { sync: true });
4456
- if (!(syncResult instanceof Promise) && !syncResult.success) {
4457
- applySchemaErrorsForSubtree(st, [], syncResult.errors);
4458
- }
4907
+ st.skipErrorSeed().clear();
4908
+ replaceErrorChannel(st, "schema", st.schema.validateSync(next));
4459
4909
  st.firstValidationDone.value = initialFirstValidationGate(st.schema);
4460
4910
  queueInitialAsyncValidation(st);
4461
- const now = (/* @__PURE__ */ new Date()).toISOString();
4911
+ noteStamp(st, now);
4462
4912
  for (const [pathKey, record] of st.fields) {
4463
4913
  st.fields.set(pathKey, withClearedHistoryFlags(record, now));
4464
4914
  }
@@ -4487,6 +4937,7 @@ function reset(st, nextDefaultValues) {
4487
4937
  }
4488
4938
  function resetField(st, path) {
4489
4939
  const { key: targetKey, segments: targetSegments } = canonicalizePath(path);
4940
+ const now = writeInstant(st);
4490
4941
  st.variantMemory.clearUnderPath(targetSegments);
4491
4942
  cancelFieldValidationUnder(st, targetSegments);
4492
4943
  cancelTransformsUnder(st, targetSegments);
@@ -4495,9 +4946,21 @@ function resetField(st, path) {
4495
4946
  if (segs === null) continue;
4496
4947
  if (isPathPrefix(targetSegments, segs)) st.pathSnapshots.delete(snapKey);
4497
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
+ }
4498
4955
  const leafEntry = st.originals.get(targetKey);
4499
4956
  if (leafEntry !== void 0) {
4500
- 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
+ );
4501
4964
  if (!wrote) {
4502
4965
  console.error(
4503
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.`
@@ -4515,10 +4978,10 @@ function resetField(st, path) {
4515
4978
  if (subtree === void 0) {
4516
4979
  subtree = typeof relative[0] === "number" ? [] : {};
4517
4980
  }
4518
- subtree = setAtPath(subtree, relative, entry.value);
4981
+ subtree = setAtPath(subtree, relative, structuralSnapshot(entry.value));
4519
4982
  }
4520
4983
  if (anyMatch) {
4521
- const wroteSubtree = setValueAtPath(st, targetSegments, subtree);
4984
+ const wroteSubtree = setValueAtPath(st, targetSegments, subtree, void 0, now);
4522
4985
  if (!wroteSubtree) {
4523
4986
  console.error(
4524
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.`
@@ -4527,12 +4990,18 @@ function resetField(st, path) {
4527
4990
  }
4528
4991
  }
4529
4992
  deleteErrorCellsUnderPrefix(st, targetSegments);
4530
- for (const [fieldKey, record] of Array.from(st.fields.entries())) {
4531
- 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);
4532
5001
  }
4533
5002
  }
4534
5003
  function deleteErrorCellsUnderPrefix(st, prefix) {
4535
- for (const [errorKey, cell] of st.errorCells) {
5004
+ for (const [errorKey, cell] of st.errorCells()) {
4536
5005
  for (const src of ERROR_SOURCES) {
4537
5006
  const first = cell[src][0];
4538
5007
  if (first !== void 0 && isPathPrefix(prefix, first.path)) {
@@ -4541,36 +5010,35 @@ function deleteErrorCellsUnderPrefix(st, prefix) {
4541
5010
  }
4542
5011
  }
4543
5012
  }
4544
- function clearFieldRecordFlags(st, pathKey) {
4545
- const record = st.fields.get(pathKey);
4546
- if (record === void 0) return;
4547
- st.fields.set(pathKey, withClearedHistoryFlags(record, (/* @__PURE__ */ new Date()).toISOString()));
4548
- }
4549
5013
  function isPristineAtPathByKey(st, key, segments) {
4550
5014
  if (st.blankPaths.has(key) !== st.originalBlankPaths.has(key)) return false;
4551
5015
  const entry = st.originals.get(key);
4552
5016
  if (entry === void 0) return true;
4553
5017
  return Object.is(getAtPath(st.form.value, segments), entry.value);
4554
5018
  }
4555
- function hasStructuralChangeUnder(st, path) {
5019
+ function hasStructuralChangeUnder(st, path, key) {
5020
+ subscribeStructure(st.structureSignal, key);
4556
5021
  return st.arrayIdentity.hasStructuralChangeUnder(path);
4557
5022
  }
4558
- function subtreeHadRealBaseline(st, prefix, removedValue) {
4559
- let had = false;
4560
- diffAndApply(removedValue, void 0, prefix, (patch) => {
4561
- if (had || patch.kind !== "removed") return;
4562
- const record = st.originals.get(canonicalizePath(patch.path).key);
4563
- 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);
4564
5029
  });
4565
- return had;
4566
5030
  }
4567
- function hasRemovedSubtreeUnder(st, prefix) {
4568
- if (st.removedSubtrees.size === 0) return false;
4569
- for (const key of st.removedSubtrees) {
4570
- const segments = segmentsForPathKey(key);
4571
- 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()) {
4572
5040
  if (!isPathPrefix(prefix, segments)) continue;
4573
- if (isContainer(getAtPath(toRaw(st.form.value), segments))) continue;
5041
+ if (hasAtPath(raw, segments)) continue;
4574
5042
  return true;
4575
5043
  }
4576
5044
  return false;
@@ -4597,8 +5065,8 @@ function createFormStore(options) {
4597
5065
  const fieldValidatingSince = reactive(/* @__PURE__ */ new Map());
4598
5066
  const displayEngine = createDisplayEngine(ssr);
4599
5067
  cleanupHooks.push(() => displayEngine.dispose());
4600
- const schemaResponse = computeBaselineResponse(schema, defaultValues);
4601
- const schemaInitialData = schemaResponse.data;
5068
+ const ownDefaultValues = structuralSnapshot(defaultValues);
5069
+ const schemaInitialData = computeBaseline(schema, ownDefaultValues, options.schemaDefaults);
4602
5070
  const authoredPaths = /* @__PURE__ */ new Set();
4603
5071
  const initialData = hydration !== void 0 ? hydration.form : structuralSnapshot(schemaInitialData);
4604
5072
  const hasDU = schema.hasDiscriminatedUnions?.() !== false;
@@ -4606,15 +5074,23 @@ function createFormStore(options) {
4606
5074
  warn: true
4607
5075
  }) : initialData;
4608
5076
  const form = ref(stubbedInitialData);
4609
- const arrayIdentity = createArrayIdentity((arraySegs) => {
4610
- const v = getAtPath(toRaw(form.value), arraySegs);
4611
- return Array.isArray(v) ? v.length : 0;
4612
- });
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
+ );
4613
5085
  const fields = shallowReactive(/* @__PURE__ */ new Map());
4614
5086
  const domBinding = shallowRef(null);
4615
- const errorCells = shallowReactive(/* @__PURE__ */ new Map());
5087
+ const errorStore = createErrorCells(
5088
+ schema,
5089
+ hydration === void 0 ? schemaInitialData : void 0
5090
+ );
5091
+ const errorCells = () => errorStore(true);
4616
5092
  const originals = shallowReactive(/* @__PURE__ */ new Map());
4617
- const removedSubtrees = /* @__PURE__ */ new Set();
5093
+ const removedPaths = /* @__PURE__ */ new Map();
4618
5094
  const blankPaths = reactive(/* @__PURE__ */ new Set());
4619
5095
  const originalBlankPaths = /* @__PURE__ */ new Set();
4620
5096
  const seededBlankPaths = hydration !== void 0 ? (hydration.blankPaths ?? []).map((dotted) => canonicalizePath(dotted).key) : options.initialBlankPaths ?? [];
@@ -4636,7 +5112,7 @@ function createFormStore(options) {
4636
5112
  return result;
4637
5113
  });
4638
5114
  const errorPathIndex = computed(
4639
- () => buildErrorPathIndex(errorCells, derivedBlankErrors.value)
5115
+ () => buildErrorPathIndex(errorCells(), derivedBlankErrors.value)
4640
5116
  );
4641
5117
  const submitting = ref(false);
4642
5118
  const activeSubmissions = ref(0);
@@ -4723,6 +5199,8 @@ function createFormStore(options) {
4723
5199
  blankPaths,
4724
5200
  originalBlankPaths,
4725
5201
  authoredPaths,
5202
+ removedPaths,
5203
+ notifyStructure: (paths) => pulseStructure(structureSignal, paths),
4726
5204
  fieldValidationCounts,
4727
5205
  fieldValidatingSince,
4728
5206
  fieldValidationState,
@@ -4730,6 +5208,9 @@ function createFormStore(options) {
4730
5208
  arrayIdentity,
4731
5209
  variantMemory,
4732
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),
4733
5214
  decFieldValidation: (key) => decFieldValidation(st, key)
4734
5215
  });
4735
5216
  const bind = (fn) => (...args) => fn(st, ...args);
@@ -4776,18 +5257,16 @@ function createFormStore(options) {
4776
5257
  blankPaths,
4777
5258
  originalBlankPaths,
4778
5259
  // --- kernel-internal state ---
4779
- // A defensive copy. `getDefaultValues` building a fresh tree is an adapter
4780
- // implementation detail, not a contract, and this field is durable state
4781
- // that every `reset()` reads, so it must not depend on one. The copy also
4782
- // stops a consumer holding a reference to the literal they passed from
4783
- // mutating the form's defaults from outside. `reset()` snapshots for a
4784
- // harder reason, where an alias IS reachable.
4785
- defaultValues: structuralSnapshot(defaultValues),
5260
+ // The copy taken above, which also stops a consumer holding a reference to
5261
+ // the literal they passed from mutating the form's defaults from outside.
5262
+ // `reset()` snapshots for a harder reason, where an alias IS reachable.
5263
+ defaultValues: ownDefaultValues,
4786
5264
  ssrPrefetch,
4787
5265
  rememberVariants,
4788
5266
  fieldValidationMode,
4789
5267
  fieldValidationDebounceMs,
4790
5268
  hasDU,
5269
+ hasPreprocessOrCoerce: schema.hasPreprocessOrCoerce?.() !== false,
4791
5270
  fieldValidationState,
4792
5271
  formChangeListeners,
4793
5272
  submitSuccessListeners,
@@ -4795,7 +5274,8 @@ function createFormStore(options) {
4795
5274
  cleanupHooks,
4796
5275
  authoredPaths,
4797
5276
  arrayIdentity,
4798
- removedSubtrees,
5277
+ removedPaths,
5278
+ structureSignal,
4799
5279
  variantMemory,
4800
5280
  pathOrdinals,
4801
5281
  pathSnapshots,
@@ -4803,7 +5283,9 @@ function createFormStore(options) {
4803
5283
  transformRuns,
4804
5284
  transformWaiters,
4805
5285
  arrayBookkeeping,
5286
+ skipErrorSeed: () => errorStore(false),
4806
5287
  nextOrdinal: 0,
5288
+ latestStamp: "",
4807
5289
  scheduleEpoch: 0,
4808
5290
  lastCommittedEpoch: 0,
4809
5291
  transformTokenSeq: 0,
@@ -4841,6 +5323,8 @@ function createFormStore(options) {
4841
5323
  ),
4842
5324
  clearUserErrors: (path) => clearErrorChannel(st, "user", path),
4843
5325
  restoreErrorCells: bind(restoreErrorCells),
5326
+ captureStructure: bind(captureStructure),
5327
+ restoreStructure: bind(restoreStructure),
4844
5328
  getErrorsForPath: bind(getErrorsForPath),
4845
5329
  ensurePathOrdinal: bind(ensurePathOrdinal),
4846
5330
  noteDomConnected: bind(noteDomConnected),
@@ -4870,7 +5354,26 @@ function createFormStore(options) {
4870
5354
  dispose: bind(dispose)
4871
5355
  };
4872
5356
  rebuildAuthoredPaths(st, defaultValues, schemaInitialData);
4873
- seedOriginalsFromBaseline(st, schemaInitialData, true);
5357
+ const initStamp = (/* @__PURE__ */ new Date()).toISOString();
5358
+ diffAndApply({}, schemaInitialData, [], (patch) => {
5359
+ if (patch.kind !== "added") return;
5360
+ const { key } = canonicalizePath(patch.path);
5361
+ if (seedBaseline(originals, key, patch)) return;
5362
+ ensurePathOrdinal(st, key);
5363
+ if (hydration === void 0) {
5364
+ fields.set(key, {
5365
+ path: patch.path,
5366
+ updatedAt: initStamp,
5367
+ connected: false,
5368
+ focused: null,
5369
+ blurred: null,
5370
+ touched: false,
5371
+ interacted: false,
5372
+ blurredAfterInteraction: false
5373
+ });
5374
+ }
5375
+ });
5376
+ if (fields.size > 0) noteStamp(st, initStamp);
4874
5377
  if (hydration !== void 0) {
4875
5378
  for (const [rawKey, record] of hydration.fields) {
4876
5379
  if (typeof rawKey !== "string" || !isHydratedFieldRecord(record)) {
@@ -4878,6 +5381,7 @@ function createFormStore(options) {
4878
5381
  continue;
4879
5382
  }
4880
5383
  fields.set(rawKey, record);
5384
+ noteStamp(st, record.updatedAt);
4881
5385
  }
4882
5386
  for (const [rawKey, errs] of hydration.schemaErrors) {
4883
5387
  if (typeof rawKey !== "string" || !isHydratedValidationErrorArray(errs)) {
@@ -4893,25 +5397,6 @@ function createFormStore(options) {
4893
5397
  }
4894
5398
  setErrorChannelForKey(st, rawKey, "user", errs);
4895
5399
  }
4896
- } else {
4897
- const initStamp = (/* @__PURE__ */ new Date()).toISOString();
4898
- diffAndApply({}, initialData, [], (patch) => {
4899
- if (patch.kind !== "added") return;
4900
- const { key } = canonicalizePath(patch.path);
4901
- fields.set(key, {
4902
- path: patch.path,
4903
- updatedAt: initStamp,
4904
- connected: false,
4905
- focused: null,
4906
- blurred: null,
4907
- touched: false,
4908
- interacted: false,
4909
- blurredAfterInteraction: false
4910
- });
4911
- });
4912
- if (!schemaResponse.success) {
4913
- replaceErrorChannel(st, "schema", schemaResponse.errors);
4914
- }
4915
5400
  }
4916
5401
  queueInitialAsyncValidation(st);
4917
5402
  return st;
@@ -5009,9 +5494,11 @@ const HISTORY_MODULE_KEY = "history";
5009
5494
  function buildFreshState(key, schema, configuration, registry) {
5010
5495
  const pending = registry.pendingHydration.get(key);
5011
5496
  if (pending !== void 0) registry.pendingHydration.delete(key);
5497
+ const schemaDefaults = schema.getDefaultValues({ useDefaultSchemaValues: true });
5012
5498
  const walked = walkUnsetSentinels(
5013
5499
  configuration.defaultValues,
5014
- schema
5500
+ schema,
5501
+ schemaDefaults
5015
5502
  );
5016
5503
  let initialBlankPaths;
5017
5504
  if (pending === void 0) {
@@ -5021,6 +5508,7 @@ function buildFreshState(key, schema, configuration, registry) {
5021
5508
  formKey: key,
5022
5509
  schema,
5023
5510
  defaultValues: walked.cleanedValues,
5511
+ schemaDefaults,
5024
5512
  hydration: pending,
5025
5513
  ssr: registry.ssr,
5026
5514
  ...pickDefined({
@@ -5084,6 +5572,7 @@ function resolveFormKey(key) {
5084
5572
  }
5085
5573
 
5086
5574
  let injectedInstanceCounter = 0;
5575
+ const sharedApis = /* @__PURE__ */ new WeakMap();
5087
5576
  function injectForm(input) {
5088
5577
  const key = typeof input === "string" ? input : input?.key;
5089
5578
  const ssrAccessed = typeof input === "object" && input !== null ? input.__ssrAccessed === true : false;
@@ -5106,12 +5595,37 @@ function injectForm(input) {
5106
5595
  apiOptions.history = history;
5107
5596
  }
5108
5597
  const ambientInstanceId = getCurrentInstance() !== null ? inject(kFormInstanceId, null) : null;
5109
- const formInstanceId = ambientInstanceId ?? (getCurrentInstance() !== null ? useId() : `atta:form-instance-injected:${injectedInstanceCounter++}`);
5110
- return buildFormApi(
5598
+ const api = ambientInstanceId !== null ? shareApi(state, ambientInstanceId, apiOptions) : buildFormApi(
5111
5599
  state,
5112
- formInstanceId,
5600
+ getCurrentInstance() !== null ? useId() : `atta:form-instance-injected:${injectedInstanceCounter++}`,
5113
5601
  apiOptions
5114
5602
  );
5603
+ return api;
5604
+ }
5605
+ function shareApi(state, formInstanceId, options) {
5606
+ let instances = sharedApis.get(state);
5607
+ if (instances === void 0) {
5608
+ instances = /* @__PURE__ */ new Map();
5609
+ sharedApis.set(state, instances);
5610
+ }
5611
+ const byInstance = instances;
5612
+ let shared = byInstance.get(formInstanceId);
5613
+ if (shared === void 0) {
5614
+ const scope = effectScope(true);
5615
+ const api = scope.run(() => buildFormApi(state, formInstanceId, options));
5616
+ if (api === void 0) return buildFormApi(state, formInstanceId, options);
5617
+ shared = { api, scope, users: 0 };
5618
+ byInstance.set(formInstanceId, shared);
5619
+ }
5620
+ const entry = shared;
5621
+ entry.users += 1;
5622
+ onScopeDispose(() => {
5623
+ entry.users -= 1;
5624
+ if (entry.users > 0) return;
5625
+ entry.scope.stop();
5626
+ byInstance.delete(formInstanceId);
5627
+ });
5628
+ return entry.api;
5115
5629
  }
5116
5630
  function resolveState(key, registry) {
5117
5631
  if (key !== void 0) {
@@ -5206,22 +5720,23 @@ function useRegister(options) {
5206
5720
  const capturedRegisterValue = shallowRef(void 0);
5207
5721
  const refreshAndStripBridgeAttrs = () => {
5208
5722
  const rawAttrs = instance.attrs;
5723
+ const parentBinding = instance.vnode.dirs?.find(
5724
+ (dir) => dir.dir?.[V_REGISTER_MARKER] === true
5725
+ );
5209
5726
  if ("registerValue" in rawAttrs) {
5210
5727
  capturedRegisterValue.value = rawAttrs["registerValue"];
5211
5728
  delete rawAttrs["registerValue"];
5212
- if (capturedRegisterValue.value !== void 0) armDomBinding(capturedRegisterValue.value);
5213
- } else {
5214
- const dirs = instance.vnode.dirs;
5215
- if (dirs !== null && dirs !== void 0) {
5216
- for (const dir of dirs) {
5217
- const marked = dir.dir?.[V_REGISTER_MARKER];
5218
- if (marked === true) {
5219
- capturedRegisterValue.value = dir.value;
5220
- if (capturedRegisterValue.value !== void 0)
5221
- armDomBinding(capturedRegisterValue.value);
5222
- break;
5223
- }
5224
- }
5729
+ } else if (parentBinding !== void 0) {
5730
+ capturedRegisterValue.value = parentBinding.value;
5731
+ }
5732
+ const captured = capturedRegisterValue.value;
5733
+ if (captured !== void 0) {
5734
+ armDomBinding(captured);
5735
+ if (parentBinding !== void 0) {
5736
+ recordInheritedModifiers(
5737
+ captured,
5738
+ withInheritedModifiers(parentBinding.value, parentBinding.modifiers)
5739
+ );
5225
5740
  }
5226
5741
  }
5227
5742
  if ("value" in rawAttrs) delete rawAttrs["value"];
@@ -5347,11 +5862,11 @@ const NOOP_SUCCESS = {
5347
5862
  data: EMPTY_VALUE,
5348
5863
  errors: void 0
5349
5864
  };
5350
- const NOOP_DEFAULTS = NOOP_SUCCESS;
5351
5865
  let NOOP_SCHEMA;
5352
5866
  function buildNoopWizardSchema() {
5353
5867
  NOOP_SCHEMA ?? (NOOP_SCHEMA = {
5354
- getDefaultValues: () => NOOP_DEFAULTS,
5868
+ getDefaultValues: () => EMPTY_VALUE,
5869
+ validateSync: () => [],
5355
5870
  getDefaultAtPath: () => void 0,
5356
5871
  getEmptyValueAtPath: () => void 0,
5357
5872
  isPreprocessOrCoerceLeaf: () => false,
@@ -5367,7 +5882,8 @@ function buildNoopWizardSchema() {
5367
5882
  isLeafAtPath: () => false,
5368
5883
  isRequiredAtPath: () => false,
5369
5884
  getUnionDiscriminatorAtPath: () => void 0,
5370
- hasDiscriminatedUnions: () => false
5885
+ hasDiscriminatedUnions: () => false,
5886
+ hasPreprocessOrCoerce: () => false
5371
5887
  });
5372
5888
  return NOOP_SCHEMA;
5373
5889
  }
@@ -5443,7 +5959,7 @@ function buildWizardStatusesProxy(statuses) {
5443
5959
  // resolves to `undefined` (consistent with property-access).
5444
5960
  resolveCall: (arg) => statuses[String(arg)]?.value,
5445
5961
  ownKeys: () => Object.keys(statuses),
5446
- hasKey: (key) => Object.hasOwn(statuses, key)
5962
+ hasKey: (key) => safeOwnHas(statuses, key)
5447
5963
  });
5448
5964
  }
5449
5965
 
@@ -6371,7 +6887,7 @@ function useWizard(options) {
6371
6887
  for (const key of keys) {
6372
6888
  const store = registry.forms.get(key);
6373
6889
  if (store === void 0) continue;
6374
- for (const cell of store.errorCells.values()) {
6890
+ for (const cell of store.errorCells().values()) {
6375
6891
  for (const err of cell.user) out.push(toWizardAggregateError(err, key));
6376
6892
  }
6377
6893
  }