attaform 0.21.2 → 0.23.0

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 (101) hide show
  1. package/README.md +7 -10
  2. package/dist/chunks/dev-key-collision-warnings.cjs +0 -33
  3. package/dist/chunks/dev-key-collision-warnings.cjs.map +1 -1
  4. package/dist/chunks/dev-key-collision-warnings.mjs +1 -33
  5. package/dist/chunks/dev-key-collision-warnings.mjs.map +1 -1
  6. package/dist/chunks/devtools.cjs +3 -5
  7. package/dist/chunks/devtools.cjs.map +1 -1
  8. package/dist/chunks/devtools.mjs +3 -5
  9. package/dist/chunks/devtools.mjs.map +1 -1
  10. package/dist/chunks/fingerprint2.cjs +1 -1
  11. package/dist/chunks/fingerprint2.mjs +1 -1
  12. package/dist/index.cjs +3 -5
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +6 -41
  15. package/dist/index.d.mts +6 -41
  16. package/dist/index.d.ts +6 -41
  17. package/dist/index.mjs +5 -5
  18. package/dist/nuxt.d.cts +1 -1
  19. package/dist/nuxt.d.mts +1 -1
  20. package/dist/nuxt.d.ts +1 -1
  21. package/dist/runtime/components/AttaformDevtoolsPanel.vue +3 -11
  22. package/dist/runtime/plugins/attaform.cjs +2 -2
  23. package/dist/runtime/plugins/attaform.mjs +2 -2
  24. package/dist/shared/{attaform.BGf_J22U.d.ts → attaform.BGMRvckW.d.ts} +11 -70
  25. package/dist/shared/{attaform.ory-3WhV.d.mts → attaform.BJnNK75Y.d.cts} +41 -491
  26. package/dist/shared/{attaform.ory-3WhV.d.ts → attaform.BJnNK75Y.d.mts} +41 -491
  27. package/dist/shared/{attaform.ory-3WhV.d.cts → attaform.BJnNK75Y.d.ts} +41 -491
  28. package/dist/shared/{attaform.DP-u7_tk.mjs → attaform.BhI9Icek.mjs} +17 -291
  29. package/dist/shared/attaform.BhI9Icek.mjs.map +1 -0
  30. package/dist/shared/{attaform.BwLp9KM7.cjs → attaform.BibT5AS_.cjs} +2 -2
  31. package/dist/shared/{attaform.BwLp9KM7.cjs.map → attaform.BibT5AS_.cjs.map} +1 -1
  32. package/dist/shared/{attaform.DkA5J8NW.d.cts → attaform.CO0e7YVY.d.cts} +1 -46
  33. package/dist/shared/{attaform.DkA5J8NW.d.ts → attaform.CO0e7YVY.d.mts} +1 -46
  34. package/dist/shared/{attaform.DkA5J8NW.d.mts → attaform.CO0e7YVY.d.ts} +1 -46
  35. package/dist/shared/{attaform.BwrowMp2.cjs → attaform.CaYj3ZfY.cjs} +3 -3
  36. package/dist/shared/{attaform.BwrowMp2.cjs.map → attaform.CaYj3ZfY.cjs.map} +1 -1
  37. package/dist/shared/{attaform.BBDIKtKY.cjs → attaform.Cmb_LCie.cjs} +4 -4
  38. package/dist/shared/{attaform.BVeLgfEh.mjs.map → attaform.Cmb_LCie.cjs.map} +1 -1
  39. package/dist/shared/{attaform.CTheKoTc.mjs → attaform.CtJOd7ox.mjs} +446 -525
  40. package/dist/shared/attaform.CtJOd7ox.mjs.map +1 -0
  41. package/dist/shared/{attaform.CrD73S4m.mjs → attaform.CzVta5o2.mjs} +116 -47
  42. package/dist/shared/attaform.CzVta5o2.mjs.map +1 -0
  43. package/dist/shared/{attaform.CnEl--PF.d.mts → attaform.D52oJiYC.d.cts} +1 -1
  44. package/dist/shared/{attaform.BoY6RZUl.d.cts → attaform.DCkSNnPr.d.mts} +1 -1
  45. package/dist/shared/{attaform.B5LNzqQh.cjs → attaform.Db4E4IW6.cjs} +18 -297
  46. package/dist/shared/attaform.Db4E4IW6.cjs.map +1 -0
  47. package/dist/shared/{attaform.CcnF1AKJ.cjs → attaform.DbyTD8N2.cjs} +116 -47
  48. package/dist/shared/attaform.DbyTD8N2.cjs.map +1 -0
  49. package/dist/shared/{attaform.D6GYGshL.mjs → attaform.Dd1Kmmaj.mjs} +3 -3
  50. package/dist/shared/{attaform.D6GYGshL.mjs.map → attaform.Dd1Kmmaj.mjs.map} +1 -1
  51. package/dist/shared/{attaform.BCcrLApm.d.mts → attaform.DrY8srOp.d.mts} +11 -70
  52. package/dist/shared/{attaform.D2ZuIOCf.cjs → attaform.DsQkXE3o.cjs} +445 -534
  53. package/dist/shared/attaform.DsQkXE3o.cjs.map +1 -0
  54. package/dist/shared/{attaform.BkjJfMvJ.d.cts → attaform.DuPneYR0.d.cts} +11 -70
  55. package/dist/shared/{attaform.C41gjp-a.mjs → attaform.Dx9-QQE2.mjs} +2 -2
  56. package/dist/shared/{attaform.C41gjp-a.mjs.map → attaform.Dx9-QQE2.mjs.map} +1 -1
  57. package/dist/shared/{attaform.BYgioWLF.d.ts → attaform.WEwfXcHq.d.ts} +1 -1
  58. package/dist/shared/{attaform.BVeLgfEh.mjs → attaform.alpG7rT7.mjs} +4 -4
  59. package/dist/shared/{attaform.BBDIKtKY.cjs.map → attaform.alpG7rT7.mjs.map} +1 -1
  60. package/dist/zod-v3.cjs +2 -2
  61. package/dist/zod-v3.d.cts +3 -3
  62. package/dist/zod-v3.d.mts +3 -3
  63. package/dist/zod-v3.d.ts +3 -3
  64. package/dist/zod-v3.mjs +2 -2
  65. package/dist/zod-v4.cjs +2 -2
  66. package/dist/zod-v4.d.cts +5 -5
  67. package/dist/zod-v4.d.mts +5 -5
  68. package/dist/zod-v4.d.ts +5 -5
  69. package/dist/zod-v4.mjs +2 -2
  70. package/dist/zod.cjs +5 -5
  71. package/dist/zod.d.cts +5 -5
  72. package/dist/zod.d.mts +5 -5
  73. package/dist/zod.d.ts +5 -5
  74. package/dist/zod.mjs +5 -5
  75. package/package.json +2 -2
  76. package/dist/chunks/indexeddb.cjs +0 -119
  77. package/dist/chunks/indexeddb.cjs.map +0 -1
  78. package/dist/chunks/indexeddb.mjs +0 -117
  79. package/dist/chunks/indexeddb.mjs.map +0 -1
  80. package/dist/chunks/local-storage.cjs +0 -58
  81. package/dist/chunks/local-storage.cjs.map +0 -1
  82. package/dist/chunks/local-storage.mjs +0 -56
  83. package/dist/chunks/local-storage.mjs.map +0 -1
  84. package/dist/chunks/multi-tab-sync.cjs +0 -367
  85. package/dist/chunks/multi-tab-sync.cjs.map +0 -1
  86. package/dist/chunks/multi-tab-sync.mjs +0 -364
  87. package/dist/chunks/multi-tab-sync.mjs.map +0 -1
  88. package/dist/chunks/session-storage.cjs +0 -58
  89. package/dist/chunks/session-storage.cjs.map +0 -1
  90. package/dist/chunks/session-storage.mjs +0 -56
  91. package/dist/chunks/session-storage.mjs.map +0 -1
  92. package/dist/chunks/wire-persistence.cjs +0 -396
  93. package/dist/chunks/wire-persistence.cjs.map +0 -1
  94. package/dist/chunks/wire-persistence.mjs +0 -394
  95. package/dist/chunks/wire-persistence.mjs.map +0 -1
  96. package/dist/shared/attaform.B5LNzqQh.cjs.map +0 -1
  97. package/dist/shared/attaform.CTheKoTc.mjs.map +0 -1
  98. package/dist/shared/attaform.CcnF1AKJ.cjs.map +0 -1
  99. package/dist/shared/attaform.CrD73S4m.mjs.map +0 -1
  100. package/dist/shared/attaform.D2ZuIOCf.cjs.map +0 -1
  101. package/dist/shared/attaform.DP-u7_tk.mjs.map +0 -1
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const vue = require('vue');
4
- const paths = require('./attaform.B5LNzqQh.cjs');
4
+ const paths = require('./attaform.Db4E4IW6.cjs');
5
5
 
6
6
  function safeAssign(target, key, value) {
7
7
  if (key === "__proto__") {
@@ -36,7 +36,7 @@ function descendStep(value, segment) {
36
36
  if (typeof value !== "object") return NOT_FOUND;
37
37
  if (Array.isArray(value)) {
38
38
  if (typeof segment !== "number") return NOT_FOUND;
39
- if (segment < 0 || segment >= value.length) return NOT_FOUND;
39
+ if (!(segment in value)) return NOT_FOUND;
40
40
  return value[segment];
41
41
  }
42
42
  const record = value;
@@ -71,7 +71,7 @@ function hasAtPath(root, path) {
71
71
  if (current === null || current === void 0) return false;
72
72
  if (typeof current !== "object") return false;
73
73
  if (Array.isArray(current)) {
74
- return typeof last === "number" && last >= 0 && last < current.length;
74
+ return typeof last === "number" && last in current;
75
75
  }
76
76
  const key = typeof last === "number" ? String(last) : last;
77
77
  if (isShadowedKey(key)) return safeOwnHas(current, key);
@@ -100,6 +100,31 @@ function setAtPathOffset(root, path, value, offset) {
100
100
  safeAssign(rec, head, setAtPathOffset(safeOwnRead(rec, head), path, value, nextOffset));
101
101
  return rec;
102
102
  }
103
+ const NO_IN_PLACE = { applied: false };
104
+ function tryInPlaceLeafWrite(root, path, value) {
105
+ if (path.length === 0) return NO_IN_PLACE;
106
+ let node = root;
107
+ for (let i = 0; i < path.length; i++) {
108
+ const seg = path[i];
109
+ if (Array.isArray(node)) {
110
+ if (typeof seg !== "number" || seg < 0 || seg >= node.length) return NO_IN_PLACE;
111
+ } else if (isPlainRecord(node)) {
112
+ if (typeof seg !== "string" || isShadowedKey(seg) || !(seg in node)) return NO_IN_PLACE;
113
+ } else {
114
+ return NO_IN_PLACE;
115
+ }
116
+ const container = node;
117
+ if (i < path.length - 1) {
118
+ node = container[seg];
119
+ continue;
120
+ }
121
+ const old = container[seg];
122
+ if (isPlainRecord(old) || Array.isArray(old)) return NO_IN_PLACE;
123
+ container[seg] = value;
124
+ return { applied: true, old };
125
+ }
126
+ return NO_IN_PLACE;
127
+ }
103
128
  function deleteAtPath(root, path) {
104
129
  return deleteAtPathOffset(root, path, 0);
105
130
  }
@@ -403,7 +428,7 @@ function diffObjectsLockstep(oldRec, newRec, prefix, visit) {
403
428
  diffAndApply(oldRec[k], newRec[k], appendSegment(prefix, k), visit);
404
429
  }
405
430
  }
406
- function applyChangedKeys(target, source) {
431
+ function applyChangedKeys(target, source, arrayOpPath, currentPath) {
407
432
  if (!isDescendable(target) || !isDescendable(source)) return false;
408
433
  const targetIsArray = Array.isArray(target);
409
434
  const sourceIsArray = Array.isArray(source);
@@ -421,11 +446,27 @@ function applyChangedKeys(target, source) {
421
446
  if (targetIsArray) {
422
447
  const t = target;
423
448
  const s = source;
424
- if (t.length > s.length) t.length = s.length;
425
- for (const idx of changedFirstSegments) {
426
- if (typeof idx === "symbol") continue;
427
- const i = typeof idx === "number" ? idx : Number(idx);
428
- t[i] = s[i];
449
+ if (arrayOpPath === null || paths.pathsEqual(currentPath, arrayOpPath)) {
450
+ if (t.length > s.length) t.length = s.length;
451
+ for (const idx of changedFirstSegments) {
452
+ if (typeof idx === "symbol") continue;
453
+ const i = typeof idx === "number" ? idx : Number(idx);
454
+ if (i >= s.length) continue;
455
+ t[i] = s[i];
456
+ }
457
+ } else {
458
+ for (const idx of changedFirstSegments) {
459
+ if (typeof idx === "symbol") continue;
460
+ const i = typeof idx === "number" ? idx : Number(idx);
461
+ if (i >= s.length) continue;
462
+ const childPath = appendSegment(currentPath, i);
463
+ const curEl = t[i];
464
+ const nextEl = s[i];
465
+ if (paths.isPathPrefix(childPath, arrayOpPath) && isDescendable(curEl) && isDescendable(nextEl) && applyChangedKeys(curEl, nextEl, arrayOpPath, childPath)) {
466
+ continue;
467
+ }
468
+ t[i] = nextEl;
469
+ }
429
470
  }
430
471
  } else {
431
472
  const t = target;
@@ -437,7 +478,14 @@ function applyChangedKeys(target, source) {
437
478
  for (const k of changedFirstSegments) {
438
479
  if (typeof k === "symbol") continue;
439
480
  const key = String(k);
440
- safeAssign(t, key, safeOwnRead(s, key));
481
+ const nextVal = safeOwnRead(s, key);
482
+ if (arrayOpPath !== null) {
483
+ const curVal = safeOwnRead(t, key);
484
+ if (isDescendable(curVal) && isDescendable(nextVal) && applyChangedKeys(curVal, nextVal, arrayOpPath, appendSegment(currentPath, key))) {
485
+ continue;
486
+ }
487
+ }
488
+ safeAssign(t, key, nextVal);
441
489
  }
442
490
  }
443
491
  return true;
@@ -549,10 +597,52 @@ function resolveGetDisplayState(config) {
549
597
  return config ?? defaultDisplayState;
550
598
  }
551
599
 
600
+ const AttaformErrorCode = {
601
+ /** A required field is in the blank set — user hasn't supplied a value. */
602
+ NoValueSupplied: "atta:no-value-supplied",
603
+ /** The schema adapter's `validateAtPath` threw synchronously. */
604
+ AdapterThrew: "atta:adapter-threw",
605
+ /**
606
+ * User code inside a `z.preprocess`, `.refine`, or `.transform`
607
+ * threw (sync or async). The adapter caught the throw and surfaced
608
+ * it as a `ValidationError` at the field path so the form's normal
609
+ * error pipeline handles it instead of leaking as an unhandled
610
+ * rejection or routing through `submitError`.
611
+ */
612
+ ValidatorThrew: "atta:validator-threw",
613
+ /**
614
+ * A function-form `defaultValues` factory threw or its promise
615
+ * rejected. The runtime captures the raw error on `form.hydrateError`
616
+ * and ALSO surfaces a form-level `ValidationError` (path `[]`) so
617
+ * the standard error pipeline carries the signal. Critical for the
618
+ * SSR round-trip: `hydrateError` itself does not ride the wire
619
+ * payload, but `schemaErrors` does, so the client sees the failure
620
+ * after rehydration without an extra channel.
621
+ */
622
+ HydrationFailed: "atta:hydration-failed",
623
+ /** The supplied path didn't resolve to any node in the schema. */
624
+ PathNotFound: "atta:path-not-found",
625
+ /**
626
+ * A walked form's `activate()` (async `defaultValues` factory) threw
627
+ * during `wizard.handleSubmit`'s path walk. Surfaced as a synthetic
628
+ * `ValidationError` at the form-level path (`[]`) so the wizard's
629
+ * aggregate error pipeline can carry the failure alongside ordinary
630
+ * validation errors. The raw factory error remains on
631
+ * `form.hydrateError` for retry UX.
632
+ */
633
+ ActivationFailed: "atta:activation-failed"
634
+ };
635
+ function makeBlankRequiredError(segments, formKey) {
636
+ return {
637
+ message: "No value supplied",
638
+ path: [...segments],
639
+ formKey,
640
+ code: AttaformErrorCode.NoValueSupplied
641
+ };
642
+ }
643
+
552
644
  const DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS = 0;
553
- const DEFAULT_PERSISTENCE_DEBOUNCE_MS = 300;
554
645
  const DEFAULT_HISTORY_MAX_SNAPSHOTS = 128;
555
- const PERSISTENCE_KEY_PREFIX = "attaform:";
556
646
  const RESERVED_KEY_PREFIX = "__atta:";
557
647
  const ANONYMOUS_FORM_KEY_PREFIX = `${RESERVED_KEY_PREFIX}anon:`;
558
648
  const ANONYMOUS_WIZARD_KEY_PREFIX = `${RESERVED_KEY_PREFIX}anon-wizard:`;
@@ -662,7 +752,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
662
752
  const original = state.originals.get(key)?.value;
663
753
  const pristine = state.isPristineAtPath(segments);
664
754
  const schemaForKey = state.schemaErrors.get(key);
665
- const blankForKey = state.derivedBlankErrors.value.get(key);
755
+ const blankForKey = state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments) ? [makeBlankRequiredError(segments, state.formKey)] : void 0;
666
756
  const userForKey = state.userErrors.get(key);
667
757
  const errors = [];
668
758
  if (schemaForKey !== void 0) errors.push(...schemaForKey);
@@ -726,9 +816,32 @@ function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBa
726
816
  getDisplayState
727
817
  );
728
818
  }
819
+ function visitActiveLeafPaths(value, base, visit) {
820
+ if (Array.isArray(value)) {
821
+ for (let i = 0; i < value.length; i++) {
822
+ const child = value[i];
823
+ if (Array.isArray(child) || isPlainRecord(child)) {
824
+ visitActiveLeafPaths(child, [...base, i], visit);
825
+ } else {
826
+ visit([...base, i]);
827
+ }
828
+ }
829
+ return;
830
+ }
831
+ if (isPlainRecord(value)) {
832
+ for (const k of Object.keys(value)) {
833
+ const child = value[k];
834
+ if (Array.isArray(child) || isPlainRecord(child)) {
835
+ visitActiveLeafPaths(child, [...base, k], visit);
836
+ } else {
837
+ visit([...base, k]);
838
+ }
839
+ }
840
+ }
841
+ }
729
842
  function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
730
843
  const formValue = state.form.value;
731
- const value = state.getValueAtPath(segments);
844
+ const value = getAtPath(formValue, segments);
732
845
  const original = state.originals.get(key)?.value;
733
846
  let pristine = true;
734
847
  let blank = true;
@@ -747,12 +860,16 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
747
860
  let asyncPending = false;
748
861
  const submissionAttempts = state.submissionAttempts.value;
749
862
  const blurredLeafSegments = [];
750
- for (const [leafKey, entry] of state.originals) {
751
- if (!paths.isPathPrefix(segments, entry.segments)) continue;
752
- if (segments.length === entry.segments.length) continue;
753
- if (!hasAtPath(formValue, entry.segments)) continue;
863
+ const descendantLeaves = [];
864
+ visitActiveLeafPaths(value, segments, (leafSegments) => {
865
+ const { key: leafKey } = paths.keyForSegments(leafSegments);
866
+ const entry = state.originals.get(leafKey);
867
+ if (entry === void 0) return;
868
+ descendantLeaves.push({ key: leafKey, segments: entry.segments });
869
+ });
870
+ for (const { key: leafKey, segments: leafSeg } of descendantLeaves) {
754
871
  const leafRecord = state.fields.get(leafKey);
755
- if (!state.isPristineAtPathByKey(leafKey, entry.segments)) {
872
+ if (!state.isPristineAtPathByKey(leafKey, leafSeg)) {
756
873
  pristine = false;
757
874
  dirty = true;
758
875
  }
@@ -763,7 +880,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
763
880
  if (leafRecord?.interacted === true) interacted = true;
764
881
  if (leafRecord?.blurredAfterInteraction === true) {
765
882
  blurredAfterInteraction = true;
766
- blurredLeafSegments.push(entry.segments);
883
+ blurredLeafSegments.push(leafSeg);
767
884
  }
768
885
  if (leafRecord?.connected === true) connected = true;
769
886
  if ((state.fieldValidationCounts.get(leafKey) ?? 0) > 0) {
@@ -780,7 +897,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
780
897
  if (leafGateOpen && since !== void 0 && (transformingSince === null || since < transformingSince))
781
898
  transformingSince = since;
782
899
  }
783
- if (state.pathHasAsyncValidationByKey(leafKey, entry.segments)) asyncPending = true;
900
+ if (state.pathHasAsyncValidationByKey(leafKey, leafSeg)) asyncPending = true;
784
901
  const ts = leafRecord?.updatedAt;
785
902
  if (ts !== void 0 && ts !== null) {
786
903
  if (updatedAt === null || ts > updatedAt) updatedAt = ts;
@@ -1396,9 +1513,8 @@ function buildFieldArrayApi(state) {
1396
1513
  return Array.isArray(current) ? current.slice() : [];
1397
1514
  }
1398
1515
  function writeArray(path, next, arrayOp) {
1399
- const { segments, key } = paths.canonicalizePath(path);
1516
+ const { segments } = paths.canonicalizePath(path);
1400
1517
  const meta = {
1401
- persist: state.persistOptIns.hasAnyOptInForPath(key),
1402
1518
  ...arrayOp !== void 0 ? { arrayOp } : {}
1403
1519
  };
1404
1520
  return state.setValueAtPath(segments, next, meta);
@@ -1407,7 +1523,7 @@ function buildFieldArrayApi(state) {
1407
1523
  append(path, value) {
1408
1524
  const next = readArray(path);
1409
1525
  next.push(value);
1410
- return writeArray(path, next);
1526
+ return writeArray(path, next, { kind: "insert", index: next.length - 1 });
1411
1527
  },
1412
1528
  prepend(path, value) {
1413
1529
  const next = readArray(path);
@@ -1620,157 +1736,6 @@ function walk$1(value, basePath, schema, snapshotFieldStateAt) {
1620
1736
  return result;
1621
1737
  }
1622
1738
 
1623
- const PERSISTENCE_MODULE_KEY = "persistence";
1624
- async function getStorageAdapter(storage) {
1625
- if (typeof storage === "object") return storage;
1626
- switch (storage) {
1627
- case "local": {
1628
- const { createLocalStorageAdapter } = await import('../chunks/local-storage.cjs');
1629
- return createLocalStorageAdapter();
1630
- }
1631
- case "session": {
1632
- const { createSessionStorageAdapter } = await import('../chunks/session-storage.cjs');
1633
- return createSessionStorageAdapter();
1634
- }
1635
- case "indexeddb": {
1636
- const { createIndexedDbAdapter } = await import('../chunks/indexeddb.cjs');
1637
- return createIndexedDbAdapter();
1638
- }
1639
- }
1640
- }
1641
- function resolveStorageKeyBase(config, formKey) {
1642
- return config.key ?? `${PERSISTENCE_KEY_PREFIX}${formKey}`;
1643
- }
1644
- async function removeMatchingKeys(adapter, base, keepKey) {
1645
- let keys;
1646
- try {
1647
- keys = await adapter.listKeys(base);
1648
- } catch {
1649
- return;
1650
- }
1651
- for (const key of keys) {
1652
- if (key === keepKey) continue;
1653
- if (key === base || key.startsWith(`${base}:`)) {
1654
- void adapter.removeItem(key).catch(() => void 0);
1655
- }
1656
- }
1657
- }
1658
- async function cleanupOrphanKeys(adapter, base, currentKey) {
1659
- await removeMatchingKeys(adapter, base, currentKey);
1660
- }
1661
- const STANDARD_STORAGE_KINDS = ["local", "session", "indexeddb"];
1662
- function normalizePersistConfig(input) {
1663
- if (typeof input === "string") return { storage: input };
1664
- if ("storage" in input) return input;
1665
- return { storage: input };
1666
- }
1667
- async function sweepAllOrphansAcrossStandardStores(base) {
1668
- for (const kind of STANDARD_STORAGE_KINDS) {
1669
- try {
1670
- const adapter = await getStorageAdapter(kind);
1671
- await removeMatchingKeys(adapter, base);
1672
- } catch {
1673
- }
1674
- }
1675
- }
1676
- async function sweepNonConfiguredStandardStoresForOrphans(configured, base) {
1677
- const configuredKind = typeof configured === "string" ? configured : null;
1678
- for (const kind of STANDARD_STORAGE_KINDS) {
1679
- if (kind === configuredKind) continue;
1680
- try {
1681
- const adapter = await getStorageAdapter(kind);
1682
- await removeMatchingKeys(adapter, base);
1683
- } catch {
1684
- }
1685
- }
1686
- }
1687
- function mergeSparseHydration(schemaDefaults, sparse, schema) {
1688
- return mergeDeep(schemaDefaults, sparse, [], schema);
1689
- }
1690
- function mergeDeep(target, source, path, schema) {
1691
- if (source === void 0) return target;
1692
- if (source === null || typeof source !== "object") return source;
1693
- if (Array.isArray(source)) return source;
1694
- if (!isPlainRecord(source)) return source;
1695
- if (schema !== void 0) {
1696
- const du = schema.getUnionDiscriminatorAtPath(path);
1697
- if (du !== void 0) return mergeDuAwareKeys(source, path, schema, du);
1698
- }
1699
- return mergeObjectKeys(target, source, path, schema);
1700
- }
1701
- function mergeDuAwareKeys(source, path, schema, du) {
1702
- const sourceDisc = source[du.discriminatorKey];
1703
- if (sourceDisc !== void 0 && !du.isVariantSelected(sourceDisc)) {
1704
- return { [du.discriminatorKey]: sourceDisc };
1705
- }
1706
- if (sourceDisc !== void 0) {
1707
- const variantDefault = du.getVariantDefault(sourceDisc);
1708
- if (isPlainRecord(variantDefault)) {
1709
- return mergeVariantKeys(source, variantDefault, path, schema, du);
1710
- }
1711
- }
1712
- return {};
1713
- }
1714
- function mergeVariantKeys(source, variantDefault, path, schema, du) {
1715
- const out = { ...variantDefault };
1716
- for (const key of Object.keys(source)) {
1717
- if (!safeOwnHas(variantDefault, key) && key !== du.discriminatorKey) continue;
1718
- safeAssign(
1719
- out,
1720
- key,
1721
- mergeDeep(safeOwnRead(out, key), safeOwnRead(source, key), [...path, key], schema)
1722
- );
1723
- }
1724
- return out;
1725
- }
1726
- function mergeObjectKeys(target, source, path, schema) {
1727
- const out = isPlainRecord(target) ? { ...target } : {};
1728
- for (const key of Object.keys(source)) {
1729
- safeAssign(
1730
- out,
1731
- key,
1732
- mergeDeep(safeOwnRead(out, key), safeOwnRead(source, key), [...path, key], schema)
1733
- );
1734
- }
1735
- return out;
1736
- }
1737
-
1738
- const AttaformErrorCode = {
1739
- /** A required field is in the blank set — user hasn't supplied a value. */
1740
- NoValueSupplied: "atta:no-value-supplied",
1741
- /** The schema adapter's `validateAtPath` threw synchronously. */
1742
- AdapterThrew: "atta:adapter-threw",
1743
- /**
1744
- * User code inside a `z.preprocess`, `.refine`, or `.transform`
1745
- * threw (sync or async). The adapter caught the throw and surfaced
1746
- * it as a `ValidationError` at the field path so the form's normal
1747
- * error pipeline handles it instead of leaking as an unhandled
1748
- * rejection or routing through `submitError`.
1749
- */
1750
- ValidatorThrew: "atta:validator-threw",
1751
- /**
1752
- * A function-form `defaultValues` factory threw or its promise
1753
- * rejected. The runtime captures the raw error on `form.hydrateError`
1754
- * and ALSO surfaces a form-level `ValidationError` (path `[]`) so
1755
- * the standard error pipeline carries the signal. Critical for the
1756
- * SSR round-trip: `hydrateError` itself does not ride the wire
1757
- * payload, but `schemaErrors` does, so the client sees the failure
1758
- * after rehydration without an extra channel.
1759
- */
1760
- HydrationFailed: "atta:hydration-failed",
1761
- /** The supplied path didn't resolve to any node in the schema. */
1762
- PathNotFound: "atta:path-not-found",
1763
- /**
1764
- * A walked form's `activate()` (async `defaultValues` factory) threw
1765
- * during `wizard.handleSubmit`'s path walk. Surfaced as a synthetic
1766
- * `ValidationError` at the form-level path (`[]`) so the wizard's
1767
- * aggregate error pipeline can carry the failure alongside ordinary
1768
- * validation errors. The raw factory error remains on
1769
- * `form.hydrateError` for retry UX.
1770
- */
1771
- ActivationFailed: "atta:activation-failed"
1772
- };
1773
-
1774
1739
  const warnedNoScopeStores = paths.__DEV__ ? /* @__PURE__ */ new WeakSet() : null;
1775
1740
  function buildProcessForm(state, formInstanceId, options = {}) {
1776
1741
  const invalidPolicy = options.onInvalidSubmit ?? "focus-first-error";
@@ -2028,44 +1993,6 @@ function applyInvalidSubmitPolicy(state, formInstanceId, policy) {
2028
1993
  target.element.focus({ preventScroll: true });
2029
1994
  }
2030
1995
 
2031
- function captureUserCallSite() {
2032
- const raw = new Error().stack;
2033
- if (typeof raw !== "string") return void 0;
2034
- const lines = raw.split("\n");
2035
- for (let i = 1; i < lines.length; i++) {
2036
- const frame = lines[i];
2037
- if (frame === void 0) continue;
2038
- if (/attaform[/-]forms?/i.test(frame)) continue;
2039
- if (/\bforms\.[A-Za-z0-9_-]+\.m?js\b/.test(frame)) continue;
2040
- const trimmed = frame.trim();
2041
- if (trimmed.length === 0) continue;
2042
- return shortenSourceFrame(trimmed);
2043
- }
2044
- return void 0;
2045
- }
2046
- function shortenSourceFrame(frame) {
2047
- const match = /(?:^|\s|\()([^\s()]+):(\d+):\d+\)?$/.exec(frame);
2048
- if (match === null) return frame;
2049
- const [, urlOrPath, line] = match;
2050
- if (urlOrPath === void 0 || line === void 0) return frame;
2051
- let path = urlOrPath;
2052
- path = path.replace(/^[a-z]+:\/\/[^/]+\//i, "");
2053
- path = path.replace(/^_nuxt\//, "");
2054
- path = path.replace(/^\//, "");
2055
- return `(${path}:${line})`;
2056
- }
2057
-
2058
- function extractSchemaFields(schema) {
2059
- try {
2060
- const root = schema.getDefaultAtPath([]);
2061
- if (root !== null && typeof root === "object" && !Array.isArray(root)) {
2062
- return Object.keys(root);
2063
- }
2064
- } catch {
2065
- }
2066
- return [];
2067
- }
2068
-
2069
1996
  const warnedRejections = paths.__DEV__ ? /* @__PURE__ */ new WeakMap() : null;
2070
1997
  function shouldWarnOnce$1(store, key) {
2071
1998
  if (warnedRejections === null) return false;
@@ -2395,16 +2322,7 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2395
2322
  const slimTypes = state.schema.getSlimPrimitiveTypesAtPath(segments);
2396
2323
  const acceptsUndefined = slimTypes.has("undefined");
2397
2324
  const acceptsString = slimTypes.has("string");
2398
- const persist = options?.persist === true;
2399
- const acknowledgeSensitive = options?.acknowledgeSensitive === true;
2400
- const multiTab = options?.multiTab !== false;
2401
2325
  const transforms = options?.transforms ?? EMPTY_TRANSFORMS;
2402
- const markNoSync = !multiTab ? () => {
2403
- state.incrementNoSyncOptOut(pathKey);
2404
- } : void 0;
2405
- const unmarkNoSync = !multiTab ? () => {
2406
- state.decrementNoSyncOptOut(pathKey);
2407
- } : void 0;
2408
2326
  const coerce = buildCoerceFn(
2409
2327
  state.schema,
2410
2328
  segments,
@@ -2415,18 +2333,10 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2415
2333
  segments,
2416
2334
  coerceIndex
2417
2335
  );
2418
- if (persist && !state.ssr && !state.modules.has(PERSISTENCE_MODULE_KEY)) {
2419
- throw new paths.AnonPersistError({
2420
- cause: "register-without-config",
2421
- schemaFields: extractSchemaFields(state.schema),
2422
- callSite: captureUserCallSite()
2423
- });
2424
- }
2425
2336
  const { aria } = computeFieldIdentity(formInstanceId, state.formKey, pathKey);
2426
2337
  const isRequired = state.schema.isRequiredAtPath(segments);
2427
2338
  const ariaEnabled = options?.autoAria ?? formAutoAria;
2428
2339
  const ariaDisplayState = getDisplayStateAt !== void 0 ? vue.computed(() => getDisplayStateAt(segments)) : void 0;
2429
- let boundElement = null;
2430
2340
  const internalRv = {
2431
2341
  innerRef,
2432
2342
  displayValue,
@@ -2436,8 +2346,7 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2436
2346
  segments,
2437
2347
  slimDefault,
2438
2348
  withInstanceMeta({
2439
- blank: true,
2440
- persist
2349
+ blank: true
2441
2350
  })
2442
2351
  );
2443
2352
  },
@@ -2445,7 +2354,6 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2445
2354
  state.markInteracted(segments);
2446
2355
  },
2447
2356
  registerElement: (element) => {
2448
- boundElement = element;
2449
2357
  if (!paths.INTERACTIVE_TAG_NAMES.has(element.tagName)) return;
2450
2358
  const added = state.registerElement(segments, element, formInstanceId);
2451
2359
  if (added) attachFocusListeners(state, segments, element, instanceMeta);
@@ -2453,11 +2361,9 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2453
2361
  deregisterElement: (element) => {
2454
2362
  detachFocusListeners(element);
2455
2363
  state.deregisterElement(segments, element);
2456
- if (boundElement === element) boundElement = null;
2457
2364
  },
2458
2365
  setValueWithInternalPath: (value, meta) => {
2459
- const resolvedMeta = meta === void 0 && boundElement !== null ? { persist: state.persistOptIns.hasOptIn(paths.getOrAssignElementId(boundElement), pathKey) } : meta;
2460
- return state.setValueAtPath(segments, value, withInstanceMeta(resolvedMeta));
2366
+ return state.setValueAtPath(segments, value, withInstanceMeta(meta));
2461
2367
  },
2462
2368
  // Called by the `vRegisterHint` compile-time transform's wrapping
2463
2369
  // IIFE on every server-side render of `<element v-register="…">`.
@@ -2495,15 +2401,6 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2495
2401
  segments: Object.freeze(segments.slice()),
2496
2402
  formKey: state.formKey,
2497
2403
  formInstanceId,
2498
- // --- Persistence opt-in (internal; the directive is the only
2499
- // legitimate consumer) ---
2500
- persist,
2501
- acknowledgeSensitive,
2502
- persistOptIns: state.persistOptIns,
2503
- isSensitivePath: state.isSensitivePath,
2504
- multiTab,
2505
- ...markNoSync !== void 0 ? { markNoSync } : {},
2506
- ...unmarkNoSync !== void 0 ? { unmarkNoSync } : {},
2507
2404
  transforms,
2508
2405
  coerce,
2509
2406
  ...coerceElement !== void 0 ? { coerceElement } : {},
@@ -2796,19 +2693,116 @@ function buildFormApi(state, formInstanceId, options = {}) {
2796
2693
  }
2797
2694
  };
2798
2695
  const getFormMetaBase = () => {
2799
- const { base: rootBase } = buildContainerFieldStateBase(
2696
+ let rollup;
2697
+ const rootBase = () => rollup ?? (rollup = buildContainerFieldStateBase(
2800
2698
  state,
2801
2699
  paths.ROOT_PATH,
2802
2700
  paths.ROOT_PATH_KEY,
2803
2701
  formInstanceId
2804
- );
2702
+ ).base);
2805
2703
  return {
2806
- ...rootBase,
2704
+ // Rollup-derived (FieldStateBase) — the whole rollup builds once, on the
2705
+ // first access of any of these.
2706
+ get value() {
2707
+ return rootBase().value;
2708
+ },
2709
+ get original() {
2710
+ return rootBase().original;
2711
+ },
2712
+ get pristine() {
2713
+ return rootBase().pristine;
2714
+ },
2715
+ get dirty() {
2716
+ return rootBase().dirty;
2717
+ },
2718
+ get focused() {
2719
+ return rootBase().focused;
2720
+ },
2721
+ get blurred() {
2722
+ return rootBase().blurred;
2723
+ },
2724
+ get touched() {
2725
+ return rootBase().touched;
2726
+ },
2727
+ get interacted() {
2728
+ return rootBase().interacted;
2729
+ },
2730
+ get blurredAfterInteraction() {
2731
+ return rootBase().blurredAfterInteraction;
2732
+ },
2733
+ get connected() {
2734
+ return rootBase().connected;
2735
+ },
2736
+ get element() {
2737
+ return rootBase().element;
2738
+ },
2739
+ get elements() {
2740
+ return rootBase().elements;
2741
+ },
2742
+ get updatedAt() {
2743
+ return rootBase().updatedAt;
2744
+ },
2745
+ get errors() {
2746
+ return rootBase().errors;
2747
+ },
2748
+ get validating() {
2749
+ return rootBase().validating;
2750
+ },
2751
+ get valid() {
2752
+ return rootBase().valid;
2753
+ },
2754
+ get transforming() {
2755
+ return rootBase().transforming;
2756
+ },
2757
+ get busy() {
2758
+ return rootBase().busy;
2759
+ },
2760
+ get transformError() {
2761
+ return rootBase().transformError;
2762
+ },
2763
+ get path() {
2764
+ return rootBase().path;
2765
+ },
2766
+ get id() {
2767
+ return rootBase().id;
2768
+ },
2769
+ get aria() {
2770
+ return rootBase().aria;
2771
+ },
2772
+ get key() {
2773
+ return rootBase().key;
2774
+ },
2775
+ get blank() {
2776
+ return rootBase().blank;
2777
+ },
2778
+ get label() {
2779
+ return rootBase().label;
2780
+ },
2781
+ get description() {
2782
+ return rootBase().description;
2783
+ },
2784
+ get placeholder() {
2785
+ return rootBase().placeholder;
2786
+ },
2787
+ get meta() {
2788
+ return rootBase().meta;
2789
+ },
2790
+ get errorCount() {
2791
+ return rootBase().errors.length;
2792
+ },
2793
+ // Form-level scalars — EAGER reads, tracked on every field-state eval.
2794
+ // They are O(1) refs that never change on a keystroke, so tracking them
2795
+ // per field costs nothing on the hot path. Kept eager (NOT lazy like the
2796
+ // rollup) because behaviors beyond the predicate's own output depend on
2797
+ // every field re-evaluating when they flip — most notably, the display
2798
+ // engine is cleared on submit (revealing held spinners), and that
2799
+ // imperative reset only becomes visible if `submitting` is a tracked dep
2800
+ // of each field. Matches the pre-bust dependency set for these scalars
2801
+ // exactly.
2807
2802
  submitting: state.submitting.value,
2808
2803
  submissionAttempts: state.submissionAttempts.value,
2809
2804
  departAttempts: state.departAttempts.value,
2810
2805
  submitError: state.submitError.value,
2811
- errorCount: rootBase.errors.length,
2812
2806
  submitted: state.submitted.value,
2813
2807
  instanceId: formInstanceId
2814
2808
  };
@@ -2844,13 +2838,16 @@ function buildFormApi(state, formInstanceId, options = {}) {
2844
2838
  return vue.computed(() => getAtPath(state.form.value, segments));
2845
2839
  }
2846
2840
  function setValueImpl(pathOrValue, maybeValue) {
2847
- if (arguments.length === 1) {
2841
+ const argc = arguments.length;
2842
+ const isPathForm = argc >= 2 && (typeof pathOrValue === "string" || Array.isArray(pathOrValue));
2843
+ const writeMeta = (extra) => withInstanceMeta(extra);
2844
+ if (!isPathForm) {
2848
2845
  const next = typeof pathOrValue === "function" ? pathOrValue(structuralSnapshot(state.form.value)) : pathOrValue;
2849
2846
  const walked2 = walkUnsetSentinels(
2850
2847
  next,
2851
2848
  state.schema
2852
2849
  );
2853
- const ok2 = state.setValueAtPath([], walked2.cleanedValues, withInstanceMeta());
2850
+ const ok2 = state.setValueAtPath([], walked2.cleanedValues, writeMeta());
2854
2851
  if (!ok2) return false;
2855
2852
  reMarkBlanksAfterSubstitution(walked2.paths);
2856
2853
  return true;
@@ -2864,7 +2861,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2864
2861
  if (parentDU?.discriminatorKey === last) {
2865
2862
  const slimDefault = state.schema.getEmptyValueAtPath(segments);
2866
2863
  const blank = blankForKind(slimDefault);
2867
- return state.setValueAtPath(segments, blank, withInstanceMeta({ blank: true }));
2864
+ return state.setValueAtPath(segments, blank, writeMeta({ blank: true }));
2868
2865
  }
2869
2866
  }
2870
2867
  const blankPaths = [];
@@ -2875,9 +2872,9 @@ function buildFormApi(state, formInstanceId, options = {}) {
2875
2872
  );
2876
2873
  const segmentsKey = paths.canonicalizePath(segments).key;
2877
2874
  if (blankPaths.length === 1 && blankPaths[0] === segmentsKey) {
2878
- return state.setValueAtPath(segments, expanded, withInstanceMeta({ blank: true }));
2875
+ return state.setValueAtPath(segments, expanded, writeMeta({ blank: true }));
2879
2876
  }
2880
- const ok2 = state.setValueAtPath(segments, expanded, withInstanceMeta());
2877
+ const ok2 = state.setValueAtPath(segments, expanded, writeMeta());
2881
2878
  if (!ok2) return false;
2882
2879
  for (const pathKey of blankPaths) {
2883
2880
  const blankSegments = paths.segmentsForPathKey(pathKey);
@@ -2885,7 +2882,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2885
2882
  state.setValueAtPath(
2886
2883
  blankSegments,
2887
2884
  state.getValueAtPath(blankSegments),
2888
- withInstanceMeta({ blank: true })
2885
+ writeMeta({ blank: true })
2889
2886
  );
2890
2887
  }
2891
2888
  return true;
@@ -2905,7 +2902,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2905
2902
  segments,
2906
2903
  state.schema
2907
2904
  );
2908
- const ok = state.setValueAtPath(segments, walked.cleanedValues, withInstanceMeta());
2905
+ const ok = state.setValueAtPath(segments, walked.cleanedValues, writeMeta());
2909
2906
  if (!ok) return false;
2910
2907
  reMarkBlanksAfterSubstitution(walked.paths);
2911
2908
  return true;
@@ -3135,7 +3132,6 @@ function buildFormApi(state, formInstanceId, options = {}) {
3135
3132
  instanceId: formInstanceId
3136
3133
  })
3137
3134
  );
3138
- const persistenceHandle = state.modules.get(PERSISTENCE_MODULE_KEY);
3139
3135
  const reset = (nextDefaultValues) => {
3140
3136
  if (nextDefaultValues === void 0) {
3141
3137
  state.reset();
@@ -3150,16 +3146,10 @@ function buildFormApi(state, formInstanceId, options = {}) {
3150
3146
  state.originalBlankPaths.add(pathKey);
3151
3147
  }
3152
3148
  }
3153
- if (persistenceHandle !== void 0) {
3154
- void persistenceHandle.ready.then((m) => m?.clearPersistedDraft()).catch(() => void 0);
3155
- }
3156
3149
  };
3157
3150
  const resetField = (pathInput) => {
3158
3151
  const segments = paths.canonicalizePath(pathInput).segments;
3159
3152
  state.resetField(segments);
3160
- if (persistenceHandle !== void 0) {
3161
- void persistenceHandle.ready.then((m) => m?.clearPersistedDraft(segments)).catch(() => void 0);
3162
- }
3163
3153
  };
3164
3154
  function clear(pathInput) {
3165
3155
  if (pathInput === void 0) {
@@ -3167,31 +3157,6 @@ function buildFormApi(state, formInstanceId, options = {}) {
3167
3157
  }
3168
3158
  return setValueImpl(pathInput, unset);
3169
3159
  }
3170
- const persist = async (pathInput, options2) => {
3171
- const segments = paths.canonicalizePath(pathInput).segments;
3172
- if (!paths.allowSensitivePersist(
3173
- segments,
3174
- options2?.acknowledgeSensitive === true,
3175
- state.isSensitivePath
3176
- )) {
3177
- return;
3178
- }
3179
- if (persistenceHandle === void 0) return;
3180
- const persistence = await persistenceHandle.ready;
3181
- if (persistence === void 0) return;
3182
- await persistence.writePathImmediately(segments);
3183
- };
3184
- const clearPersistedDraft = async (pathInput) => {
3185
- if (persistenceHandle === void 0) return;
3186
- const persistence = await persistenceHandle.ready;
3187
- if (persistence === void 0) return;
3188
- if (pathInput === void 0) {
3189
- await persistence.clearPersistedDraft();
3190
- return;
3191
- }
3192
- const segments = paths.canonicalizePath(pathInput).segments;
3193
- await persistence.clearPersistedDraft(segments);
3194
- };
3195
3160
  function touch(pathInput) {
3196
3161
  const segments = pathInput === void 0 ? paths.ROOT_PATH : paths.canonicalizePath(pathInput).segments;
3197
3162
  state.touchAtPath(segments);
@@ -3276,7 +3241,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
3276
3241
  }
3277
3242
  return Object.freeze(out);
3278
3243
  }
3279
- return {
3244
+ const api = {
3280
3245
  handleSubmit: gated(handleSubmit),
3281
3246
  // Callable readonly Proxies (`values`, `fields`, `errors`) and the
3282
3247
  // reactive containers (`meta`, `history`, `blankPaths`) are exposed
@@ -3341,8 +3306,6 @@ function buildFormApi(state, formInstanceId, options = {}) {
3341
3306
  reset: gated(reset),
3342
3307
  resetField: gated(resetField),
3343
3308
  clear: gated(clear),
3344
- persist: gated(persist),
3345
- clearPersistedDraft: gated(clearPersistedDraft),
3346
3309
  focusFirstError: gated(focusFirstError),
3347
3310
  scrollToFirstError: gated(scrollToFirstError),
3348
3311
  applyInvalidSubmitPolicy: gated(applyInvalidSubmitPolicyPublic),
@@ -3365,6 +3328,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
3365
3328
  return blankPathsView;
3366
3329
  }
3367
3330
  };
3331
+ return api;
3368
3332
  }
3369
3333
 
3370
3334
  const IDLE = Object.freeze({ display: "idle" });
@@ -3791,6 +3755,7 @@ function createArrayBookkeeping(deps) {
3791
3755
  originals,
3792
3756
  blankPaths,
3793
3757
  originalBlankPaths,
3758
+ authoredPaths,
3794
3759
  fieldValidationCounts,
3795
3760
  fieldValidatingSince,
3796
3761
  fieldValidationState,
@@ -3818,6 +3783,7 @@ function createArrayBookkeeping(deps) {
3818
3783
  }));
3819
3784
  migrateSetSubtree(blankPaths, arrayPath, remap);
3820
3785
  migrateSetSubtree(originalBlankPaths, arrayPath, remap);
3786
+ migrateSetSubtree(authoredPaths, arrayPath, remap);
3821
3787
  migrateMapSubtree(fieldValidatingSince, arrayPath, remap, (since) => since);
3822
3788
  migrateMapSubtree(fieldValidationCounts, arrayPath, remap, (count) => count);
3823
3789
  arrayIdentity.applyRemap(arrayPath, remap);
@@ -3861,7 +3827,7 @@ function createArrayBookkeeping(deps) {
3861
3827
  activeValidations.value = Math.max(0, activeValidations.value - 1);
3862
3828
  decFieldValidation(key);
3863
3829
  }
3864
- entry.controller.abort();
3830
+ entry.aborted = true;
3865
3831
  fieldValidationState.delete(key);
3866
3832
  }
3867
3833
  }
@@ -3873,6 +3839,57 @@ function createArrayBookkeeping(deps) {
3873
3839
  };
3874
3840
  }
3875
3841
 
3842
+ function mergeSparseHydration(schemaDefaults, sparse, schema) {
3843
+ return mergeDeep(schemaDefaults, sparse, [], schema);
3844
+ }
3845
+ function mergeDeep(target, source, path, schema) {
3846
+ if (source === void 0) return target;
3847
+ if (source === null || typeof source !== "object") return source;
3848
+ if (Array.isArray(source)) return source;
3849
+ if (!isPlainRecord(source)) return source;
3850
+ if (schema !== void 0) {
3851
+ const du = schema.getUnionDiscriminatorAtPath(path);
3852
+ if (du !== void 0) return mergeDuAwareKeys(source, path, schema, du);
3853
+ }
3854
+ return mergeObjectKeys(target, source, path, schema);
3855
+ }
3856
+ function mergeDuAwareKeys(source, path, schema, du) {
3857
+ const sourceDisc = source[du.discriminatorKey];
3858
+ if (sourceDisc !== void 0 && !du.isVariantSelected(sourceDisc)) {
3859
+ return { [du.discriminatorKey]: sourceDisc };
3860
+ }
3861
+ if (sourceDisc !== void 0) {
3862
+ const variantDefault = du.getVariantDefault(sourceDisc);
3863
+ if (isPlainRecord(variantDefault)) {
3864
+ return mergeVariantKeys(source, variantDefault, path, schema, du);
3865
+ }
3866
+ }
3867
+ return {};
3868
+ }
3869
+ function mergeVariantKeys(source, variantDefault, path, schema, du) {
3870
+ const out = { ...variantDefault };
3871
+ for (const key of Object.keys(source)) {
3872
+ if (!safeOwnHas(variantDefault, key) && key !== du.discriminatorKey) continue;
3873
+ safeAssign(
3874
+ out,
3875
+ key,
3876
+ mergeDeep(safeOwnRead(out, key), safeOwnRead(source, key), [...path, key], schema)
3877
+ );
3878
+ }
3879
+ return out;
3880
+ }
3881
+ function mergeObjectKeys(target, source, path, schema) {
3882
+ const out = isPlainRecord(target) ? { ...target } : {};
3883
+ for (const key of Object.keys(source)) {
3884
+ safeAssign(
3885
+ out,
3886
+ key,
3887
+ mergeDeep(safeOwnRead(out, key), safeOwnRead(source, key), [...path, key], schema)
3888
+ );
3889
+ }
3890
+ return out;
3891
+ }
3892
+
3876
3893
  function isHydratedFieldRecord(value) {
3877
3894
  if (typeof value !== "object" || value === null) return false;
3878
3895
  const r = value;
@@ -3957,6 +3974,17 @@ function walkAuthoredFromConstraints(value, prefix, out) {
3957
3974
  }
3958
3975
  }
3959
3976
  }
3977
+ function freshElementIndices(op) {
3978
+ switch (op.kind) {
3979
+ case "insert":
3980
+ case "replace-at":
3981
+ return [op.index];
3982
+ case "remove":
3983
+ case "swap":
3984
+ case "move":
3985
+ return [];
3986
+ }
3987
+ }
3960
3988
  function walkAuthoredFromSchemaDiff(withDefaults, withoutDefaults, prefix, out) {
3961
3989
  if (isPlainRecord(withDefaults) && isPlainRecord(withoutDefaults)) {
3962
3990
  const left = withDefaults;
@@ -3995,26 +4023,8 @@ function createFormStore(options) {
3995
4023
  const formChangeListeners = /* @__PURE__ */ new Set();
3996
4024
  const submitSuccessListeners = /* @__PURE__ */ new Set();
3997
4025
  const resetListeners = /* @__PURE__ */ new Set();
3998
- const persistOptIns = paths.createPersistOptInRegistry();
3999
- const noSyncPaths = /* @__PURE__ */ new Set();
4000
- const noSyncPathCounts = /* @__PURE__ */ new Map();
4001
- function incrementNoSyncOptOut(path) {
4002
- const next = (noSyncPathCounts.get(path) ?? 0) + 1;
4003
- noSyncPathCounts.set(path, next);
4004
- if (next === 1) noSyncPaths.add(path);
4005
- }
4006
- function decrementNoSyncOptOut(path) {
4007
- const current = noSyncPathCounts.get(path) ?? 0;
4008
- if (current <= 1) {
4009
- noSyncPathCounts.delete(path);
4010
- noSyncPaths.delete(path);
4011
- return;
4012
- }
4013
- noSyncPathCounts.set(path, current - 1);
4014
- }
4015
4026
  const coerceIndex = resolveCoercionIndex(options.coerce);
4016
4027
  const resolvedGetDisplayState = resolveGetDisplayState(options.getDisplayState);
4017
- const resolvedIsSensitivePath = options.isSensitivePath ?? paths.isSensitivePath;
4018
4028
  const cleanupHooks = [];
4019
4029
  const modules = /* @__PURE__ */ new Map();
4020
4030
  const fieldValidatingSince = vue.reactive(/* @__PURE__ */ new Map());
@@ -4033,11 +4043,8 @@ function createFormStore(options) {
4033
4043
  if (constraints !== void 0) {
4034
4044
  walkAuthoredFromConstraints(constraints, [], authoredPaths);
4035
4045
  }
4036
- const slimResponse = schema.getDefaultValues({
4037
- useDefaultSchemaValues: false,
4038
- strict
4039
- });
4040
- walkAuthoredFromSchemaDiff(schemaWithDefaultsData, slimResponse.data, [], authoredPaths);
4046
+ const slimBaseline = schema.getEmptyValueAtPath([]);
4047
+ walkAuthoredFromSchemaDiff(schemaWithDefaultsData, slimBaseline, [], authoredPaths);
4041
4048
  }
4042
4049
  rebuildAuthoredPaths(defaultValues, schemaInitialData);
4043
4050
  function filterAuthoredErrors(errors) {
@@ -4056,7 +4063,7 @@ function createFormStore(options) {
4056
4063
  });
4057
4064
  const form = vue.ref(stubbedInitialData);
4058
4065
  const arrayIdentity = createArrayIdentity((arraySegs) => {
4059
- const v = getAtPath(form.value, arraySegs);
4066
+ const v = getAtPath(vue.toRaw(form.value), arraySegs);
4060
4067
  return Array.isArray(v) ? v.length : 0;
4061
4068
  });
4062
4069
  function arrayElementKey(path) {
@@ -4099,14 +4106,7 @@ function createFormStore(options) {
4099
4106
  const segments = paths.segmentsForPathKey(pathKey);
4100
4107
  if (segments === null) continue;
4101
4108
  if (!schema.isRequiredAtPath(segments)) continue;
4102
- result.set(pathKey, [
4103
- {
4104
- message: "No value supplied",
4105
- path: [...segments],
4106
- formKey,
4107
- code: AttaformErrorCode.NoValueSupplied
4108
- }
4109
- ]);
4109
+ result.set(pathKey, [makeBlankRequiredError(segments, formKey)]);
4110
4110
  }
4111
4111
  return result;
4112
4112
  });
@@ -4346,6 +4346,7 @@ function createFormStore(options) {
4346
4346
  originals,
4347
4347
  blankPaths,
4348
4348
  originalBlankPaths,
4349
+ authoredPaths,
4349
4350
  fieldValidationCounts,
4350
4351
  fieldValidatingSince,
4351
4352
  fieldValidationState,
@@ -4355,17 +4356,8 @@ function createFormStore(options) {
4355
4356
  touchFieldRecord,
4356
4357
  decFieldValidation
4357
4358
  });
4358
- function applyFormReplacement(next, meta) {
4359
- const prev = form.value;
4360
- if (Object.is(prev, next)) return;
4359
+ function commitWritePatches(patches, meta) {
4361
4360
  const now = (/* @__PURE__ */ new Date()).toISOString();
4362
- const patches = [];
4363
- diffAndApply(prev, next, [], (patch) => {
4364
- patches.push(patch);
4365
- });
4366
- if (!applyChangedKeys(prev, next)) {
4367
- form.value = next;
4368
- }
4369
4361
  for (const patch of patches) {
4370
4362
  const { key } = paths.canonicalizePath(patch.path);
4371
4363
  if (patch.kind === "added" && !originals.has(key)) {
@@ -4381,9 +4373,61 @@ function createFormStore(options) {
4381
4373
  }
4382
4374
  }
4383
4375
  }
4376
+ function applyFormReplacementWithPath(next, meta, arrayOpPath) {
4377
+ const prev = form.value;
4378
+ if (Object.is(prev, next)) return;
4379
+ const patches = [];
4380
+ diffAndApply(prev, next, [], (patch) => {
4381
+ patches.push(patch);
4382
+ });
4383
+ if (!applyChangedKeys(prev, next, arrayOpPath, [])) {
4384
+ form.value = next;
4385
+ } else if (patches.some(
4386
+ (p) => p.path.length > 0 && typeof p.path[0] === "string" && isShadowedKey(p.path[0])
4387
+ )) {
4388
+ vue.triggerRef(form);
4389
+ }
4390
+ commitWritePatches(patches, meta);
4391
+ }
4392
+ function applyFormReplacement(next, meta) {
4393
+ applyFormReplacementWithPath(next, meta, null);
4394
+ }
4395
+ function applyTargetedWrite(path, completedValue, meta) {
4396
+ const result = tryInPlaceLeafWrite(form.value, path, completedValue);
4397
+ if (!result.applied) {
4398
+ applyFormReplacementWithPath(
4399
+ setAtPathWithSchemaFill(form.value, schema, path, completedValue),
4400
+ meta,
4401
+ meta?.arrayOp !== void 0 ? path : null
4402
+ );
4403
+ return;
4404
+ }
4405
+ const patches = [];
4406
+ diffAndApply(result.old, completedValue, path, (patch) => {
4407
+ patches.push(patch);
4408
+ });
4409
+ commitWritePatches(patches, meta);
4410
+ }
4384
4411
  function setValueAtPath(path, value, meta) {
4385
- value = stripSymbolsDeep(value);
4386
- if (!isSlimPrimitiveValid(schema, form, path, value)) {
4412
+ if (meta?.arrayOp !== void 0 && Array.isArray(value)) {
4413
+ for (const idx of freshElementIndices(meta.arrayOp)) {
4414
+ value[idx] = stripSymbolsDeep(value[idx]);
4415
+ }
4416
+ } else {
4417
+ value = stripSymbolsDeep(value);
4418
+ }
4419
+ let slimOk = true;
4420
+ if (meta?.arrayOp !== void 0 && Array.isArray(value)) {
4421
+ for (const idx of freshElementIndices(meta.arrayOp)) {
4422
+ if (!isSlimPrimitiveValid(schema, form, [...path, idx], value[idx])) {
4423
+ slimOk = false;
4424
+ break;
4425
+ }
4426
+ }
4427
+ } else {
4428
+ slimOk = isSlimPrimitiveValid(schema, form, path, value);
4429
+ }
4430
+ if (!slimOk) {
4387
4431
  return false;
4388
4432
  }
4389
4433
  if (path.length >= 2) {
@@ -4476,22 +4520,37 @@ function createFormStore(options) {
4476
4520
  }
4477
4521
  }
4478
4522
  }
4523
+ const currentValue = getAtPath(form.value, path);
4479
4524
  const pathKey = paths.canonicalizePath(path).key;
4480
4525
  if (meta?.blank === true) {
4481
4526
  blankPaths.add(pathKey);
4482
4527
  } else {
4483
4528
  if (blankPaths.has(pathKey)) blankPaths.delete(pathKey);
4484
- if (meta?.arrayOp === void 0) {
4529
+ if (meta?.arrayOp === void 0 && (isPlainRecord(currentValue) || Array.isArray(currentValue))) {
4485
4530
  for (const existingKey of [...blankPaths]) {
4486
4531
  if (isPathKeyUnder(existingKey, path)) blankPaths.delete(existingKey);
4487
4532
  }
4488
4533
  }
4489
4534
  }
4490
4535
  const wasAuthoredBefore = authoredPaths.has(pathKey);
4491
- walkAuthoredFromConstraints(value, path, authoredPaths);
4536
+ if (meta?.arrayOp !== void 0 && Array.isArray(value)) {
4537
+ if (path.length > 0) authoredPaths.add(pathKey);
4538
+ for (const idx of freshElementIndices(meta.arrayOp)) {
4539
+ walkAuthoredFromConstraints(value[idx], [...path, idx], authoredPaths);
4540
+ }
4541
+ } else {
4542
+ walkAuthoredFromConstraints(value, path, authoredPaths);
4543
+ }
4492
4544
  const newlyAuthored = !wasAuthoredBefore && authoredPaths.has(pathKey);
4493
- const completedValue = mergeStructural(schema, path, value);
4494
- const currentValue = getAtPath(form.value, path);
4545
+ let completedValue;
4546
+ if (meta?.arrayOp !== void 0 && Array.isArray(value)) {
4547
+ for (const idx of freshElementIndices(meta.arrayOp)) {
4548
+ value[idx] = mergeStructural(schema, [...path, idx], value[idx]);
4549
+ }
4550
+ completedValue = value;
4551
+ } else {
4552
+ completedValue = mergeStructural(schema, path, value);
4553
+ }
4495
4554
  if (Object.is(currentValue, completedValue)) {
4496
4555
  if (newlyAuthored && schema.isPreprocessOrCoerceLeaf(path)) {
4497
4556
  const modeForAuthoringTransition = meta?.instance?.validateOn ?? fieldValidationMode;
@@ -4505,8 +4564,7 @@ function createFormStore(options) {
4505
4564
  return true;
4506
4565
  }
4507
4566
  const oldArrayLength = Array.isArray(currentValue) ? currentValue.length : 0;
4508
- const nextForm = setAtPathWithSchemaFill(form.value, schema, path, completedValue);
4509
- applyFormReplacement(nextForm, meta);
4567
+ applyTargetedWrite(path, completedValue, meta);
4510
4568
  if (meta?.arrayOp !== void 0) {
4511
4569
  const remap = remapForOp(meta.arrayOp, oldArrayLength);
4512
4570
  arrayBookkeeping.migrateElementState(path, remap);
@@ -4589,7 +4647,7 @@ function createFormStore(options) {
4589
4647
  const prevValidation = fieldValidationState.get(parentKey2);
4590
4648
  if (prevValidation !== void 0) {
4591
4649
  if (prevValidation.timer !== null) clearTimeout(prevValidation.timer);
4592
- prevValidation.controller.abort();
4650
+ prevValidation.aborted = true;
4593
4651
  fieldValidationState.delete(parentKey2);
4594
4652
  }
4595
4653
  appliedSync = true;
@@ -4613,15 +4671,19 @@ function createFormStore(options) {
4613
4671
  const prev = fieldValidationState.get(key);
4614
4672
  if (prev !== void 0) {
4615
4673
  if (prev.timer !== null) clearTimeout(prev.timer);
4616
- prev.controller.abort();
4674
+ prev.aborted = true;
4617
4675
  }
4618
- const controller = new AbortController();
4619
- const fresh = { controller, timer: null, settled: false, released: false };
4676
+ const fresh = {
4677
+ aborted: false,
4678
+ timer: null,
4679
+ settled: false,
4680
+ released: false
4681
+ };
4620
4682
  fieldValidationState.set(key, fresh);
4621
4683
  const myEpoch = ++scheduleEpoch;
4622
4684
  const run = () => {
4623
4685
  fresh.timer = null;
4624
- if (controller.signal.aborted) return;
4686
+ if (fresh.aborted) return;
4625
4687
  let activeIncremented = false;
4626
4688
  try {
4627
4689
  activeValidations.value += 1;
@@ -4638,7 +4700,7 @@ function createFormStore(options) {
4638
4700
  const dataAtScope = subtreeScope ? getAtPath(form.value, path) : form.value;
4639
4701
  const scopeKey = subtreeScope ? paths.canonicalizePath(path).key : paths.ROOT_PATH_KEY;
4640
4702
  void Promise.resolve().then(() => schema.validateAtPath(dataAtScope, scopePath)).then((response) => {
4641
- if (controller.signal.aborted) return;
4703
+ if (fresh.aborted) return;
4642
4704
  if (myEpoch <= lastCommittedEpoch) return;
4643
4705
  lastCommittedEpoch = myEpoch;
4644
4706
  if (effectiveMode === "blur") {
@@ -4675,7 +4737,7 @@ function createFormStore(options) {
4675
4737
  activeValidations.value = Math.max(0, activeValidations.value - 1);
4676
4738
  decFieldValidation(pkey);
4677
4739
  }
4678
- entry.controller.abort();
4740
+ entry.aborted = true;
4679
4741
  }
4680
4742
  fieldValidationState.clear();
4681
4743
  }
@@ -4691,7 +4753,7 @@ function createFormStore(options) {
4691
4753
  decFieldValidation(key);
4692
4754
  entry.released = true;
4693
4755
  }
4694
- entry.controller.abort();
4756
+ entry.aborted = true;
4695
4757
  fieldValidationState.delete(key);
4696
4758
  }
4697
4759
  }
@@ -4750,9 +4812,6 @@ function createFormStore(options) {
4750
4812
  formChangeListeners.clear();
4751
4813
  submitSuccessListeners.clear();
4752
4814
  resetListeners.clear();
4753
- persistOptIns.clear();
4754
- noSyncPaths.clear();
4755
- noSyncPathCounts.clear();
4756
4815
  }
4757
4816
  function getValueAtPath(path) {
4758
4817
  return getAtPath(form.value, path);
@@ -5308,11 +5367,6 @@ function createFormStore(options) {
5308
5367
  registerDrain,
5309
5368
  awaitPendingWrites,
5310
5369
  modules,
5311
- persistOptIns,
5312
- isSensitivePath: resolvedIsSensitivePath,
5313
- noSyncPaths,
5314
- incrementNoSyncOptOut,
5315
- decrementNoSyncOptOut,
5316
5370
  coerceIndex,
5317
5371
  blankPaths,
5318
5372
  originalBlankPaths,
@@ -5320,6 +5374,33 @@ function createFormStore(options) {
5320
5374
  };
5321
5375
  }
5322
5376
 
5377
+ function captureUserCallSite() {
5378
+ const raw = new Error().stack;
5379
+ if (typeof raw !== "string") return void 0;
5380
+ const lines = raw.split("\n");
5381
+ for (let i = 1; i < lines.length; i++) {
5382
+ const frame = lines[i];
5383
+ if (frame === void 0) continue;
5384
+ if (/attaform[/-]forms?/i.test(frame)) continue;
5385
+ if (/\bforms\.[A-Za-z0-9_-]+\.m?js\b/.test(frame)) continue;
5386
+ const trimmed = frame.trim();
5387
+ if (trimmed.length === 0) continue;
5388
+ return shortenSourceFrame(trimmed);
5389
+ }
5390
+ return void 0;
5391
+ }
5392
+ function shortenSourceFrame(frame) {
5393
+ const match = /(?:^|\s|\()([^\s()]+):(\d+):\d+\)?$/.exec(frame);
5394
+ if (match === null) return frame;
5395
+ const [, urlOrPath, line] = match;
5396
+ if (urlOrPath === void 0 || line === void 0) return frame;
5397
+ let path = urlOrPath;
5398
+ path = path.replace(/^[a-z]+:\/\/[^/]+\//i, "");
5399
+ path = path.replace(/^_nuxt\//, "");
5400
+ path = path.replace(/^\//, "");
5401
+ return `(${path}:${line})`;
5402
+ }
5403
+
5323
5404
  function getComputedSchema(formKey, schemaOrCallback, options) {
5324
5405
  if (typeof schemaOrCallback === "function") return schemaOrCallback(formKey, options);
5325
5406
  return schemaOrCallback;
@@ -5330,19 +5411,12 @@ function captureErrorEntries(map) {
5330
5411
  for (const [k, v] of map) out.push([k, [...v]]);
5331
5412
  return out;
5332
5413
  }
5333
- function pathsEqual(a, b) {
5334
- if (a.length !== b.length) return false;
5335
- for (let j = 0; j < a.length; j++) {
5336
- if (a[j] !== b[j]) return false;
5337
- }
5338
- return true;
5339
- }
5340
5414
  function errorFieldsEqual(av, bvi) {
5341
5415
  if (av === bvi) return true;
5342
5416
  if (av.message !== bvi.message) return false;
5343
5417
  if (av.code !== bvi.code) return false;
5344
5418
  if (av.formKey !== bvi.formKey) return false;
5345
- return av.path === bvi.path || pathsEqual(av.path, bvi.path);
5419
+ return av.path === bvi.path || paths.pathsEqual(av.path, bvi.path);
5346
5420
  }
5347
5421
  function errorsEqual(a, b) {
5348
5422
  if (a.length !== b.length) return false;
@@ -5436,10 +5510,6 @@ function createHistoryModule(state, config) {
5436
5510
  clear();
5437
5511
  return;
5438
5512
  }
5439
- if (meta?.crossTab === true) {
5440
- currentSnapshot.value = captureSnapshot();
5441
- return;
5442
- }
5443
5513
  const newSnap = captureSnapshot();
5444
5514
  const prevSnap = currentSnapshot.value;
5445
5515
  const formPatches = [];
@@ -5460,9 +5530,7 @@ function createHistoryModule(state, config) {
5460
5530
  suppressNext = true;
5461
5531
  state.blankPaths.clear();
5462
5532
  for (const key of snap.blankPaths) state.blankPaths.add(key);
5463
- state.applyFormReplacement(snap.form, {
5464
- persist: !state.persistOptIns.isEmpty()
5465
- });
5533
+ state.applyFormReplacement(snap.form);
5466
5534
  const schemaFlat = snap.schemaErrors.flatMap(([, errs]) => errs);
5467
5535
  const userFlat = snap.userErrors.flatMap(([, errs]) => errs);
5468
5536
  state.setAllSchemaErrors(schemaFlat);
@@ -5513,28 +5581,6 @@ function createHistoryModule(state, config) {
5513
5581
  };
5514
5582
  }
5515
5583
 
5516
- const warned = /* @__PURE__ */ new Set();
5517
- function warnOnceInsecureContext(feature) {
5518
- if (!paths.__DEV__) return;
5519
- if (warned.has(feature)) return;
5520
- warned.add(feature);
5521
- const message = featureMessage(feature);
5522
- console.warn(`[attaform] ${message}`);
5523
- }
5524
- function featureMessage(feature) {
5525
- switch (feature) {
5526
- case "multiTab":
5527
- return "Multi-tab sync requires a secure context (HTTPS or localhost). Plain HTTP on a real hostname is interceptable by network observers, so the sync module is disabled. Serve over HTTPS in production (or develop on `localhost`) to enable cross-tab synchronisation. Use `multiTab: false` on `useForm` to silence this warning.";
5528
- case "persist:local":
5529
- return "Built-in `persist: 'local'` storage requires a secure context (HTTPS or localhost). Plain HTTP on a real hostname is MITM-interceptable, so the persistence layer is disabled. Serve over HTTPS to enable localStorage persistence, or pass a custom storage adapter to opt out of the secure-context gate.";
5530
- case "persist:session":
5531
- return "Built-in `persist: 'session'` storage requires a secure context (HTTPS or localhost). Plain HTTP on a real hostname is MITM-interceptable, so the persistence layer is disabled. Serve over HTTPS to enable sessionStorage persistence, or pass a custom storage adapter to opt out of the secure-context gate.";
5532
- }
5533
- }
5534
- function isSecureContext() {
5535
- return typeof window !== "undefined" && window.isSecureContext === true;
5536
- }
5537
-
5538
5584
  function resolveTrichotomy(input) {
5539
5585
  if (typeof input === "function") {
5540
5586
  return { kind: "async", factory: input };
@@ -5563,18 +5609,10 @@ function useAbstractForm(configuration, options) {
5563
5609
  defaultValue: DEFAULT_MAX_RECURSION_DEPTH
5564
5610
  });
5565
5611
  const resolvedSchema = getComputedSchema(key, configuration.schema, { maxRecursionDepth });
5566
- if (configuration.persist !== void 0 && configuration.key === void 0) {
5567
- throw new paths.AnonPersistError({
5568
- cause: "no-key",
5569
- schemaFields: extractSchemaFields(resolvedSchema),
5570
- callSite: captureUserCallSite()
5571
- });
5572
- }
5573
5612
  const existing = registry.forms.get(key);
5574
5613
  if (paths.__DEV__ && existing !== void 0) {
5575
5614
  void import('../chunks/dev-key-collision-warnings.cjs').then((m) => {
5576
5615
  void m.warnOnSchemaFingerprintMismatch(key, existing.schema, resolvedSchema);
5577
- m.warnOnPersistDivergence(key, existing, configuration.persist);
5578
5616
  });
5579
5617
  }
5580
5618
  const hadPendingHydration = registry.pendingHydration.has(key);
@@ -5602,85 +5640,6 @@ function useAbstractForm(configuration, options) {
5602
5640
  const releaseConsumer = registry.trackConsumer(key);
5603
5641
  vue.onScopeDispose(releaseConsumer);
5604
5642
  }
5605
- const persistDisabledByAnonRule = merged.persist !== void 0 && enforceAnonPersistRule(state.formKey, registry.ssr);
5606
- if (existing === void 0 && !registry.ssr) {
5607
- if (merged.persist !== void 0 && !persistDisabledByAnonRule) {
5608
- const resolvedPersist = normalizePersistConfig(merged.persist);
5609
- const storageKind = resolvedPersist.storage;
5610
- const isBuiltinStorage = typeof storageKind === "string";
5611
- const secureContextOk = !isBuiltinStorage || isSecureContext();
5612
- if (!secureContextOk) {
5613
- const feature = storageKind === "session" ? "persist:session" : "persist:local";
5614
- warnOnceInsecureContext(feature);
5615
- void sweepAllOrphansAcrossStandardStores(`${PERSISTENCE_KEY_PREFIX}${state.formKey}`);
5616
- } else {
5617
- const persistenceBase = resolveStorageKeyBase(resolvedPersist, state.formKey);
5618
- void sweepNonConfiguredStandardStoresForOrphans(resolvedPersist.storage, persistenceBase);
5619
- const adapterPromise = getStorageAdapter(resolvedPersist.storage);
5620
- let persistDisposed = false;
5621
- state.registerCleanup(() => {
5622
- persistDisposed = true;
5623
- });
5624
- const ready = (async () => {
5625
- try {
5626
- const [{ wirePersistence }, fingerprintToken] = await Promise.all([
5627
- import('../chunks/wire-persistence.cjs'),
5628
- resolvePersistFingerprintToken(state)
5629
- ]);
5630
- if (persistDisposed) return void 0;
5631
- const persistenceModule = wirePersistence(
5632
- state,
5633
- resolvedPersist,
5634
- adapterPromise,
5635
- fingerprintToken
5636
- );
5637
- state.registerDrain(() => persistenceModule.awaitPendingWrites());
5638
- state.registerCleanup(() => persistenceModule.dispose());
5639
- return persistenceModule;
5640
- } catch {
5641
- return void 0;
5642
- }
5643
- })();
5644
- const persistenceHandle = { config: resolvedPersist, ready };
5645
- state.modules.set(PERSISTENCE_MODULE_KEY, persistenceHandle);
5646
- }
5647
- } else {
5648
- void sweepAllOrphansAcrossStandardStores(`${PERSISTENCE_KEY_PREFIX}${state.formKey}`);
5649
- }
5650
- }
5651
- if (existing === void 0 && merged.multiTab === true && configuration.key !== void 0 && !registry.ssr) {
5652
- const hasBroadcastChannel = typeof BroadcastChannel !== "undefined";
5653
- const secureContext = isSecureContext();
5654
- if (hasBroadcastChannel && secureContext) {
5655
- let formDisposed = false;
5656
- state.registerCleanup(() => {
5657
- formDisposed = true;
5658
- });
5659
- void (async () => {
5660
- try {
5661
- const [{ createMultiTabSyncModule, MULTI_TAB_SYNC_MODULE_KEY }, fingerprint] = await Promise.all([import('../chunks/multi-tab-sync.cjs'), state.schema.fingerprint()]);
5662
- if (formDisposed) return;
5663
- const channelName = `attaform:sync:${state.formKey}:${hashStableString(fingerprint)}`;
5664
- const syncModule = createMultiTabSyncModule(state, channelName, {
5665
- isSensitivePath: state.isSensitivePath,
5666
- noSyncPaths: state.noSyncPaths,
5667
- validateForm: (form) => {
5668
- const result = state.schema.validateAtPath(form, void 0, { sync: true });
5669
- if (result instanceof Promise) return;
5670
- if (!result.success) {
5671
- throw new Error("attaform multi-tab sync: post-apply schema validation failed");
5672
- }
5673
- }
5674
- });
5675
- state.modules.set(MULTI_TAB_SYNC_MODULE_KEY, syncModule);
5676
- state.registerCleanup(() => syncModule.dispose());
5677
- } catch {
5678
- }
5679
- })();
5680
- } else if (hasBroadcastChannel && !secureContext) {
5681
- warnOnceInsecureContext("multiTab");
5682
- }
5683
- }
5684
5643
  if (existing === void 0 && merged.history !== void 0) {
5685
5644
  const historyModule = createHistoryModule(state, merged.history);
5686
5645
  state.modules.set(HISTORY_MODULE_KEY, historyModule);
@@ -5721,11 +5680,8 @@ function useAbstractForm(configuration, options) {
5721
5680
  if (merged.autoAria !== void 0) {
5722
5681
  apiOptions.autoAria = merged.autoAria;
5723
5682
  }
5724
- return buildFormApi(
5725
- state,
5726
- formInstanceId,
5727
- apiOptions
5728
- );
5683
+ const api = buildFormApi(state, formInstanceId, apiOptions);
5684
+ return api;
5729
5685
  }
5730
5686
  function mergeWithDefaults(defaults, configuration) {
5731
5687
  const strict = configuration.strict ?? defaults.strict;
@@ -5737,8 +5693,6 @@ function mergeWithDefaults(defaults, configuration) {
5737
5693
  const debounceMs = configuration.debounceMs ?? defaults.debounceMs;
5738
5694
  const getDisplayState = configuration.getDisplayState ?? defaults.getDisplayState;
5739
5695
  const maxRecursionDepth = configuration.maxRecursionDepth ?? defaults.maxRecursionDepth;
5740
- const sensitiveNames = configuration.sensitiveNames ?? defaults.sensitiveNames;
5741
- const multiTab = configuration.multiTab ?? defaults.multiTab;
5742
5696
  const autoAria = configuration.autoAria ?? defaults.autoAria;
5743
5697
  return {
5744
5698
  ...configuration,
@@ -5751,8 +5705,6 @@ function mergeWithDefaults(defaults, configuration) {
5751
5705
  ...debounceMs === void 0 ? {} : { debounceMs },
5752
5706
  ...getDisplayState === void 0 ? {} : { getDisplayState },
5753
5707
  ...maxRecursionDepth === void 0 ? {} : { maxRecursionDepth },
5754
- ...sensitiveNames === void 0 ? {} : { sensitiveNames },
5755
- ...multiTab === void 0 ? {} : { multiTab },
5756
5708
  ...autoAria === void 0 ? {} : { autoAria }
5757
5709
  };
5758
5710
  }
@@ -5768,8 +5720,6 @@ function buildFreshState(key, schema, configuration, registry) {
5768
5720
  if (pending === void 0) {
5769
5721
  initialBlankPaths = walked.paths;
5770
5722
  }
5771
- const resolvedSensitiveNames = configuration.sensitiveNames;
5772
- const resolvedIsSensitivePath = resolvedSensitiveNames === void 0 ? void 0 : paths.createIsSensitivePath(resolvedSensitiveNames);
5773
5723
  const createOptions = {
5774
5724
  formKey: key,
5775
5725
  schema,
@@ -5797,8 +5747,7 @@ function buildFreshState(key, schema, configuration, registry) {
5797
5747
  ...configuration.rememberVariants !== void 0 ? { rememberVariants: configuration.rememberVariants } : {},
5798
5748
  ...configuration.coerce !== void 0 ? { coerce: configuration.coerce } : {},
5799
5749
  ...configuration.getDisplayState !== void 0 ? { getDisplayState: configuration.getDisplayState } : {},
5800
- ...initialBlankPaths !== void 0 ? { initialBlankPaths } : {},
5801
- ...resolvedIsSensitivePath !== void 0 ? { isSensitivePath: resolvedIsSensitivePath } : {}
5750
+ ...initialBlankPaths !== void 0 ? { initialBlankPaths } : {}
5802
5751
  };
5803
5752
  const state = createFormStore(createOptions);
5804
5753
  registry.forms.set(
@@ -5837,34 +5786,6 @@ function resolveFormKey(key) {
5837
5786
  }
5838
5787
  return `${ANONYMOUS_FORM_KEY_PREFIX}${anonCounter++}`;
5839
5788
  }
5840
- async function resolvePersistFingerprintToken(state) {
5841
- try {
5842
- return hashStableString(await state.schema.fingerprint());
5843
- } catch (err) {
5844
- if (paths.__DEV__) {
5845
- console.warn(
5846
- `[attaform] Could not fingerprint the schema for form '${state.formKey}': ${err instanceof Error ? err.message : String(err)}. Persistence falls back to a fingerprint-free key, so a schema change won't auto-invalidate a saved draft.`
5847
- );
5848
- }
5849
- return "unfingerprinted";
5850
- }
5851
- }
5852
- const warnedAnonPersistKeys = /* @__PURE__ */ new Set();
5853
- function enforceAnonPersistRule(formKey, ssr) {
5854
- if (!formKey.startsWith(ANONYMOUS_FORM_KEY_PREFIX)) return false;
5855
- if (paths.__DEV__)
5856
- throw new paths.AnonPersistError({
5857
- cause: "no-key",
5858
- callSite: captureUserCallSite()
5859
- });
5860
- if (!ssr && !warnedAnonPersistKeys.has(formKey)) {
5861
- warnedAnonPersistKeys.add(formKey);
5862
- console.warn(
5863
- "[attaform] persist: ignored \u2014 anonymous useForm() can't safely persist (key drift + cross-form collision risk).\n Persistence is disabled for this form; the app keeps working.\n Fix: useForm({ schema, key: 'login', persist: '...' })"
5864
- );
5865
- }
5866
- return true;
5867
- }
5868
5789
 
5869
5790
  let injectedInstanceCounter = 0;
5870
5791
  function injectForm(input) {
@@ -7092,16 +7013,10 @@ function warnIfAmbientWizardProviderHadDuplicates() {
7092
7013
  }
7093
7014
 
7094
7015
  exports.AttaformErrorCode = AttaformErrorCode;
7095
- exports.DEFAULT_PERSISTENCE_DEBOUNCE_MS = DEFAULT_PERSISTENCE_DEBOUNCE_MS;
7096
7016
  exports.DEFAULT_TIMINGS = DEFAULT_TIMINGS;
7097
- exports.PERSISTENCE_MODULE_KEY = PERSISTENCE_MODULE_KEY;
7098
- exports.applyPatchesForward = applyPatchesForward;
7099
- exports.cleanupOrphanKeys = cleanupOrphanKeys;
7100
7017
  exports.defaultCoercionRules = defaultCoercionRules;
7101
7018
  exports.defaultDisplayState = defaultDisplayState;
7102
7019
  exports.defineCoercion = defineCoercion;
7103
- exports.deleteAtPath = deleteAtPath;
7104
- exports.diffAndApply = diffAndApply;
7105
7020
  exports.getAtPath = getAtPath;
7106
7021
  exports.humanize = humanize;
7107
7022
  exports.injectForm = injectForm;
@@ -7110,17 +7025,13 @@ exports.isPlainRecord = isPlainRecord;
7110
7025
  exports.isUnset = isUnset;
7111
7026
  exports.lazy = lazy;
7112
7027
  exports.makeDefaultDisplayState = makeDefaultDisplayState;
7113
- exports.mergeSparseHydration = mergeSparseHydration;
7114
7028
  exports.normalizeNumericOption = normalizeNumericOption;
7115
- exports.normalizePersistConfig = normalizePersistConfig;
7116
- exports.resolveStorageKeyBase = resolveStorageKeyBase;
7117
7029
  exports.safeAssign = safeAssign;
7118
7030
  exports.safeOwnRead = safeOwnRead;
7119
7031
  exports.setAtPath = setAtPath;
7120
7032
  exports.slimKindOf = slimKindOf;
7121
- exports.structuralSnapshot = structuralSnapshot;
7122
7033
  exports.unset = unset;
7123
7034
  exports.useAbstractForm = useAbstractForm;
7124
7035
  exports.useRegister = useRegister;
7125
7036
  exports.useWizard = useWizard;
7126
- //# sourceMappingURL=attaform.D2ZuIOCf.cjs.map
7037
+ //# sourceMappingURL=attaform.DsQkXE3o.cjs.map