attaform 0.29.0 → 0.30.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 (59) 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/dev-key-collision-warnings.mjs +47 -8
  5. package/dist/dev/chunks/devtools.mjs +1 -1
  6. package/dist/dev/directive.mjs +1 -1
  7. package/dist/dev/history.mjs +1 -2
  8. package/dist/dev/index.mjs +5 -5
  9. package/dist/dev/runtime/plugins/attaform.mjs +3 -3
  10. package/dist/dev/shared/{attaform-dev.BO-71R54.mjs → attaform-dev.BK6Ge2qR.mjs} +34 -188
  11. package/dist/dev/shared/{attaform-dev.A-TpJW0B.mjs → attaform-dev.BQc5QV3Y.mjs} +1 -19
  12. package/dist/dev/shared/{attaform-dev.DrzObAZo.mjs → attaform-dev.BcNtyOmf.mjs} +4 -4
  13. package/dist/dev/shared/{attaform-dev.ButTkwHd.mjs → attaform-dev.BcYT6tFh.mjs} +7 -8
  14. package/dist/dev/shared/{attaform-dev.BgM6FdtA.mjs → attaform-dev.BisFstxh.mjs} +91 -59
  15. package/dist/dev/shared/{attaform-dev.DHuydLAC.mjs → attaform-dev.CQ2rJiAX.mjs} +560 -631
  16. package/dist/dev/shared/{attaform-dev.D8aoKb89.mjs → attaform-dev.D6CLvaQT.mjs} +8 -8
  17. package/dist/dev/shared/{attaform-dev.q6UutkCx.mjs → attaform-dev.DTrHonpc.mjs} +69 -120
  18. package/dist/dev/shared/{attaform-dev.DD5m2W51.mjs → attaform-dev.DUZckyV8.mjs} +1 -3
  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 +1 -2
  26. package/dist/index.d.mts +6 -6
  27. package/dist/index.mjs +5 -5
  28. package/dist/nuxt.d.mts +2 -11
  29. package/dist/nuxt.mjs +0 -1
  30. package/dist/runtime/plugins/attaform.mjs +3 -3
  31. package/dist/shared/{attaform.DffRL5pP.mjs → attaform.B3resMQ1.mjs} +8 -8
  32. package/dist/shared/{attaform.Cvao8bW5.mjs → attaform.BRDDQeHV.mjs} +6 -6
  33. package/dist/shared/{attaform.C2MVyuxC.mjs → attaform.BXneBxEj.mjs} +34 -188
  34. package/dist/shared/{attaform.BndjUUYX.mjs → attaform.ByWP6kSx.mjs} +4 -4
  35. package/dist/shared/{attaform.D1fnTifF.mjs → attaform.CJ8DpRGj.mjs} +69 -120
  36. package/dist/shared/{attaform.B0dKL8ST.mjs → attaform.CUfrMK7t.mjs} +91 -59
  37. package/dist/shared/{attaform.CZYt_5N_.mjs → attaform.CdZIEf7_.mjs} +1 -19
  38. package/dist/shared/{attaform.axHXVQO7.d.mts → attaform.Clz0ArIi.d.mts} +1 -1
  39. package/dist/shared/{attaform.CZMAYwSK.mjs → attaform.DNJOWjQw.mjs} +559 -588
  40. package/dist/shared/{attaform.CIWLMY-R.d.mts → attaform.Rc9u4Vfw.d.mts} +1 -1
  41. package/dist/shared/{attaform.DDtqHYv1.d.mts → attaform.UGyOK83T.d.mts} +115 -214
  42. package/dist/shared/{attaform.D0x-qSXm.mjs → attaform.WiGdIqgx.mjs} +1 -3
  43. package/dist/shared/{attaform.CsoeRi3P.d.mts → attaform.bKLzMU0o.d.mts} +99 -493
  44. package/dist/vite.mjs +5 -0
  45. package/dist/zod-v3.d.mts +4 -4
  46. package/dist/zod-v3.mjs +6 -6
  47. package/dist/zod-v4.d.mts +9 -9
  48. package/dist/zod-v4.mjs +6 -6
  49. package/dist/zod.d.mts +4 -4
  50. package/dist/zod.mjs +5 -5
  51. package/package.json +3 -2
  52. package/skills/attaform/SKILL.md +1 -1
  53. package/skills/attaform/references/custom-components.md +1 -1
  54. package/dist/chunks/fingerprint.mjs +0 -183
  55. package/dist/chunks/fingerprint2.mjs +0 -159
  56. package/dist/dev/chunks/fingerprint.mjs +0 -183
  57. package/dist/dev/chunks/fingerprint2.mjs +0 -159
  58. package/dist/dev/shared/attaform-dev.BxfsuwBR.mjs +0 -44
  59. package/dist/shared/attaform.BxfsuwBR.mjs +0 -44
@@ -1,9 +1,9 @@
1
- import { computed, readonly, toRaw, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, reactive, shallowRef, toValue, watch, triggerRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, onBeforeMount, onBeforeUpdate, onMounted, effectScope, nextTick } from 'vue';
2
- import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform.D0x-qSXm.mjs';
3
- import { c as armDomBinding } from './attaform.DffRL5pP.mjs';
1
+ import { computed, readonly, toRaw, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, reactive, shallowReactive, shallowRef, toValue, watch, triggerRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, onBeforeMount, onBeforeUpdate, onMounted, effectScope, nextTick } from 'vue';
2
+ import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform.WiGdIqgx.mjs';
3
+ import { c as armDomBinding } from './attaform.B3resMQ1.mjs';
4
4
  import { R as REGISTER_OWNER_MARKER, b as V_REGISTER_MARKER } from './attaform.KvlEedlF.mjs';
5
- import { A as ANONYMOUS_FORM_KEY_PREFIX, d as consumerHas, i as isShadowedKey, e as safeOwnHas, a as safeOwnRead, 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, t as ANONYMOUS_WIZARD_KEY_PREFIX } from './attaform.Cvao8bW5.mjs';
6
- import { i as isPathPrefix, e as canonicalizePath, j as cellEntriesFor, s as segmentsForPathKey, k as keyForSegments, m as mapSegmentKeys, b as ROOT_PATH_KEY, S as SubmitErrorHandlerError, t as toError, l as groupErrorsByKey, n as normalizeErrorInput, h as SET_MEMBER_SEGMENT, R as ROOT_PATH, o as normalizeErrorInputs, q as coerceToPathKey, a as InvalidUseFormConfigError, d as ReservedFormKeyError } from './attaform.CZYt_5N_.mjs';
5
+ import { A as ANONYMOUS_FORM_KEY_PREFIX, i as isShadowedKey, d as safeOwnHas, a as safeOwnRead, e as consumerHas, f as spreadConsumerRecord, g as copyConsumerArray, r as readConsumerIndex, b as safeAssign, h as consumerKeys, j as readConsumerProp, k as diffAndApply, p as pickDefined, s as structuralSnapshot, n as normalizeNumericOption, l as DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS, m as consumerSymbolKeys, o as applyChangedKeys, R as RESERVED_KEY_PREFIX, q as DEFAULT_MAX_RECURSION_DEPTH, t as ANONYMOUS_WIZARD_KEY_PREFIX } from './attaform.BRDDQeHV.mjs';
6
+ import { i as isPathPrefix, e as canonicalizePath, k as keyForSegments, m as mapSegmentKeys, b as ROOT_PATH_KEY, s as segmentsForPathKey, S as SubmitErrorHandlerError, t as toError, j as groupErrorsByKey, n as normalizeErrorInput, h as SET_MEMBER_SEGMENT, R as ROOT_PATH, l as normalizeErrorInputs, a as InvalidUseFormConfigError, d as ReservedFormKeyError } from './attaform.CdZIEf7_.mjs';
7
7
 
8
8
  const AttaformErrorCode = {
9
9
  /** A required field is in the blank set — user hasn't supplied a value. */
@@ -78,11 +78,6 @@ function makeBlankRequiredError(segments) {
78
78
  }
79
79
  const NO_ERRORS = Object.freeze([]);
80
80
 
81
- function crossCopyState(key, create) {
82
- const carrier = globalThis;
83
- return carrier[key] ?? (carrier[key] = create());
84
- }
85
-
86
81
  function isGateOpen(field, formMeta) {
87
82
  return formMeta.submissionAttempts > 0 || field.blurredAfterInteraction === true;
88
83
  }
@@ -104,45 +99,32 @@ function earliestNonNull(a, b) {
104
99
  return a < b ? a : b;
105
100
  }
106
101
  const DEFAULT_TIMINGS = { showDelay: 120, minVisible: 120 };
102
+ const { showDelay, minVisible } = DEFAULT_TIMINGS;
107
103
  const FOCUS_OUT_GRACE = 16;
108
- const defaultFamily = crossCopyState(
109
- /* @__PURE__ */ Symbol.for("attaform:default-display-state-family"),
110
- () => /* @__PURE__ */ new WeakSet()
111
- );
112
- function isDefaultDisplayState(fn) {
113
- return defaultFamily.has(fn);
114
- }
115
- function makeDefaultDisplayState({
116
- showDelay,
117
- minVisible
118
- }) {
119
- const reducer = (prev, { field, formMeta, validatingSince, transformingSince, now }) => {
120
- const verdict = computeVerdict(field, formMeta);
121
- if (!isGateOpen(field, formMeta)) return { display: verdict };
122
- const inFlightSince = earliestNonNull(validatingSince, transformingSince);
123
- if (inFlightSince === null) {
124
- if (prev.display === "pending") {
125
- const shownAt = prev.pendingShownAt ?? now;
126
- if (now < shownAt + minVisible)
127
- return { display: "pending", pendingShownAt: shownAt, reviewAt: shownAt + minVisible };
128
- }
129
- return { display: verdict };
130
- }
131
- if (prev.display === "pending")
132
- return { display: "pending", pendingShownAt: prev.pendingShownAt ?? now };
133
- const window = field.focused === false ? Math.min(showDelay, FOCUS_OUT_GRACE) : showDelay;
134
- if (now - inFlightSince < window) {
135
- return { display: prev.display, reviewAt: inFlightSince + window };
104
+ const defaultDisplayState = (prev, { field, formMeta, validatingSince, transformingSince, now }) => {
105
+ const verdict = computeVerdict(field, formMeta);
106
+ if (!isGateOpen(field, formMeta)) return { display: verdict };
107
+ const inFlightSince = earliestNonNull(validatingSince, transformingSince);
108
+ if (inFlightSince === null) {
109
+ if (prev.display === "pending") {
110
+ const shownAt = prev.pendingShownAt ?? now;
111
+ if (now < shownAt + minVisible)
112
+ return {
113
+ display: "pending",
114
+ pendingShownAt: shownAt,
115
+ reviewAt: shownAt + minVisible
116
+ };
136
117
  }
137
- return { display: "pending", pendingShownAt: now, reviewAt: now + minVisible };
138
- };
139
- defaultFamily.add(reducer);
140
- return reducer;
141
- }
142
- const defaultDisplayState = makeDefaultDisplayState(DEFAULT_TIMINGS);
143
- function resolveGetDisplayState(config) {
144
- return config ?? defaultDisplayState;
145
- }
118
+ return { display: verdict };
119
+ }
120
+ if (prev.display === "pending")
121
+ return { display: "pending", pendingShownAt: prev.pendingShownAt ?? now };
122
+ const window = field.focused === false ? Math.min(showDelay, FOCUS_OUT_GRACE) : showDelay;
123
+ if (now - inFlightSince < window) {
124
+ return { display: prev.display, reviewAt: inFlightSince + window };
125
+ }
126
+ return { display: "pending", pendingShownAt: now, reviewAt: now + minVisible };
127
+ };
146
128
 
147
129
  function hashStableString(input, seed = 0) {
148
130
  let h1 = 3735928559 ^ seed;
@@ -230,16 +212,27 @@ function descendStep(value, segment) {
230
212
  }
231
213
  function getAtPath(root, path) {
232
214
  if (path.length === 0) return root;
233
- let current = root;
234
- for (const segment of path) {
235
- const next = descendStep(current, segment);
236
- if (next === NOT_FOUND) return void 0;
237
- current = next;
215
+ try {
216
+ let current = root;
217
+ for (const segment of path) {
218
+ const next = descendStep(current, segment);
219
+ if (next === NOT_FOUND) return void 0;
220
+ current = next;
221
+ }
222
+ return current;
223
+ } catch {
224
+ return void 0;
238
225
  }
239
- return current;
240
226
  }
241
227
  function hasAtPath(root, path) {
242
228
  if (path.length === 0) return true;
229
+ try {
230
+ return hasAtPathUnguarded(root, path);
231
+ } catch {
232
+ return false;
233
+ }
234
+ }
235
+ function hasAtPathUnguarded(root, path) {
243
236
  let current = root;
244
237
  for (let i = 0; i < path.length - 1; i++) {
245
238
  const segment = path[i];
@@ -266,29 +259,15 @@ function isPlainRecord(value) {
266
259
  const proto = Object.getPrototypeOf(value);
267
260
  return proto === null || proto === Object.prototype;
268
261
  }
262
+ const NO_SCHEMA_DEFAULTS = /* @__PURE__ */ new Set();
263
+ const NO_SCHEMA_FILL = {
264
+ getDefaultAtPath: () => void 0,
265
+ arrayShapeAtPath: () => null,
266
+ getSlimPrimitiveTypesAtPath: () => NO_SCHEMA_DEFAULTS,
267
+ entryKeyKindAtPath: () => void 0
268
+ };
269
269
  function setAtPath(root, path, value) {
270
- return setAtPathOffset(root, path, value, 0);
271
- }
272
- function setAtPathOffset(root, path, value, offset) {
273
- if (offset >= path.length) return value;
274
- const head = path[offset];
275
- const nextOffset = offset + 1;
276
- if (root instanceof Map) {
277
- const next = new Map(root);
278
- const key = mapKeyForSegment(root, head);
279
- next.set(key, setAtPathOffset(root.get(key), path, value, nextOffset));
280
- return next;
281
- }
282
- if (!isRebuildableContainer(root, head)) return root;
283
- if (typeof head === "number") {
284
- const arr = Array.isArray(root) ? [...root] : [];
285
- while (arr.length <= head) arr.push(void 0);
286
- arr[head] = setAtPathOffset(arr[head], path, value, nextOffset);
287
- return arr;
288
- }
289
- const rec = isPlainRecord(root) ? { ...root } : {};
290
- safeAssign(rec, head, setAtPathOffset(safeOwnRead(rec, head), path, value, nextOffset));
291
- return rec;
270
+ return setAtPathWithSchemaFill(root, NO_SCHEMA_FILL, path, value);
292
271
  }
293
272
  const NO_IN_PLACE = { applied: false };
294
273
  function tryInPlaceLeafWrite(root, path, value) {
@@ -494,10 +473,10 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
494
473
  }
495
474
  const rec = isPlainRecord(root) ? { ...root } : {};
496
475
  if (isLeafStep) {
497
- rec[head] = value;
476
+ safeAssign(rec, head, value);
498
477
  return rec;
499
478
  }
500
- const existing = rec[head];
479
+ const existing = safeOwnRead(rec, head);
501
480
  let childRoot;
502
481
  if (existing === void 0 || existing !== null && typeof existing !== "object") {
503
482
  const intermPath = [...fullPath.slice(0, startIdx + 1)];
@@ -506,7 +485,11 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
506
485
  } else {
507
486
  childRoot = existing;
508
487
  }
509
- rec[head] = setAtPathWithSchemaFillImpl(childRoot, schema, fullPath, value, startIdx + 1);
488
+ safeAssign(
489
+ rec,
490
+ head,
491
+ setAtPathWithSchemaFillImpl(childRoot, schema, fullPath, value, startIdx + 1)
492
+ );
510
493
  return rec;
511
494
  }
512
495
 
@@ -523,16 +506,15 @@ function isUnderStubAncestor(state, segments) {
523
506
  }
524
507
  return false;
525
508
  }
526
- function buildFieldStateAccessor(state, formInstanceId, getFormMetaBase, sweep, options) {
509
+ function buildFieldStateAccessor(state, formInstanceId, getFormMetaBase, sweep) {
527
510
  const cache = /* @__PURE__ */ new Map();
528
- const predicate = options?.getDisplayState;
529
511
  sweep.onEvict((key) => cache.delete(key));
530
512
  return function getFieldState(pathInput) {
531
513
  const { segments, key } = canonicalizePath(pathInput);
532
514
  const cached = cache.get(key);
533
515
  if (cached !== void 0) return cached;
534
516
  const c = computed(
535
- () => state.schema.isLeafAtPath(segments) ? buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase, predicate) : buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase, predicate)
517
+ () => state.schema.isLeafAtPath(segments) ? buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase) : buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase)
536
518
  );
537
519
  cache.set(key, c);
538
520
  sweep.track(segments, key);
@@ -549,7 +531,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
549
531
  const record = state.fields.get(key);
550
532
  const value = state.getValueAtPath(segments);
551
533
  const original = state.originals.get(key)?.value;
552
- const pristine = state.isPristineAtPath(segments);
534
+ const pristine = state.isPristineAtPathByKey(key, segments);
553
535
  const cell = state.errorCells.get(key);
554
536
  const schemaForKey = cell !== void 0 && cell.schema.length > 0 ? cell.schema : void 0;
555
537
  const blankForKey = state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments) ? [makeBlankRequiredError(segments)] : void 0;
@@ -561,7 +543,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
561
543
  const validating = (state.fieldValidationCounts.get(key) ?? 0) > 0;
562
544
  const transforming = (state.fieldTransformCounts.get(key) ?? 0) > 0;
563
545
  const transformError = state.transformErrors.get(key) ?? null;
564
- const gated = state.pathHasAsyncValidation(segments) && !state.firstValidationDone.value;
546
+ const gated = state.pathHasAsyncValidationByKey(key, segments) && !state.firstValidationDone.value;
565
547
  const isOrphan = segments.length > 0 && !hasAtPath(state.form.value, segments) && isUnderStubAncestor(state, segments);
566
548
  const valid = !gated && errors.length === 0 && !validating && !isOrphan;
567
549
  const elementRecord = state.domBinding.value?.elements.get(key);
@@ -604,7 +586,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
604
586
  meta: resolved.meta
605
587
  };
606
588
  }
607
- function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase, getDisplayState) {
589
+ function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase) {
608
590
  const base = buildLeafFieldStateBase(state, segments, key, formInstanceId);
609
591
  const validatingSince = state.fieldValidatingSince.get(key) ?? null;
610
592
  const transformingSince = state.fieldTransformingSince.get(key) ?? null;
@@ -617,9 +599,8 @@ function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBa
617
599
  transformingSince,
618
600
  false,
619
601
  // revealedDescendantError: leaves have no descendants
620
- false,
602
+ false
621
603
  // isRoot: a leaf is never the form root
622
- getDisplayState
623
604
  );
624
605
  }
625
606
  function visitActiveLeafPaths(value, base, visit) {
@@ -717,7 +698,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
717
698
  pristine = false;
718
699
  dirty = true;
719
700
  }
720
- const errors = aggregateErrorsAt(state, segments);
701
+ const errors = aggregateErrorsAt(state, segments, key);
721
702
  const revealedDescendantError = errors.length > 0 && errors.some((e) => {
722
703
  const ePath = e.path;
723
704
  if (ePath.length === segments.length && ePath.every((s, i) => s === segments[i])) return false;
@@ -725,7 +706,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
725
706
  if (ePath.length === 1 && ePath[0] === "") return blurredAfterInteraction;
726
707
  return blurredLeafSegments.some((s) => isPathPrefix(ePath, s));
727
708
  });
728
- if (!asyncPending && state.pathHasAsyncValidation(segments)) asyncPending = true;
709
+ if (!asyncPending && state.pathHasAsyncValidationByKey(key, segments)) asyncPending = true;
729
710
  if ((state.fieldValidationCounts.get(key) ?? 0) > 0) {
730
711
  validating = true;
731
712
  const since = state.fieldValidatingSince.get(key);
@@ -796,7 +777,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
796
777
  revealedDescendantError
797
778
  };
798
779
  }
799
- function buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase, getDisplayState) {
780
+ function buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase) {
800
781
  const { base, validatingSince, transformingSince, revealedDescendantError } = buildContainerFieldStateBase(state, segments, key, formInstanceId);
801
782
  return decorateWithDerivedProps(
802
783
  base,
@@ -806,14 +787,12 @@ function buildContainerFieldState(state, segments, key, formInstanceId, getFormM
806
787
  validatingSince,
807
788
  transformingSince,
808
789
  revealedDescendantError,
809
- segments.length === 0,
810
- getDisplayState
790
+ segments.length === 0
811
791
  );
812
792
  }
813
- function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, transformingSince, revealedDescendantError, isRoot, getDisplayState) {
793
+ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, transformingSince, revealedDescendantError, isRoot) {
814
794
  const firstError = base.errors[0];
815
795
  const firstOwnError = base.ownErrors[0];
816
- const predicate = getDisplayState ?? state.getDisplayState;
817
796
  const formMeta = getFormMetaBase();
818
797
  const ctx = {
819
798
  field: base,
@@ -824,16 +803,9 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
824
803
  // flight) so the reducer returns the plain verdict and hydration matches.
825
804
  now: state.ssr ? 0 : Date.now()
826
805
  };
827
- let machine;
828
- let rollupApplies = isDefaultDisplayState(predicate);
829
- try {
830
- machine = state.displayEngine.resolve(key, ctx, predicate);
831
- } catch (err) {
832
- machine = state.displayEngine.resolve(key, ctx, defaultDisplayState);
833
- rollupApplies = true;
834
- }
835
- const submitValidating = rollupApplies && isRoot && state.submitting.value && state.activeValidations.value > 0;
836
- const resolvedDisplayState = machine.display === "pending" || submitValidating ? "pending" : rollupApplies && revealedDescendantError ? "error" : machine.display;
806
+ const machine = state.displayEngine.resolve(key, ctx, defaultDisplayState);
807
+ const submitValidating = isRoot && state.submitting.value && state.activeValidations.value > 0;
808
+ const resolvedDisplayState = machine.display === "pending" || submitValidating ? "pending" : revealedDescendantError ? "error" : machine.display;
837
809
  const displayState = base.disabled === true ? "idle" : resolvedDisplayState;
838
810
  return {
839
811
  ...base,
@@ -846,26 +818,33 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
846
818
  firstOwnError
847
819
  };
848
820
  }
849
- function aggregateErrorsAt(state, prefix) {
821
+ function aggregateErrorsAt(state, prefix, prefixKey) {
822
+ const candidates = state.errorWindowAt(prefix, prefixKey);
823
+ if (candidates.length === 0) return [];
850
824
  const formValue = state.form.value;
825
+ const cells = state.errorCells;
851
826
  const buckets = /* @__PURE__ */ new Map();
852
- const collect = (errs) => {
853
- for (const [pathKey, list] of errs) {
854
- if (list.length === 0) continue;
855
- const segs = segmentsForPathKey(pathKey);
856
- if (segs === null) continue;
857
- if (!isPathPrefix(prefix, segs)) continue;
858
- if (segs.length > 0 && !hasAtPath(formValue, segs)) continue;
859
- const ordinal = state.ensurePathOrdinal(pathKey);
860
- const existing = buckets.get(ordinal);
861
- if (existing === void 0) buckets.set(ordinal, [...list]);
862
- else existing.push(...list);
863
- }
864
- };
865
- collect(cellEntriesFor(state.errorCells, "schema"));
866
- collect(state.derivedBlankErrors.value);
867
- collect(cellEntriesFor(state.errorCells, "user"));
827
+ for (const { key, segments } of candidates) {
828
+ if (!isPathPrefix(prefix, segments)) continue;
829
+ if (segments.length > 0 && !hasAtPath(formValue, segments)) continue;
830
+ const cell = cells.get(key);
831
+ const blankList = state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments) ? [makeBlankRequiredError(segments)] : void 0;
832
+ const schemaList = cell?.schema;
833
+ const userList = cell?.user;
834
+ const total = (schemaList?.length ?? 0) + (blankList?.length ?? 0) + (userList?.length ?? 0);
835
+ if (total === 0) continue;
836
+ const ordinal = state.ensurePathOrdinal(key);
837
+ let bucket = buckets.get(ordinal);
838
+ if (bucket === void 0) {
839
+ bucket = [];
840
+ buckets.set(ordinal, bucket);
841
+ }
842
+ if (schemaList !== void 0) bucket.push(...schemaList);
843
+ if (blankList !== void 0) bucket.push(...blankList);
844
+ if (userList !== void 0) bucket.push(...userList);
845
+ }
868
846
  if (buckets.size === 0) return [];
847
+ if (buckets.size === 1) return [...buckets.values()][0];
869
848
  return [...buckets.entries()].sort(([a], [b]) => a - b).flatMap(([, errs]) => errs);
870
849
  }
871
850
  const EMPTY_ELEMENTS = Object.freeze([]);
@@ -957,7 +936,7 @@ function buildTree(spec) {
957
936
  existsCache.delete(key);
958
937
  });
959
938
  function schemaHasPath(segs) {
960
- const cacheKey = JSON.stringify(segs);
939
+ const cacheKey = keyForSegments(segs).key;
961
940
  const cached = existsCache.get(cacheKey);
962
941
  if (cached !== void 0) return cached;
963
942
  const result = spec.schema.getSlimPrimitiveTypesAtPath(segs).size > 0;
@@ -972,7 +951,7 @@ function buildTree(spec) {
972
951
  }
973
952
  function containerAt(segments) {
974
953
  const isArrayLike = spec.isArrayAt(segments);
975
- const pathKey = JSON.stringify(segments);
954
+ const pathKey = keyForSegments(segments).key;
976
955
  const cacheKey = `${pathKey}+${isArrayLike ? "A" : "O"}`;
977
956
  const existing = containerCache.get(cacheKey);
978
957
  if (existing !== void 0) return existing;
@@ -1072,7 +1051,7 @@ function buildErrorsSurface(state, sweep) {
1072
1051
  const treeCache = /* @__PURE__ */ new Map();
1073
1052
  sweep.onEvict((key) => treeCache.delete(key));
1074
1053
  const materialize = (segments) => {
1075
- const cacheKey = JSON.stringify(segments);
1054
+ const cacheKey = keyForSegments(segments).key;
1076
1055
  let tree = treeCache.get(cacheKey);
1077
1056
  if (tree === void 0) {
1078
1057
  const frozen = [...segments];
@@ -1084,28 +1063,21 @@ function buildErrorsSurface(state, sweep) {
1084
1063
  };
1085
1064
  const resolveLeaf = (path) => {
1086
1065
  const isContainerSelfAccess = path.length > 1 && path[path.length - 1] === "";
1087
- const collectAtKey = (key2, active2, into) => {
1088
- const cell = state.errorCells.get(key2);
1089
- if (active2) {
1090
- const b = state.derivedBlankErrors.value.get(key2);
1091
- if (cell !== void 0) into.push(...cell.schema);
1092
- if (b !== void 0) into.push(...b);
1093
- }
1094
- if (cell !== void 0) into.push(...cell.user);
1095
- };
1096
1066
  const merged = [];
1097
1067
  if (isContainerSelfAccess) {
1098
1068
  const containerPath = path.slice(0, -1);
1099
- const containerKey = canonicalizePath(containerPath).key;
1100
- const literalKey = canonicalizePath(path).key;
1069
+ const container = canonicalizePath(containerPath);
1070
+ const literal = canonicalizePath(path);
1101
1071
  const active2 = hasAtPath(state.form.value, containerPath);
1102
- collectAtKey(containerKey, active2, merged);
1103
- if (literalKey !== containerKey) collectAtKey(literalKey, active2, merged);
1072
+ collectErrorsAt(state, container.key, container.segments, active2, merged);
1073
+ if (literal.key !== container.key) {
1074
+ collectErrorsAt(state, literal.key, literal.segments, active2, merged);
1075
+ }
1104
1076
  return merged;
1105
1077
  }
1106
- const { key } = canonicalizePath(path);
1078
+ const { key, segments } = canonicalizePath(path);
1107
1079
  const active = hasAtPath(state.form.value, path);
1108
- collectAtKey(key, active, merged);
1080
+ collectErrorsAt(state, key, segments, active, merged);
1109
1081
  return merged;
1110
1082
  };
1111
1083
  return buildTree({
@@ -1123,65 +1095,80 @@ function buildErrorsSurface(state, sweep) {
1123
1095
  // `errors()` / `errors([])` / `errors(path)` are all the subtree
1124
1096
  // aggregate — the same helper `meta.errors` reads, so the surfaces
1125
1097
  // never drift.
1126
- call: (path) => aggregateErrorsAt(state, path),
1098
+ call: (path) => aggregateErrorsAt(state, path, keyForSegments(path).key),
1127
1099
  surface: "form.errors",
1128
1100
  sweep
1129
1101
  });
1130
1102
  }
1103
+ function collectErrorsAt(state, key, segments, active, into) {
1104
+ const cell = state.errorCells.get(key);
1105
+ if (active) {
1106
+ if (cell !== void 0) into.push(...cell.schema);
1107
+ if (state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments)) {
1108
+ into.push(makeBlankRequiredError(segments));
1109
+ }
1110
+ }
1111
+ if (cell !== void 0) into.push(...cell.user);
1112
+ }
1131
1113
  function errorAwareContainerKeys(state, segments) {
1132
1114
  const keys = new Set(liveKeysAtPath(state, segments));
1133
1115
  const formValue = state.form.value;
1134
- const walk = (store, applyActivePathFilter) => {
1135
- for (const [pathKey, errors] of store) {
1136
- if (errors.length === 0) continue;
1137
- const decoded = segmentsForPathKey(pathKey);
1138
- if (decoded === null) continue;
1139
- if (decoded.length <= segments.length) continue;
1140
- if (!isPathPrefix(segments, decoded)) continue;
1141
- if (applyActivePathFilter && !hasAtPath(formValue, decoded)) continue;
1142
- const nextSeg = decoded[segments.length];
1143
- keys.add(typeof nextSeg === "number" ? String(nextSeg) : nextSeg);
1144
- }
1145
- };
1146
- walk(cellEntriesFor(state.errorCells, "schema"), true);
1147
- walk(state.derivedBlankErrors.value, true);
1148
- walk(cellEntriesFor(state.errorCells, "user"), false);
1116
+ const errors = [];
1117
+ const found = [];
1118
+ for (const { key, segments: decoded } of state.errorWindowAt(
1119
+ segments,
1120
+ keyForSegments(segments).key
1121
+ )) {
1122
+ if (decoded.length <= segments.length) continue;
1123
+ if (!isPathPrefix(segments, decoded)) continue;
1124
+ errors.length = 0;
1125
+ collectErrorsAt(state, key, decoded, hasAtPath(formValue, decoded), errors);
1126
+ if (errors.length === 0) continue;
1127
+ const nextSeg = decoded[segments.length];
1128
+ found.push({
1129
+ childKey: typeof nextSeg === "number" ? String(nextSeg) : nextSeg,
1130
+ ordinal: state.ensurePathOrdinal(key)
1131
+ });
1132
+ }
1133
+ found.sort((a, b) => a.ordinal - b.ordinal);
1134
+ for (const { childKey } of found) keys.add(childKey);
1149
1135
  return [...keys];
1150
1136
  }
1151
1137
  function materializeErrors(state, containerSegments) {
1152
- const liveContainer = getAtPath(state.form.value, containerSegments);
1138
+ const formValue = state.form.value;
1139
+ const liveContainer = getAtPath(formValue, containerSegments);
1153
1140
  const tree = Array.isArray(liveContainer) ? [] : {};
1154
- const collect = (store, applyActivePathFilter) => {
1155
- entries: for (const [pathKey, errors] of store) {
1156
- if (errors.length === 0) continue;
1157
- const fullPath = segmentsForPathKey(pathKey);
1158
- if (fullPath === null) continue;
1159
- if (fullPath.length === 0) {
1160
- if (containerSegments.length === 0) placeAt(tree, [ROOT_PATH_KEY], errors);
1161
- continue;
1162
- }
1163
- if (fullPath.length < containerSegments.length) continue;
1164
- for (let i = 0; i < containerSegments.length; i++) {
1165
- if (fullPath[i] !== containerSegments[i]) continue entries;
1166
- }
1167
- if (applyActivePathFilter && !hasAtPath(state.form.value, fullPath)) continue;
1168
- const relativePath = fullPath.slice(containerSegments.length);
1169
- let placePath;
1170
- if (relativePath.length === 0) {
1171
- placePath = [""];
1172
- } else if (state.schema.isLeafAtPath(fullPath)) {
1173
- placePath = relativePath;
1174
- } else if (state.schema.getSlimPrimitiveTypesAtPath(fullPath).size > 0) {
1175
- placePath = [...relativePath, ""];
1176
- } else {
1177
- placePath = relativePath;
1178
- }
1179
- placeAt(tree, placePath, errors);
1141
+ const placements = [];
1142
+ for (const { key, segments: fullPath } of state.errorWindowAt(
1143
+ containerSegments,
1144
+ keyForSegments(containerSegments).key
1145
+ )) {
1146
+ const isRoot = fullPath.length === 0;
1147
+ if (isRoot) {
1148
+ if (containerSegments.length !== 0) continue;
1149
+ } else if (!isPathPrefix(containerSegments, fullPath)) {
1150
+ continue;
1180
1151
  }
1181
- };
1182
- collect(cellEntriesFor(state.errorCells, "schema"), true);
1183
- collect(state.derivedBlankErrors.value, true);
1184
- collect(cellEntriesFor(state.errorCells, "user"), false);
1152
+ const errors = [];
1153
+ collectErrorsAt(state, key, fullPath, isRoot || hasAtPath(formValue, fullPath), errors);
1154
+ if (errors.length === 0) continue;
1155
+ const relativePath = fullPath.slice(containerSegments.length);
1156
+ let placePath;
1157
+ if (isRoot) {
1158
+ placePath = [ROOT_PATH_KEY];
1159
+ } else if (relativePath.length === 0) {
1160
+ placePath = [""];
1161
+ } else if (state.schema.isLeafAtPath(fullPath)) {
1162
+ placePath = relativePath;
1163
+ } else if (state.schema.getSlimPrimitiveTypesAtPath(fullPath).size > 0) {
1164
+ placePath = [...relativePath, ""];
1165
+ } else {
1166
+ placePath = relativePath;
1167
+ }
1168
+ placements.push({ placePath, errors, ordinal: state.ensurePathOrdinal(key) });
1169
+ }
1170
+ placements.sort((a, b) => a.ordinal - b.ordinal);
1171
+ for (const { placePath, errors } of placements) placeAt(tree, placePath, errors);
1185
1172
  return tree;
1186
1173
  }
1187
1174
  function placeAt(tree, path, errors) {
@@ -1254,7 +1241,7 @@ function buildFieldsSurface(state, getFieldStateAt, sweep) {
1254
1241
  const viewCache = /* @__PURE__ */ new Map();
1255
1242
  sweep.onEvict((key) => viewCache.delete(key));
1256
1243
  function viewAt(segments) {
1257
- const cacheKey = JSON.stringify(segments);
1244
+ const cacheKey = keyForSegments(segments).key;
1258
1245
  const existing = viewCache.get(cacheKey);
1259
1246
  if (existing !== void 0) return existing;
1260
1247
  const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(
@@ -1816,45 +1803,6 @@ function buildFieldArrayApi(state) {
1816
1803
  };
1817
1804
  }
1818
1805
 
1819
- const SWEEP_SLICE = 8;
1820
- function createDynamicPathSweep(state) {
1821
- const dynamicKeys = /* @__PURE__ */ new Set();
1822
- const evictors = [];
1823
- const isDynamicPath = (segments) => {
1824
- for (let i = 0; i < segments.length; i++) {
1825
- if (typeof segments[i] === "number") return true;
1826
- if (!state.schema.isFixedObjectAtPath(segments.slice(0, i))) return true;
1827
- }
1828
- return false;
1829
- };
1830
- let sweepCursor = null;
1831
- state.onFormChange((next) => {
1832
- if (dynamicKeys.size === 0) return;
1833
- const raw = toRaw(next);
1834
- for (let i = 0; i < SWEEP_SLICE; i++) {
1835
- sweepCursor ?? (sweepCursor = dynamicKeys.values());
1836
- const step = sweepCursor.next();
1837
- if (step.done === true) {
1838
- sweepCursor = null;
1839
- break;
1840
- }
1841
- const segments = segmentsForPathKey(step.value);
1842
- if (segments !== null && hasAtPath(raw, segments)) continue;
1843
- dynamicKeys.delete(step.value);
1844
- for (const evict of evictors) evict(step.value);
1845
- }
1846
- });
1847
- return {
1848
- track(segments, key) {
1849
- if (dynamicKeys.has(key)) return;
1850
- if (isDynamicPath(segments)) dynamicKeys.add(key);
1851
- },
1852
- onEvict(evict) {
1853
- evictors.push(evict);
1854
- }
1855
- };
1856
- }
1857
-
1858
1806
  function isErrorInputLike(value) {
1859
1807
  if (value instanceof Error) return true;
1860
1808
  if (typeof value !== "object" || value === null) return false;
@@ -1881,8 +1829,8 @@ function deriveSubmitErrors(err) {
1881
1829
  messageless: true
1882
1830
  };
1883
1831
  }
1884
- function buildProcessForm(state, formInstanceId, options = {}) {
1885
- const invalidPolicy = options.onInvalidSubmit ?? "focus-first-error";
1832
+ function buildProcessForm(state, options = {}) {
1833
+ const applyInvalidSubmit = options.applyInvalidSubmit;
1886
1834
  function validate(pathInput) {
1887
1835
  const result = ref({
1888
1836
  pending: true,
@@ -1975,7 +1923,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
1975
1923
  };
1976
1924
  }
1977
1925
  async function runRefinementValidation(data, path) {
1978
- return await state.schema.validateAtPath(data, path);
1926
+ return stampFormKey(await state.schema.validateAtPath(data, path), state.formKey);
1979
1927
  }
1980
1928
  function composeWithDerivedBlank(refinement, scope) {
1981
1929
  const blankErrors = collectScopedBlankErrors(state, scope);
@@ -2021,7 +1969,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
2021
1969
  }
2022
1970
  }
2023
1971
  if (generationStillValid) {
2024
- applyInvalidSubmitPolicy(state, formInstanceId, invalidPolicy);
1972
+ applyInvalidSubmit?.();
2025
1973
  }
2026
1974
  if (onError !== void 0) {
2027
1975
  try {
@@ -2038,7 +1986,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
2038
1986
  await onSubmit(merged.data);
2039
1987
  if (hasUserErrorEntries(state)) {
2040
1988
  if (state.submissionGeneration.value === genAtEntry) {
2041
- applyInvalidSubmitPolicy(state, formInstanceId, invalidPolicy);
1989
+ applyInvalidSubmit?.();
2042
1990
  }
2043
1991
  return;
2044
1992
  }
@@ -2056,7 +2004,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
2056
2004
  if (segments === null) continue;
2057
2005
  state.setUserErrorsForPath([...segments], bucket);
2058
2006
  }
2059
- applyInvalidSubmitPolicy(state, formInstanceId, invalidPolicy);
2007
+ applyInvalidSubmit?.();
2060
2008
  }
2061
2009
  }
2062
2010
  } finally {
@@ -2071,6 +2019,10 @@ function buildProcessForm(state, formInstanceId, options = {}) {
2071
2019
  };
2072
2020
  return { validate, parse, handleSubmit };
2073
2021
  }
2022
+ function stampFormKey(verdict, formKey) {
2023
+ if (verdict.success) return { ...verdict, formKey };
2024
+ return verdict.data === void 0 ? { data: void 0, errors: verdict.errors, success: false, formKey } : { data: verdict.data, errors: verdict.errors, success: false, formKey };
2025
+ }
2074
2026
  function toSegments(pathInput) {
2075
2027
  return canonicalizePath(pathInput).segments;
2076
2028
  }
@@ -2104,21 +2056,6 @@ function collectScopedBlankErrors(state, scope) {
2104
2056
  }
2105
2057
  return errors;
2106
2058
  }
2107
- function applyInvalidSubmitPolicy(state, formInstanceId, policy) {
2108
- if (policy === "none") return;
2109
- const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
2110
- if (target === null) return;
2111
- if (policy === "scroll-to-first-error") {
2112
- target.element.scrollIntoView();
2113
- return;
2114
- }
2115
- if (policy === "focus-first-error") {
2116
- target.element.focus({ focusVisible: true });
2117
- return;
2118
- }
2119
- target.element.scrollIntoView();
2120
- target.element.focus({ preventScroll: true, focusVisible: true });
2121
- }
2122
2059
 
2123
2060
  function slimKindOf(value) {
2124
2061
  if (value === null) return "null";
@@ -2182,51 +2119,9 @@ function walk(schema, store, path, value) {
2182
2119
  return true;
2183
2120
  }
2184
2121
 
2185
- function defineCoercion(entry) {
2186
- return entry;
2187
- }
2188
2122
  const IDENTITY = (v) => v;
2189
- const EMPTY_INDEX = /* @__PURE__ */ new Map();
2190
- const defaultCoercionRules = [
2191
- defineCoercion({
2192
- input: "string",
2193
- output: "number",
2194
- transform: (s) => {
2195
- const trimmed = s.trim();
2196
- if (trimmed === "") return { coerced: false };
2197
- const n = Number(trimmed);
2198
- if (!Number.isFinite(n)) return { coerced: false };
2199
- return { coerced: true, value: n };
2200
- }
2201
- }),
2202
- defineCoercion({
2203
- input: "string",
2204
- output: "boolean",
2205
- transform: (s) => {
2206
- const normalized = s.trim().toLowerCase();
2207
- if (normalized === "true") return { coerced: true, value: true };
2208
- if (normalized === "false") return { coerced: true, value: false };
2209
- return { coerced: false };
2210
- }
2211
- })
2212
- ];
2213
- function resolveCoercionIndex(config) {
2214
- if (config === false) return EMPTY_INDEX;
2215
- const rules = config === void 0 || config === true ? defaultCoercionRules : config;
2216
- return indexRules(rules);
2217
- }
2218
- function indexRules(rules) {
2219
- const idx = /* @__PURE__ */ new Map();
2220
- for (const entry of rules) {
2221
- const candidate = entry;
2222
- if (candidate === null || typeof candidate !== "object" || typeof candidate.transform !== "function") {
2223
- continue;
2224
- }
2225
- const key = `${entry.input}->${entry.output}`;
2226
- if (idx.has(key) && false) ;
2227
- idx.set(key, entry);
2228
- }
2229
- return idx;
2123
+ function resolveCoerceEnabled(config) {
2124
+ return config !== false;
2230
2125
  }
2231
2126
  function memberSlimTypes(schema, segments, accepted) {
2232
2127
  if (accepted.has("array")) return schema.getSlimPrimitiveTypesAtPath([...segments, 0]);
@@ -2235,89 +2130,83 @@ function memberSlimTypes(schema, segments, accepted) {
2235
2130
  }
2236
2131
  return void 0;
2237
2132
  }
2238
- function buildCoerceFn(schema, segments, index) {
2239
- if (index === EMPTY_INDEX) return IDENTITY;
2240
- if (index.size === 0) return IDENTITY;
2133
+ function buildCoerceFn(schema, segments, enabled) {
2134
+ if (!enabled) return IDENTITY;
2241
2135
  const accepted = schema.getSlimPrimitiveTypesAtPath(segments);
2242
2136
  const elementAccepted = memberSlimTypes(schema, segments, accepted);
2243
- return (value) => coerceValue(value, accepted, elementAccepted, index);
2137
+ return (value) => coerceValue(value, accepted, elementAccepted);
2244
2138
  }
2245
- function buildElementCoerceFn(schema, segments, index) {
2246
- if (index === EMPTY_INDEX) return void 0;
2247
- if (index.size === 0) return void 0;
2139
+ function buildElementCoerceFn(schema, segments, enabled) {
2140
+ if (!enabled) return void 0;
2248
2141
  const accepted = schema.getSlimPrimitiveTypesAtPath(segments);
2249
2142
  const elementAccepted = memberSlimTypes(schema, segments, accepted);
2250
2143
  if (elementAccepted === void 0) return void 0;
2251
- return (value) => coerceScalar(value, elementAccepted, index);
2144
+ return (value) => coerceScalar(value, elementAccepted);
2252
2145
  }
2253
2146
  function pickScalarTarget(accepted) {
2254
2147
  if (accepted.has("string")) return null;
2255
2148
  if (accepted.has("number")) return "number";
2256
2149
  if (accepted.has("boolean")) return "boolean";
2257
- if (accepted.has("bigint")) return "bigint";
2258
2150
  return null;
2259
2151
  }
2260
- function coerceScalar(value, accepted, index) {
2152
+ function toNumber(source) {
2153
+ const trimmed = source.trim();
2154
+ if (trimmed === "") return source;
2155
+ const n = Number(trimmed);
2156
+ return Number.isFinite(n) ? n : source;
2157
+ }
2158
+ function toBoolean(source) {
2159
+ const normalized = source.trim().toLowerCase();
2160
+ if (normalized === "true") return true;
2161
+ if (normalized === "false") return false;
2162
+ return source;
2163
+ }
2164
+ function coerceScalar(value, accepted) {
2261
2165
  if (accepted.size === 0) return value;
2262
2166
  const sourceKind = slimKindOf(value);
2263
2167
  if (accepted.has(sourceKind)) return value;
2168
+ if (sourceKind !== "string") return value;
2264
2169
  const target = pickScalarTarget(accepted);
2265
- if (target === null) return value;
2266
- const entry = index.get(`${sourceKind}->${target}`);
2267
- if (entry === void 0) return value;
2268
- let result;
2269
- try {
2270
- result = entry.transform(value);
2271
- } catch (err) {
2272
- return value;
2273
- }
2274
- if (!result.coerced) return value;
2275
- const returnedKind = slimKindOf(result.value);
2276
- if (returnedKind !== entry.output) {
2277
- return value;
2278
- }
2279
- if (entry.output === "number" && !Number.isFinite(result.value)) {
2280
- return value;
2281
- }
2282
- return result.value;
2170
+ if (target === "number") return toNumber(value);
2171
+ if (target === "boolean") return toBoolean(value);
2172
+ return value;
2283
2173
  }
2284
- function coerceArrayMembers(arr, elementAccepted, index) {
2174
+ function coerceArrayMembers(arr, elementAccepted) {
2285
2175
  let changed = false;
2286
2176
  const out = [];
2287
2177
  for (const el of arr) {
2288
- const next = coerceScalar(el, elementAccepted, index);
2178
+ const next = coerceScalar(el, elementAccepted);
2289
2179
  if (next !== el) changed = true;
2290
2180
  out.push(next);
2291
2181
  }
2292
2182
  return changed ? out : arr;
2293
2183
  }
2294
- function coerceSetMembers(set, elementAccepted, index) {
2184
+ function coerceSetMembers(set, elementAccepted) {
2295
2185
  let changed = false;
2296
2186
  const out = [];
2297
2187
  for (const el of set) {
2298
- const next = coerceScalar(el, elementAccepted, index);
2188
+ const next = coerceScalar(el, elementAccepted);
2299
2189
  if (next !== el) changed = true;
2300
2190
  out.push(next);
2301
2191
  }
2302
2192
  return changed ? new Set(out) : set;
2303
2193
  }
2304
- function coerceValue(value, accepted, elementAccepted, index) {
2194
+ function coerceValue(value, accepted, elementAccepted) {
2305
2195
  if (Array.isArray(value)) {
2306
2196
  if (!accepted.has("array") || elementAccepted === void 0) return value;
2307
- return coerceArrayMembers(value, elementAccepted, index);
2197
+ return coerceArrayMembers(value, elementAccepted);
2308
2198
  }
2309
2199
  if (value instanceof Set) {
2310
2200
  if (!accepted.has("set") || elementAccepted === void 0) return value;
2311
- return coerceSetMembers(value, elementAccepted, index);
2201
+ return coerceSetMembers(value, elementAccepted);
2312
2202
  }
2313
- return coerceScalar(value, accepted, index);
2203
+ return coerceScalar(value, accepted);
2314
2204
  }
2315
2205
 
2316
2206
  const EMPTY_TRANSFORMS = Object.freeze([]);
2317
2207
  function buildRegister(state, formInstanceId, instanceConfig) {
2318
- const coerceIndex = instanceConfig?.coerce !== void 0 ? resolveCoercionIndex(instanceConfig.coerce) : state.coerceIndex;
2208
+ const coerceEnabled = instanceConfig?.coerce !== void 0 ? resolveCoerceEnabled(instanceConfig.coerce) : state.coerceEnabled;
2319
2209
  const instanceMeta = instanceConfig?.instanceMeta;
2320
- const formAutoAria = instanceConfig?.autoAria ?? true;
2321
2210
  const getDisplayStateAt = instanceConfig?.getDisplayStateAt;
2322
2211
  const withInstanceMeta = (meta) => {
2323
2212
  if (instanceMeta === void 0) return meta;
@@ -2357,16 +2246,15 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2357
2246
  const coerce = buildCoerceFn(
2358
2247
  state.schema,
2359
2248
  segments,
2360
- coerceIndex
2249
+ coerceEnabled
2361
2250
  );
2362
2251
  const coerceElement = buildElementCoerceFn(
2363
2252
  state.schema,
2364
2253
  segments,
2365
- coerceIndex
2254
+ coerceEnabled
2366
2255
  );
2367
2256
  const { aria } = computeFieldIdentity(formInstanceId, state.formKey, pathKey);
2368
2257
  const isRequired = state.schema.isRequiredAtPath(segments);
2369
- const ariaEnabled = options?.autoAria ?? formAutoAria;
2370
2258
  const ariaDisplayState = getDisplayStateAt !== void 0 ? computed(() => getDisplayStateAt(segments)) : void 0;
2371
2259
  const markBlank = () => state.setValueAtPath(segments, slimDefault, withInstanceMeta({ blank: true }));
2372
2260
  const internalRv = {
@@ -2468,7 +2356,6 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2468
2356
  // --- Aria (internal; consumed by the directive) ---
2469
2357
  aria,
2470
2358
  isRequired,
2471
- ariaEnabled,
2472
2359
  ...ariaDisplayState !== void 0 ? { ariaDisplayState } : {}
2473
2360
  };
2474
2361
  return shallowReadonly(internalRv);
@@ -2632,11 +2519,50 @@ const DERIVED_DISPLAY_KEYS = /* @__PURE__ */ new Set([
2632
2519
  "firstError",
2633
2520
  "firstOwnError"
2634
2521
  ]);
2635
- const META_SPECIAL_KEYS = /* @__PURE__ */ new Set(["errors", "validating", "valid", "transforming", "busy"]);
2636
- const BASE_MIRROR_KEYS = [...FIELD_STATE_KEYS].filter((k) => !DERIVED_DISPLAY_KEYS.has(k));
2637
- const META_MIRROR_KEYS = [...FIELD_STATE_KEYS].filter((k) => !META_SPECIAL_KEYS.has(k));
2638
- function defineGetter(target, key, get) {
2639
- Object.defineProperty(target, key, { get, enumerable: true, configurable: true });
2522
+ const META_KEYS = [
2523
+ ...FIELD_STATE_KEYS,
2524
+ "submitting",
2525
+ "submissionAttempts",
2526
+ "departAttempts",
2527
+ "submitError",
2528
+ "submitted",
2529
+ "instanceId",
2530
+ "errorCount"
2531
+ ];
2532
+ const BASE_META_KEYS = META_KEYS.filter((k) => !DERIVED_DISPLAY_KEYS.has(k));
2533
+ let INERT_HISTORY;
2534
+ function inertHistory() {
2535
+ INERT_HISTORY ?? (INERT_HISTORY = readonly({
2536
+ undo: () => false,
2537
+ redo: () => false,
2538
+ clear: () => {
2539
+ },
2540
+ canUndo: false,
2541
+ canRedo: false,
2542
+ size: 0
2543
+ }));
2544
+ return INERT_HISTORY;
2545
+ }
2546
+ const denyWrite = () => false;
2547
+ function buildMetaProxy(keys, read) {
2548
+ const target = {};
2549
+ const owns = new Set(keys);
2550
+ return new Proxy(target, {
2551
+ get: (_, key) => owns.has(key) ? read(key) : Reflect.get(target, key),
2552
+ has: (_, key) => owns.has(key) || Reflect.has(target, key),
2553
+ // Safe to hand back the same array every time: the spec copies a
2554
+ // trap's key list before using it.
2555
+ ownKeys: () => keys,
2556
+ getOwnPropertyDescriptor(_, key) {
2557
+ if (!owns.has(key)) return Reflect.getOwnPropertyDescriptor(target, key);
2558
+ return { configurable: true, enumerable: true, value: read(key), writable: false };
2559
+ },
2560
+ // A getter with no setter throws on assignment under strict mode,
2561
+ // which every module here is. `false` keeps that.
2562
+ set: denyWrite,
2563
+ deleteProperty: denyWrite,
2564
+ defineProperty: denyWrite
2565
+ });
2640
2566
  }
2641
2567
  function buildFormApi(state, formInstanceId, options = {}) {
2642
2568
  const instanceBag = pickDefined({
@@ -2663,32 +2589,26 @@ function buildFormApi(state, formInstanceId, options = {}) {
2663
2589
  const rootBaseComputed = computed(
2664
2590
  () => buildContainerFieldStateBase(state, ROOT_PATH, ROOT_PATH_KEY, formInstanceId).base
2665
2591
  );
2666
- const metaBase = {
2667
- instanceId: formInstanceId,
2668
- get submitting() {
2669
- return state.submitting.value;
2670
- },
2671
- get submissionAttempts() {
2672
- return state.submissionAttempts.value;
2673
- },
2674
- get departAttempts() {
2675
- return state.departAttempts.value;
2676
- },
2677
- get submitError() {
2678
- return state.submitError.value;
2679
- },
2680
- get submitted() {
2681
- return state.submitted.value;
2592
+ const metaBase = buildMetaProxy(BASE_META_KEYS, (key) => {
2593
+ switch (key) {
2594
+ case "instanceId":
2595
+ return formInstanceId;
2596
+ case "errorCount":
2597
+ return rootBaseComputed.value.errors.length;
2598
+ case "submitting":
2599
+ return state.submitting.value;
2600
+ case "submissionAttempts":
2601
+ return state.submissionAttempts.value;
2602
+ case "departAttempts":
2603
+ return state.departAttempts.value;
2604
+ case "submitError":
2605
+ return state.submitError.value;
2606
+ case "submitted":
2607
+ return state.submitted.value;
2608
+ default:
2609
+ return rootBaseComputed.value[key];
2682
2610
  }
2683
- };
2684
- for (const k of BASE_MIRROR_KEYS) {
2685
- defineGetter(
2686
- metaBase,
2687
- k,
2688
- () => rootBaseComputed.value[k]
2689
- );
2690
- }
2691
- defineGetter(metaBase, "errorCount", () => rootBaseComputed.value.errors.length);
2611
+ });
2692
2612
  const getFormMetaBase = () => {
2693
2613
  void state.submitting.value;
2694
2614
  void state.submissionAttempts.value;
@@ -2697,28 +2617,41 @@ function buildFormApi(state, formInstanceId, options = {}) {
2697
2617
  void state.submitted.value;
2698
2618
  return metaBase;
2699
2619
  };
2700
- const fieldStateAccessorOptions = options.getDisplayState !== void 0 ? { getDisplayState: options.getDisplayState } : void 0;
2701
- const pathSweep = createDynamicPathSweep(state);
2620
+ const pathSweep = state.pathSweep;
2702
2621
  const getRootFieldStateAt = buildFieldStateAccessor(
2703
2622
  state,
2704
2623
  formInstanceId,
2705
2624
  getFormMetaBase,
2706
- pathSweep,
2707
- fieldStateAccessorOptions
2625
+ pathSweep
2708
2626
  );
2709
2627
  const getDisplayStateAt = (segments) => getRootFieldStateAt(segments).value.displayState;
2710
2628
  const registerConfig = {
2711
- ...pickDefined({ instanceMeta, coerce: options.coerce, autoAria: options.autoAria }),
2629
+ ...pickDefined({ instanceMeta, coerce: options.coerce }),
2712
2630
  getDisplayStateAt
2713
2631
  };
2714
2632
  const register = buildRegister(state, formInstanceId, registerConfig);
2715
- const processOptions = pickDefined({ onInvalidSubmit: options.onInvalidSubmit });
2716
- const defaultInvalidSubmitPolicy = options.onInvalidSubmit ?? "focus-first-error";
2633
+ const focusFirstError = (options2) => {
2634
+ const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
2635
+ if (target === null) return false;
2636
+ target.element.focus({ focusVisible: true, ...options2 });
2637
+ return true;
2638
+ };
2639
+ const scrollToFirstError = (options2) => {
2640
+ const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
2641
+ if (target === null) return false;
2642
+ target.element.scrollIntoView(options2);
2643
+ return true;
2644
+ };
2645
+ const applyInvalidSubmitPolicyPublic = () => {
2646
+ if (options.focusOnInvalidSubmit !== false) focusFirstError();
2647
+ };
2717
2648
  const {
2718
2649
  validate: validateBuilt,
2719
2650
  parse: parseBuilt,
2720
2651
  handleSubmit
2721
- } = buildProcessForm(state, formInstanceId, processOptions);
2652
+ } = buildProcessForm(state, {
2653
+ applyInvalidSubmit: applyInvalidSubmitPolicyPublic
2654
+ });
2722
2655
  const validate = (pathInput) => validateBuilt(pathInput);
2723
2656
  const parse = (arg1, arg2) => {
2724
2657
  const isPathArg = typeof arg1 === "string" || Array.isArray(arg1);
@@ -2846,22 +2779,21 @@ function buildFormApi(state, formInstanceId, options = {}) {
2846
2779
  () => state.firstValidationDone.value && state.errorCells.size === 0 && state.derivedBlankErrors.value.size === 0 && !validating.value
2847
2780
  );
2848
2781
  const history = options.history;
2849
- const formHistory = readonly(
2782
+ const formHistory = history === void 0 ? inertHistory() : readonly(
2850
2783
  reactive({
2851
- undo: history?.undo ?? (() => false),
2852
- redo: history?.redo ?? (() => false),
2853
- clear: history?.clear ?? (() => {
2854
- }),
2855
- canUndo: history?.canUndo ?? computed(() => false),
2856
- canRedo: history?.canRedo ?? computed(() => false),
2857
- size: history?.historySize ?? computed(() => 0)
2784
+ undo: history.undo,
2785
+ redo: history.redo,
2786
+ clear: history.clear,
2787
+ canUndo: history.canUndo,
2788
+ canRedo: history.canRedo,
2789
+ size: history.historySize
2858
2790
  })
2859
2791
  );
2860
2792
  const metaErrors = computed(
2861
- () => aggregateErrorsAt(state, [])
2793
+ () => aggregateErrorsAt(state, [], ROOT_PATH_KEY)
2862
2794
  );
2863
2795
  const rootFieldState = getRootFieldStateAt([]);
2864
- const metaTarget = {
2796
+ const metaOwn = {
2865
2797
  // Whole-form work signals compose the LIFECYCLE counters with the
2866
2798
  // per-leaf rollup: a submit-time validate shows up as
2867
2799
  // activeValidations, per-field debounced validators as
@@ -2890,14 +2822,11 @@ function buildFormApi(state, formInstanceId, options = {}) {
2890
2822
  // identifier).
2891
2823
  instanceId: formInstanceId
2892
2824
  };
2893
- for (const k of META_MIRROR_KEYS) {
2894
- defineGetter(
2895
- metaTarget,
2896
- k,
2897
- () => rootFieldState.value[k]
2898
- );
2899
- }
2900
- defineGetter(metaTarget, "errorCount", () => metaErrors.value.length);
2825
+ const metaTarget = buildMetaProxy(META_KEYS, (key) => {
2826
+ if (key === "errorCount") return metaErrors.value.length;
2827
+ if (Object.hasOwn(metaOwn, key)) return metaOwn[key];
2828
+ return rootFieldState.value[key];
2829
+ });
2901
2830
  const formMeta = readonly(reactive(metaTarget));
2902
2831
  const reset = (nextDefaultValues) => {
2903
2832
  if (nextDefaultValues === void 0) {
@@ -2937,21 +2866,6 @@ function buildFormApi(state, formInstanceId, options = {}) {
2937
2866
  } catch {
2938
2867
  }
2939
2868
  }
2940
- const focusFirstError = (options2) => {
2941
- const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
2942
- if (target === null) return false;
2943
- target.element.focus({ focusVisible: true, ...options2 });
2944
- return true;
2945
- };
2946
- const scrollToFirstError = (options2) => {
2947
- const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
2948
- if (target === null) return false;
2949
- target.element.scrollIntoView(options2);
2950
- return true;
2951
- };
2952
- const applyInvalidSubmitPolicyPublic = (policy) => {
2953
- applyInvalidSubmitPolicy(state, formInstanceId, policy ?? defaultInvalidSubmitPolicy);
2954
- };
2955
2869
  const fieldArrays = buildFieldArrayApi(state);
2956
2870
  const blankPathsView = computed(() => {
2957
2871
  const keys = /* @__PURE__ */ new Set();
@@ -3099,6 +3013,45 @@ function buildFormApi(state, formInstanceId, options = {}) {
3099
3013
  return api;
3100
3014
  }
3101
3015
 
3016
+ const SWEEP_SLICE = 8;
3017
+ function createDynamicPathSweep(deps) {
3018
+ const dynamicKeys = /* @__PURE__ */ new Set();
3019
+ const evictors = [];
3020
+ const isDynamicPath = (segments) => {
3021
+ for (let i = 0; i < segments.length; i++) {
3022
+ if (typeof segments[i] === "number") return true;
3023
+ if (!deps.isFixedObjectAtPath(segments.slice(0, i))) return true;
3024
+ }
3025
+ return false;
3026
+ };
3027
+ let sweepCursor = null;
3028
+ deps.onFormChange((next) => {
3029
+ if (dynamicKeys.size === 0) return;
3030
+ const raw = toRaw(next);
3031
+ for (let i = 0; i < SWEEP_SLICE; i++) {
3032
+ sweepCursor ?? (sweepCursor = dynamicKeys.values());
3033
+ const step = sweepCursor.next();
3034
+ if (step.done === true) {
3035
+ sweepCursor = null;
3036
+ break;
3037
+ }
3038
+ const segments = segmentsForPathKey(step.value);
3039
+ if (segments !== null && hasAtPath(raw, segments)) continue;
3040
+ dynamicKeys.delete(step.value);
3041
+ for (const evict of evictors) evict(step.value);
3042
+ }
3043
+ });
3044
+ return {
3045
+ track(segments, key) {
3046
+ if (dynamicKeys.has(key)) return;
3047
+ if (isDynamicPath(segments)) dynamicKeys.add(key);
3048
+ },
3049
+ onEvict(evict) {
3050
+ evictors.push(evict);
3051
+ }
3052
+ };
3053
+ }
3054
+
3102
3055
  const IDLE = Object.freeze({ display: "idle" });
3103
3056
  const MAX_DELAY = 2147483647;
3104
3057
  const PENDING_LIVENESS_MS = 250;
@@ -3187,6 +3140,58 @@ function createDisplayEngine(ssr) {
3187
3140
  return engine;
3188
3141
  }
3189
3142
 
3143
+ function buildErrorPathIndex(cells, blank) {
3144
+ const keys = /* @__PURE__ */ new Set();
3145
+ for (const [key, cell] of cells) {
3146
+ if (cell.schema.length > 0 || cell.user.length > 0) keys.add(key);
3147
+ }
3148
+ for (const [key, list] of blank) {
3149
+ if (list.length > 0) keys.add(key);
3150
+ }
3151
+ if (keys.size === 0) return EMPTY_INDEX;
3152
+ const entries = [];
3153
+ for (const key of keys) {
3154
+ const segments = segmentsForPathKey(key);
3155
+ if (segments !== null) entries.push({ key, segments });
3156
+ }
3157
+ entries.sort(compareByKey);
3158
+ return entries;
3159
+ }
3160
+ const EMPTY_INDEX = Object.freeze([]);
3161
+ function compareByKey(a, b) {
3162
+ return a.key < b.key ? -1 : a.key > b.key ? 1 : 0;
3163
+ }
3164
+ function windowUnder(index, prefix) {
3165
+ if (prefix.length === 0 || index.length === 0) return index;
3166
+ const prefixKey = keyForSegments(prefix).key;
3167
+ const marker = `${prefixKey.slice(0, -1)},`;
3168
+ const start = lowerBound(index, marker);
3169
+ if (start >= index.length) return EMPTY_INDEX;
3170
+ let end = start;
3171
+ for (; end < index.length; end += 1) {
3172
+ const entry = index[end];
3173
+ if (entry === void 0 || entry.key > prefixKey) break;
3174
+ }
3175
+ return start === 0 && end === index.length ? index : index.slice(start, end);
3176
+ }
3177
+ function isSameWindow(a, b) {
3178
+ if (a.length !== b.length) return false;
3179
+ for (let i = 0; i < a.length; i += 1) {
3180
+ if (a[i]?.key !== b[i]?.key) return false;
3181
+ }
3182
+ return true;
3183
+ }
3184
+ function lowerBound(index, target) {
3185
+ let lo = 0;
3186
+ let hi = index.length;
3187
+ while (lo < hi) {
3188
+ const mid = lo + hi >>> 1;
3189
+ if ((index[mid]?.key ?? target) < target) lo = mid + 1;
3190
+ else hi = mid;
3191
+ }
3192
+ return lo;
3193
+ }
3194
+
3190
3195
  function mergeSparseHydration(schemaDefaults, sparse, schema) {
3191
3196
  return mergeDeep(schemaDefaults, sparse, [], schema);
3192
3197
  }
@@ -3397,16 +3402,15 @@ function walkAuthoredFromSchemaDiff(withDefaults, withoutDefaults, prefix, out)
3397
3402
  out.add(canonicalizePath(prefix).key);
3398
3403
  }
3399
3404
  }
3400
- function computeBaselineResponse(schema, strict, source) {
3405
+ function computeBaselineResponse(schema, source) {
3401
3406
  const completed = source === void 0 ? void 0 : mergeStructural(schema, [], source);
3402
3407
  return schema.getDefaultValues({
3403
3408
  useDefaultSchemaValues: true,
3404
- constraints: completed,
3405
- strict
3409
+ constraints: completed
3406
3410
  });
3407
3411
  }
3408
- function initialFirstValidationGate(schema, strict) {
3409
- return !strict || schema.needsAsyncValidation?.() !== true;
3412
+ function initialFirstValidationGate(schema) {
3413
+ return schema.needsAsyncValidation?.() !== true;
3410
3414
  }
3411
3415
  function seedOriginalsFromBaseline(st, baseline, ensureOrdinals) {
3412
3416
  st.originals.clear();
@@ -3418,7 +3422,7 @@ function seedOriginalsFromBaseline(st, baseline, ensureOrdinals) {
3418
3422
  });
3419
3423
  }
3420
3424
  function queueInitialAsyncValidation(st) {
3421
- if (!st.ssr && st.strict && st.schema.needsAsyncValidation?.() === true) {
3425
+ if (!st.ssr && st.schema.needsAsyncValidation?.() === true) {
3422
3426
  queueMicrotask(() => scheduleFieldValidation(
3423
3427
  st,
3424
3428
  [],
@@ -3460,10 +3464,6 @@ function ensurePathOrdinal(st, key) {
3460
3464
  }
3461
3465
  return ordinal;
3462
3466
  }
3463
- function pathHasAsyncValidation(st, path) {
3464
- const { key } = canonicalizePath(path);
3465
- return pathHasAsyncValidationByKey(st, key, path);
3466
- }
3467
3467
  function pathHasAsyncValidationByKey(st, key, segments) {
3468
3468
  const cached = st.pathAsyncCache.get(key);
3469
3469
  if (cached !== void 0) return cached;
@@ -3606,10 +3606,15 @@ function commitWritePatches(st, patches, meta) {
3606
3606
  const now = (/* @__PURE__ */ new Date()).toISOString();
3607
3607
  for (const patch of patches) {
3608
3608
  const { key } = canonicalizePath(patch.path);
3609
- if (patch.kind === "added" && !st.originals.has(key)) {
3609
+ if (!st.originals.has(key)) {
3610
3610
  st.originals.set(key, { segments: patch.path, value: void 0 });
3611
3611
  }
3612
3612
  touchFieldRecord(st, key, patch.path, { updatedAt: now });
3613
+ st.pathSweep.track(patch.path, key);
3614
+ for (let i = 1; i < patch.path.length; i++) {
3615
+ const ancestor = patch.path.slice(0, i);
3616
+ st.pathSweep.track(ancestor, canonicalizePath(ancestor).key);
3617
+ }
3613
3618
  }
3614
3619
  for (const listener of st.formChangeListeners) {
3615
3620
  try {
@@ -3814,10 +3819,7 @@ function setValueAtPath(st, path, value, meta) {
3814
3819
  if (newlyAuthored && st.schema.isPreprocessOrCoerceLeaf(path)) {
3815
3820
  const modeForAuthoringTransition = meta?.instance?.validateOn ?? st.fieldValidationMode;
3816
3821
  if (modeForAuthoringTransition === "change") {
3817
- scheduleFieldValidation(st, path, false, {
3818
- ...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
3819
- ...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
3820
- });
3822
+ scheduleFieldValidation(st, path, false, meta?.instance);
3821
3823
  }
3822
3824
  }
3823
3825
  return true;
@@ -3833,15 +3835,12 @@ function setValueAtPath(st, path, value, meta) {
3833
3835
  st.arrayIdentity.realign(path);
3834
3836
  } else if (isContainer(currentValue) && !isContainer(value)) {
3835
3837
  if (subtreeHadRealBaseline(st, path, currentValue)) {
3836
- st.removedSubtrees.add(canonicalizePath(path).key);
3838
+ st.removedSubtrees.add(pathKey);
3837
3839
  }
3838
3840
  }
3839
3841
  const effectiveModeAfterWrite = meta?.instance?.validateOn ?? st.fieldValidationMode;
3840
3842
  if (effectiveModeAfterWrite === "change") {
3841
- scheduleFieldValidation(st, path, false, {
3842
- ...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
3843
- ...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
3844
- });
3843
+ scheduleFieldValidation(st, path, false, meta?.instance);
3845
3844
  }
3846
3845
  return true;
3847
3846
  }
@@ -3902,12 +3901,11 @@ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variant
3902
3901
  path: [...parentPath, ...err.path]
3903
3902
  }));
3904
3903
  applySchemaErrorsForSubtree(st, parentPath, reStamped);
3905
- const { key: parentKey2 } = canonicalizePath(parentPath);
3906
- const prevValidation = st.fieldValidationState.get(parentKey2);
3904
+ const prevValidation = st.fieldValidationState.get(parentKey);
3907
3905
  if (prevValidation !== void 0) {
3908
3906
  if (prevValidation.timer !== null) clearTimeout(prevValidation.timer);
3909
3907
  prevValidation.aborted = true;
3910
- st.fieldValidationState.delete(parentKey2);
3908
+ st.fieldValidationState.delete(parentKey);
3911
3909
  }
3912
3910
  appliedSync = true;
3913
3911
  }
@@ -3915,17 +3913,14 @@ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variant
3915
3913
  applyFormReplacement(st, nextForm, meta);
3916
3914
  for (const k of newBlankPaths) st.blankPaths.add(k);
3917
3915
  if (reshapeMode === "change" && !appliedSync) {
3918
- scheduleFieldValidation(st, parentPath, false, {
3919
- ...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
3920
- ...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
3921
- });
3916
+ scheduleFieldValidation(st, parentPath, false, meta?.instance);
3922
3917
  }
3923
3918
  return true;
3924
3919
  }
3925
- function scheduleFieldValidation(st, path, immediate, override) {
3926
- const effectiveMode = override?.mode ?? st.fieldValidationMode;
3920
+ function scheduleFieldValidation(st, path, immediate, instance) {
3921
+ const effectiveMode = instance?.validateOn ?? st.fieldValidationMode;
3927
3922
  if (effectiveMode === "submit") return;
3928
- const effectiveDebounce = override?.debounceMs ?? st.fieldValidationDebounceMs;
3923
+ const effectiveDebounce = instance?.debounceMs ?? st.fieldValidationDebounceMs;
3929
3924
  const { key } = canonicalizePath(path);
3930
3925
  const prev = st.fieldValidationState.get(key);
3931
3926
  if (prev !== void 0) {
@@ -4199,10 +4194,7 @@ function markFocused(st, path, focused, meta) {
4199
4194
  });
4200
4195
  }
4201
4196
  if (changed) {
4202
- scheduleFieldValidation(st, path, true, {
4203
- ...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
4204
- ...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
4205
- });
4197
+ scheduleFieldValidation(st, path, true, meta?.instance);
4206
4198
  }
4207
4199
  }
4208
4200
  }
@@ -4214,10 +4206,9 @@ function markInteracted(st, path) {
4214
4206
  }
4215
4207
  function touchAtPath(st, segments) {
4216
4208
  const formValue = st.form.value;
4217
- for (const [, entry] of st.originals) {
4209
+ for (const [leafKey, entry] of st.originals) {
4218
4210
  if (!isPathPrefix(segments, entry.segments)) continue;
4219
4211
  if (!hasAtPath(formValue, entry.segments)) continue;
4220
- const leafKey = canonicalizePath(entry.segments).key;
4221
4212
  const current = st.fields.get(leafKey);
4222
4213
  if (current?.touched === true) continue;
4223
4214
  touchFieldRecord(st, leafKey, entry.segments, { touched: true });
@@ -4227,11 +4218,10 @@ function interactAtPath(st, segments) {
4227
4218
  if (st.effectiveDisabled.value) return false;
4228
4219
  const formValue = st.form.value;
4229
4220
  let interactedAny = false;
4230
- for (const [, entry] of st.originals) {
4221
+ for (const [leafKey, entry] of st.originals) {
4231
4222
  if (!isPathPrefix(segments, entry.segments)) continue;
4232
4223
  if (!hasAtPath(formValue, entry.segments)) continue;
4233
4224
  interactedAny = true;
4234
- const leafKey = canonicalizePath(entry.segments).key;
4235
4225
  const current = st.fields.get(leafKey);
4236
4226
  if (current?.touched === true && current.interacted === true && current.blurredAfterInteraction === true) {
4237
4227
  continue;
@@ -4283,11 +4273,7 @@ function adoptResolvedDefaults(st, value) {
4283
4273
  st.schema
4284
4274
  )
4285
4275
  );
4286
- seedOriginalsFromBaseline(
4287
- st,
4288
- computeBaselineResponse(st.schema, st.strict, st.defaultValues).data,
4289
- false
4290
- );
4276
+ seedOriginalsFromBaseline(st, computeBaselineResponse(st.schema, st.defaultValues).data, false);
4291
4277
  }
4292
4278
  function reset(st, nextDefaultValues) {
4293
4279
  const resetSource = nextDefaultValues === void 0 ? st.defaultValues : mergeSparseHydration(
@@ -4296,7 +4282,7 @@ function reset(st, nextDefaultValues) {
4296
4282
  st.schema
4297
4283
  );
4298
4284
  st.defaultValues = structuralSnapshot(resetSource);
4299
- const resetResponse = computeBaselineResponse(st.schema, st.strict, resetSource);
4285
+ const resetResponse = computeBaselineResponse(st.schema, resetSource);
4300
4286
  const next = resetResponse.data;
4301
4287
  rebuildAuthoredPaths(st, resetSource, next);
4302
4288
  applyFormReplacement(st, next);
@@ -4313,16 +4299,14 @@ function reset(st, nextDefaultValues) {
4313
4299
  st.blankPaths.add(key);
4314
4300
  }
4315
4301
  st.errorCells.clear();
4316
- if (st.strict && !resetResponse.success) {
4302
+ if (!resetResponse.success) {
4317
4303
  replaceErrorChannel(st, "schema", resetResponse.errors);
4318
4304
  }
4319
- if (st.strict) {
4320
- const syncResult = st.schema.validateAtPath(st.form.value, void 0, { sync: true });
4321
- if (!(syncResult instanceof Promise) && !syncResult.success) {
4322
- applySchemaErrorsForSubtree(st, [], syncResult.errors);
4323
- }
4305
+ const syncResult = st.schema.validateAtPath(st.form.value, void 0, { sync: true });
4306
+ if (!(syncResult instanceof Promise) && !syncResult.success) {
4307
+ applySchemaErrorsForSubtree(st, [], syncResult.errors);
4324
4308
  }
4325
- st.firstValidationDone.value = initialFirstValidationGate(st.schema, st.strict);
4309
+ st.firstValidationDone.value = initialFirstValidationGate(st.schema);
4326
4310
  queueInitialAsyncValidation(st);
4327
4311
  const now = (/* @__PURE__ */ new Date()).toISOString();
4328
4312
  for (const [pathKey, record] of st.fields) {
@@ -4412,10 +4396,6 @@ function clearFieldRecordFlags(st, pathKey) {
4412
4396
  if (record === void 0) return;
4413
4397
  st.fields.set(pathKey, withClearedHistoryFlags(record, (/* @__PURE__ */ new Date()).toISOString()));
4414
4398
  }
4415
- function isPristineAtPath(st, path) {
4416
- const { key, segments } = canonicalizePath(path);
4417
- return isPristineAtPathByKey(st, key, segments);
4418
- }
4419
4399
  function isPristineAtPathByKey(st, key, segments) {
4420
4400
  if (st.blankPaths.has(key) !== st.originalBlankPaths.has(key)) return false;
4421
4401
  const entry = st.originals.get(key);
@@ -4449,12 +4429,8 @@ function getFieldRecord(st, path) {
4449
4429
  const { key } = canonicalizePath(path);
4450
4430
  return st.fields.get(key);
4451
4431
  }
4452
- function getOriginalAtPath(st, path) {
4453
- const { key } = canonicalizePath(path);
4454
- return st.originals.get(key)?.value;
4455
- }
4456
4432
  function createFormStore(options) {
4457
- const { formKey, schema, defaultValues, strict = true, hydration } = options;
4433
+ const { formKey, schema, defaultValues, hydration } = options;
4458
4434
  const ssr = options.ssr === true;
4459
4435
  const ssrPrefetch = options.ssrPrefetch;
4460
4436
  const rememberVariants = options.rememberVariants !== false;
@@ -4462,22 +4438,16 @@ function createFormStore(options) {
4462
4438
  const fieldValidationDebounceMs = normalizeNumericOption({
4463
4439
  value: options.debounceMs ?? DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS,
4464
4440
  source: "useForm.debounceMs",
4465
- allowInfinity: false,
4466
4441
  min: 0,
4467
4442
  defaultValue: DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS
4468
4443
  });
4469
- const coerceIndex = resolveCoercionIndex(options.coerce);
4470
- const resolvedGetDisplayState = resolveGetDisplayState(options.getDisplayState);
4444
+ const coerceEnabled = resolveCoerceEnabled(options.coerce);
4471
4445
  const cleanupHooks = [];
4472
4446
  const modules = /* @__PURE__ */ new Map();
4473
4447
  const fieldValidatingSince = reactive(/* @__PURE__ */ new Map());
4474
4448
  const displayEngine = createDisplayEngine(ssr);
4475
4449
  cleanupHooks.push(() => displayEngine.dispose());
4476
- const schemaResponse = computeBaselineResponse(
4477
- schema,
4478
- strict,
4479
- defaultValues
4480
- );
4450
+ const schemaResponse = computeBaselineResponse(schema, defaultValues);
4481
4451
  const schemaInitialData = schemaResponse.data;
4482
4452
  const authoredPaths = /* @__PURE__ */ new Set();
4483
4453
  const initialData = hydration !== void 0 ? hydration.form : structuralSnapshot(schemaInitialData);
@@ -4490,16 +4460,15 @@ function createFormStore(options) {
4490
4460
  const v = getAtPath(toRaw(form.value), arraySegs);
4491
4461
  return Array.isArray(v) ? v.length : 0;
4492
4462
  });
4493
- const fields = reactive(/* @__PURE__ */ new Map());
4463
+ const fields = shallowReactive(/* @__PURE__ */ new Map());
4494
4464
  const domBinding = shallowRef(null);
4495
- const errorCells = reactive(/* @__PURE__ */ new Map());
4496
- const originals = reactive(/* @__PURE__ */ new Map());
4465
+ const errorCells = shallowReactive(/* @__PURE__ */ new Map());
4466
+ const originals = shallowReactive(/* @__PURE__ */ new Map());
4497
4467
  const removedSubtrees = /* @__PURE__ */ new Set();
4498
- const initialTransientList = hydration?.blankPaths ?? options.initialBlankPaths ?? [];
4499
4468
  const blankPaths = reactive(/* @__PURE__ */ new Set());
4500
4469
  const originalBlankPaths = /* @__PURE__ */ new Set();
4501
- for (const raw of initialTransientList) {
4502
- const key = coerceToPathKey(raw);
4470
+ const seededBlankPaths = hydration !== void 0 ? (hydration.blankPaths ?? []).map((dotted) => canonicalizePath(dotted).key) : options.initialBlankPaths ?? [];
4471
+ for (const key of seededBlankPaths) {
4503
4472
  blankPaths.add(key);
4504
4473
  originalBlankPaths.add(key);
4505
4474
  }
@@ -4516,6 +4485,9 @@ function createFormStore(options) {
4516
4485
  }
4517
4486
  return result;
4518
4487
  });
4488
+ const errorPathIndex = computed(
4489
+ () => buildErrorPathIndex(errorCells, derivedBlankErrors.value)
4490
+ );
4519
4491
  const submitting = ref(false);
4520
4492
  const activeSubmissions = ref(0);
4521
4493
  const submissionAttempts = ref(0);
@@ -4540,7 +4512,7 @@ function createFormStore(options) {
4540
4512
  const defaultsResolved = ref(false);
4541
4513
  const activated = ref(false);
4542
4514
  const activationPromise = ref(void 0);
4543
- const firstValidationDone = ref(initialFirstValidationGate(schema, strict));
4515
+ const firstValidationDone = ref(initialFirstValidationGate(schema));
4544
4516
  watch(activeValidations, (now, prev) => {
4545
4517
  if (prev > 0 && now === 0) {
4546
4518
  firstValidationDone.value = true;
@@ -4558,6 +4530,33 @@ function createFormStore(options) {
4558
4530
  const activeTransforms = ref(0);
4559
4531
  const transformRuns = /* @__PURE__ */ new Map();
4560
4532
  const transformWaiters = [];
4533
+ const errorWindows = /* @__PURE__ */ new Map();
4534
+ const pathSweep = createDynamicPathSweep({
4535
+ onFormChange: (listener) => {
4536
+ formChangeListeners.add(listener);
4537
+ },
4538
+ isFixedObjectAtPath: (path) => schema.isFixedObjectAtPath(path)
4539
+ });
4540
+ pathSweep.onEvict((key) => {
4541
+ fields.delete(key);
4542
+ fieldValidationState.delete(key);
4543
+ authoredPaths.delete(key);
4544
+ if (originals.get(key)?.value === void 0) originals.delete(key);
4545
+ errorWindows.delete(key);
4546
+ });
4547
+ const errorWindowAt = (prefix, prefixKey) => {
4548
+ let cached = errorWindows.get(prefixKey);
4549
+ if (cached === void 0) {
4550
+ const frozen = [...prefix];
4551
+ cached = computed((prev) => {
4552
+ const next = windowUnder(errorPathIndex.value, frozen);
4553
+ return prev !== void 0 && isSameWindow(prev, next) ? prev : next;
4554
+ });
4555
+ errorWindows.set(prefixKey, cached);
4556
+ pathSweep.track(frozen, prefixKey);
4557
+ }
4558
+ return cached.value;
4559
+ };
4561
4560
  const arrayBookkeeping = createArrayBookkeeping({
4562
4561
  form,
4563
4562
  fields,
@@ -4575,6 +4574,7 @@ function createFormStore(options) {
4575
4574
  touchFieldRecord: (pathKey, path, patch) => touchFieldRecord(st, pathKey, path, patch),
4576
4575
  decFieldValidation: (key) => decFieldValidation(st, key)
4577
4576
  });
4577
+ const bind = (fn) => (...args) => fn(st, ...args);
4578
4578
  const st = {
4579
4579
  // --- public data (the FormStore contract's state members) ---
4580
4580
  formKey,
@@ -4582,10 +4582,11 @@ function createFormStore(options) {
4582
4582
  fields,
4583
4583
  errorCells,
4584
4584
  derivedBlankErrors,
4585
+ errorWindowAt,
4585
4586
  originals,
4587
+ pathSweep,
4586
4588
  schema,
4587
4589
  ssr,
4588
- getDisplayState: resolvedGetDisplayState,
4589
4590
  submitting,
4590
4591
  activeSubmissions,
4591
4592
  submissionAttempts,
@@ -4613,11 +4614,10 @@ function createFormStore(options) {
4613
4614
  displayEngine,
4614
4615
  domBinding,
4615
4616
  modules,
4616
- coerceIndex,
4617
+ coerceEnabled,
4617
4618
  blankPaths,
4618
4619
  originalBlankPaths,
4619
4620
  // --- kernel-internal state ---
4620
- strict,
4621
4621
  // Defensive copy, not a fix for an observed alias: today
4622
4622
  // `getDefaultValues` happens to build a fresh tree, so form storage
4623
4623
  // does not currently share structure with the consumer's object.
@@ -4654,17 +4654,20 @@ function createFormStore(options) {
4654
4654
  transformTokenSeq: 0,
4655
4655
  warnedDisabledWrite: false,
4656
4656
  // --- methods: thin per-instance skins over the module kernel ---
4657
- rehydrate: () => rehydrate(st),
4658
- activate: () => activate(st),
4659
- adoptResolvedDefaults: (value) => adoptResolvedDefaults(st, value),
4660
- pathHasAsyncValidation: (path) => pathHasAsyncValidation(st, path),
4661
- pathHasAsyncValidationByKey: (key, segments) => pathHasAsyncValidationByKey(st, key, segments),
4662
- applyFormReplacement: (next, meta) => applyFormReplacement(st, next, meta),
4663
- setValueAtPath: (path, value, meta) => setValueAtPath(st, path, value, meta),
4664
- getValueAtPath: (path) => getValueAtPath(st, path),
4665
- arrayElementKey: (path) => arrayElementKey(st, path),
4666
- reset: (nextDefaultValues) => reset(st, nextDefaultValues),
4667
- resetField: (path) => resetField(st, path),
4657
+ rehydrate: bind(rehydrate),
4658
+ activate: bind(activate),
4659
+ adoptResolvedDefaults: bind(adoptResolvedDefaults),
4660
+ pathHasAsyncValidationByKey: bind(pathHasAsyncValidationByKey),
4661
+ applyFormReplacement: bind(applyFormReplacement),
4662
+ setValueAtPath: bind(setValueAtPath),
4663
+ getValueAtPath: bind(getValueAtPath),
4664
+ arrayElementKey: bind(arrayElementKey),
4665
+ reset: bind(reset),
4666
+ resetField: bind(resetField),
4667
+ // The schema/user pair below reads as a fold waiting to happen. It was
4668
+ // tried: a `setErrorsForPathIn(channel)` factory measured 10 B LARGER,
4669
+ // because gzip had already collected the rent on two adjacent copies
4670
+ // and the helper added a name the original did not need.
4668
4671
  setSchemaErrorsForPath: (path, entries) => setErrorChannelForKey(
4669
4672
  st,
4670
4673
  canonicalizePath(path).key,
@@ -4673,7 +4676,7 @@ function createFormStore(options) {
4673
4676
  ),
4674
4677
  setAllSchemaErrors: (entries) => replaceErrorChannel(st, "schema", entries),
4675
4678
  clearSchemaErrors: (path) => clearErrorChannel(st, "schema", path),
4676
- applySchemaErrorsForSubtree: (path, entries) => applySchemaErrorsForSubtree(st, path, entries),
4679
+ applySchemaErrorsForSubtree: bind(applySchemaErrorsForSubtree),
4677
4680
  setAllUserErrors: (entries) => replaceErrorChannel(st, "user", entries),
4678
4681
  setUserErrorsForPath: (path, entries) => setErrorChannelForKey(
4679
4682
  st,
@@ -4682,37 +4685,34 @@ function createFormStore(options) {
4682
4685
  entries.length === 0 ? NO_ERRORS : [...entries]
4683
4686
  ),
4684
4687
  clearUserErrors: (path) => clearErrorChannel(st, "user", path),
4685
- restoreErrorCells: (entries) => restoreErrorCells(st, entries),
4686
- getErrorsForPath: (path) => getErrorsForPath(st, path),
4687
- ensurePathOrdinal: (key) => ensurePathOrdinal(st, key),
4688
- noteDomConnected: (path) => noteDomConnected(st, path),
4689
- noteDomDisconnected: (path) => noteDomDisconnected(st, path),
4690
- markFocused: (path, focused, meta) => markFocused(st, path, focused, meta),
4691
- markInteracted: (path) => markInteracted(st, path),
4692
- touchAtPath: (segments) => touchAtPath(st, segments),
4693
- interactAtPath: (segments) => interactAtPath(st, segments),
4694
- markConnectedOptimistically: (path) => markConnectedOptimistically(st, path),
4695
- isPristineAtPath: (path) => isPristineAtPath(st, path),
4696
- isPristineAtPathByKey: (key, segments) => isPristineAtPathByKey(st, key, segments),
4697
- hasStructuralChangeUnder: (path) => hasStructuralChangeUnder(st, path),
4698
- hasRemovedSubtreeUnder: (path) => hasRemovedSubtreeUnder(st, path),
4699
- getFieldRecord: (path) => getFieldRecord(st, path),
4700
- getOriginalAtPath: (path) => getOriginalAtPath(st, path),
4701
- cancelFieldValidation: () => cancelFieldValidation(st),
4702
- beginTransform: (key, holder) => beginTransform(st, key, holder),
4703
- isCurrentTransform: (key, token) => isCurrentTransform(st, key, token),
4704
- endTransform: (key, token) => endTransform(st, key, token),
4705
- setTransformError: (key, err) => setTransformError(st, key, err),
4706
- cancelTransforms: () => cancelTransforms(st),
4707
- cancelTransformsUnder: (prefix) => cancelTransformsUnder(st, prefix),
4708
- settleTransforms: (path) => settleTransforms(st, path),
4709
- scheduleFieldValidation: (path, immediate, override) => scheduleFieldValidation(st, path, immediate, override),
4710
- onFormChange: (listener) => onFormChange(st, listener),
4711
- onSubmitSuccess: (listener) => onSubmitSuccess(st, listener),
4712
- onReset: (listener) => onReset(st, listener),
4713
- emitSubmitSuccess: () => emitSubmitSuccess(st),
4714
- registerCleanup: (fn) => registerCleanup(st, fn),
4715
- dispose: () => dispose(st)
4688
+ restoreErrorCells: bind(restoreErrorCells),
4689
+ getErrorsForPath: bind(getErrorsForPath),
4690
+ ensurePathOrdinal: bind(ensurePathOrdinal),
4691
+ noteDomConnected: bind(noteDomConnected),
4692
+ noteDomDisconnected: bind(noteDomDisconnected),
4693
+ markFocused: bind(markFocused),
4694
+ markInteracted: bind(markInteracted),
4695
+ touchAtPath: bind(touchAtPath),
4696
+ interactAtPath: bind(interactAtPath),
4697
+ markConnectedOptimistically: bind(markConnectedOptimistically),
4698
+ isPristineAtPathByKey: bind(isPristineAtPathByKey),
4699
+ hasStructuralChangeUnder: bind(hasStructuralChangeUnder),
4700
+ hasRemovedSubtreeUnder: bind(hasRemovedSubtreeUnder),
4701
+ getFieldRecord: bind(getFieldRecord),
4702
+ cancelFieldValidation: bind(cancelFieldValidation),
4703
+ beginTransform: bind(beginTransform),
4704
+ isCurrentTransform: bind(isCurrentTransform),
4705
+ endTransform: bind(endTransform),
4706
+ setTransformError: bind(setTransformError),
4707
+ cancelTransformsUnder: bind(cancelTransformsUnder),
4708
+ settleTransforms: bind(settleTransforms),
4709
+ scheduleFieldValidation: bind(scheduleFieldValidation),
4710
+ onFormChange: bind(onFormChange),
4711
+ onSubmitSuccess: bind(onSubmitSuccess),
4712
+ onReset: bind(onReset),
4713
+ emitSubmitSuccess: bind(emitSubmitSuccess),
4714
+ registerCleanup: bind(registerCleanup),
4715
+ dispose: bind(dispose)
4716
4716
  };
4717
4717
  rebuildAuthoredPaths(st, defaultValues, schemaInitialData);
4718
4718
  seedOriginalsFromBaseline(st, schemaInitialData, true);
@@ -4751,7 +4751,7 @@ function createFormStore(options) {
4751
4751
  blurredAfterInteraction: false
4752
4752
  });
4753
4753
  });
4754
- if (strict && !schemaResponse.success) {
4754
+ if (!schemaResponse.success) {
4755
4755
  replaceErrorChannel(st, "schema", schemaResponse.errors);
4756
4756
  }
4757
4757
  }
@@ -4782,19 +4782,18 @@ function useAbstractForm(configuration, options) {
4782
4782
  const resolvedDefaults = resolveTrichotomy(configuration.defaultValues);
4783
4783
  const materialisedDefaults = resolvedDefaults.kind === "sync" ? resolvedDefaults.value : void 0;
4784
4784
  const { defaultValues: _droppedDefaults, ...configWithoutDefaults } = configuration;
4785
- const trichotomyOverride = materialisedDefaults === void 0 ? configWithoutDefaults : { ...configWithoutDefaults, defaultValues: materialisedDefaults };
4786
- const merged = mergeWithDefaults(registry.defaults, trichotomyOverride);
4787
- const maxRecursionDepth = normalizeNumericOption({
4788
- value: merged.maxRecursionDepth ?? DEFAULT_MAX_RECURSION_DEPTH,
4789
- source: "useForm.maxRecursionDepth",
4790
- allowInfinity: true,
4791
- min: 0,
4792
- defaultValue: DEFAULT_MAX_RECURSION_DEPTH
4793
- });
4794
- const resolvedSchema = getComputedSchema(key, configuration.schema, { maxRecursionDepth });
4785
+ const materialisedConfiguration = materialisedDefaults === void 0 ? configWithoutDefaults : { ...configWithoutDefaults, defaultValues: materialisedDefaults };
4795
4786
  const existing = registry.forms.get(key);
4787
+ const resolvedSchema = existing === void 0 || false ? getComputedSchema(key, configuration.schema, {
4788
+ maxRecursionDepth: DEFAULT_MAX_RECURSION_DEPTH
4789
+ }) : existing.schema;
4796
4790
  const hadPendingHydration = registry.pendingHydration.has(key);
4797
- const state = existing ?? buildFreshState(key, resolvedSchema, merged, registry);
4791
+ const state = existing ?? buildFreshState(
4792
+ key,
4793
+ resolvedSchema,
4794
+ materialisedConfiguration,
4795
+ registry
4796
+ );
4798
4797
  if (existing !== void 0) ; else if (resolvedDefaults.kind === "sync") {
4799
4798
  state.defaultsResolved.value = true;
4800
4799
  }
@@ -4819,8 +4818,8 @@ function useAbstractForm(configuration, options) {
4819
4818
  const releaseConsumer = registry.trackConsumer(key);
4820
4819
  onScopeDispose(releaseConsumer);
4821
4820
  }
4822
- if (existing === void 0 && merged.history !== void 0) {
4823
- const historyModule = merged.history.attach(state);
4821
+ if (existing === void 0 && materialisedConfiguration.history !== void 0) {
4822
+ const historyModule = materialisedConfiguration.history.attach(state);
4824
4823
  state.modules.set(HISTORY_MODULE_KEY, historyModule);
4825
4824
  state.registerCleanup(() => historyModule.dispose());
4826
4825
  }
@@ -4833,36 +4832,16 @@ function useAbstractForm(configuration, options) {
4833
4832
  provide(kFormInstanceId, formInstanceId);
4834
4833
  }
4835
4834
  const apiOptions = pickDefined({
4836
- onInvalidSubmit: merged.onInvalidSubmit,
4835
+ focusOnInvalidSubmit: materialisedConfiguration.focusOnInvalidSubmit,
4837
4836
  history: state.modules.get(HISTORY_MODULE_KEY),
4838
- validateOn: merged.validateOn,
4839
- debounceMs: merged.debounceMs,
4840
- getDisplayState: merged.getDisplayState,
4841
- coerce: merged.coerce,
4842
- rememberVariants: merged.rememberVariants,
4843
- autoAria: merged.autoAria
4837
+ validateOn: materialisedConfiguration.validateOn,
4838
+ debounceMs: materialisedConfiguration.debounceMs,
4839
+ coerce: materialisedConfiguration.coerce,
4840
+ rememberVariants: materialisedConfiguration.rememberVariants
4844
4841
  });
4845
4842
  const api = buildFormApi(state, formInstanceId, apiOptions);
4846
4843
  return api;
4847
4844
  }
4848
- function mergeWithDefaults(defaults, configuration) {
4849
- return {
4850
- ...configuration,
4851
- ...pickDefined({
4852
- strict: configuration.strict ?? defaults.strict,
4853
- onInvalidSubmit: configuration.onInvalidSubmit ?? defaults.onInvalidSubmit,
4854
- history: configuration.history ?? defaults.history,
4855
- rememberVariants: configuration.rememberVariants ?? defaults.rememberVariants,
4856
- disabled: configuration.disabled ?? defaults.disabled,
4857
- coerce: configuration.coerce ?? defaults.coerce,
4858
- validateOn: configuration.validateOn ?? defaults.validateOn,
4859
- debounceMs: configuration.debounceMs ?? defaults.debounceMs,
4860
- getDisplayState: configuration.getDisplayState ?? defaults.getDisplayState,
4861
- maxRecursionDepth: configuration.maxRecursionDepth ?? defaults.maxRecursionDepth,
4862
- autoAria: configuration.autoAria ?? defaults.autoAria
4863
- })
4864
- };
4865
- }
4866
4845
  const HISTORY_MODULE_KEY = "history";
4867
4846
  function buildFreshState(key, schema, configuration, registry) {
4868
4847
  const pending = registry.pendingHydration.get(key);
@@ -4882,13 +4861,11 @@ function buildFreshState(key, schema, configuration, registry) {
4882
4861
  hydration: pending,
4883
4862
  ssr: registry.ssr,
4884
4863
  ...pickDefined({
4885
- strict: configuration.strict,
4886
4864
  validateOn: configuration.validateOn,
4887
4865
  debounceMs: configuration.debounceMs,
4888
4866
  rememberVariants: configuration.rememberVariants,
4889
4867
  disabled: configuration.disabled,
4890
4868
  coerce: configuration.coerce,
4891
- getDisplayState: configuration.getDisplayState,
4892
4869
  initialBlankPaths
4893
4870
  }),
4894
4871
  // Server-only: bind the SSR prefetch coordination handles. `enqueue`
@@ -5135,25 +5112,18 @@ function createWizardHistory(param) {
5135
5112
  };
5136
5113
  }
5137
5114
 
5138
- const NOOP_FINGERPRINT = "attaform:wizard-noop";
5139
5115
  const EMPTY_SLIM_KINDS = /* @__PURE__ */ new Set();
5140
- function buildNoopWizardSchema(formKey) {
5141
- const emptyValue = {};
5142
- const success = {
5143
- success: true,
5144
- data: emptyValue,
5145
- errors: void 0,
5146
- formKey
5147
- };
5148
- const defaultsResponse = {
5149
- success: true,
5150
- data: emptyValue,
5151
- errors: void 0,
5152
- formKey
5153
- };
5154
- return {
5155
- fingerprint: () => Promise.resolve(NOOP_FINGERPRINT),
5156
- getDefaultValues: () => defaultsResponse,
5116
+ const EMPTY_VALUE = {};
5117
+ const NOOP_SUCCESS = {
5118
+ success: true,
5119
+ data: EMPTY_VALUE,
5120
+ errors: void 0
5121
+ };
5122
+ const NOOP_DEFAULTS = NOOP_SUCCESS;
5123
+ let NOOP_SCHEMA;
5124
+ function buildNoopWizardSchema() {
5125
+ NOOP_SCHEMA ?? (NOOP_SCHEMA = {
5126
+ getDefaultValues: () => NOOP_DEFAULTS,
5157
5127
  getDefaultAtPath: () => void 0,
5158
5128
  getEmptyValueAtPath: () => void 0,
5159
5129
  isPreprocessOrCoerceLeaf: () => false,
@@ -5164,13 +5134,14 @@ function buildNoopWizardSchema(formKey) {
5164
5134
  // addressable, root included.
5165
5135
  entryKeyKindAtPath: () => void 0,
5166
5136
  getSchemasAtPath: () => [],
5167
- validateAtPath: () => success,
5137
+ validateAtPath: () => NOOP_SUCCESS,
5168
5138
  getSlimPrimitiveTypesAtPath: () => new Set(EMPTY_SLIM_KINDS),
5169
5139
  isLeafAtPath: () => false,
5170
5140
  isRequiredAtPath: () => false,
5171
5141
  getUnionDiscriminatorAtPath: () => void 0,
5172
5142
  hasDiscriminatedUnions: () => false
5173
- };
5143
+ });
5144
+ return NOOP_SCHEMA;
5174
5145
  }
5175
5146
 
5176
5147
  function buildCallableReadonlySnapshotProxy(opts) {
@@ -5285,7 +5256,7 @@ function useWizard(options) {
5285
5256
  if (typeof slot !== "string") continue;
5286
5257
  if (noopForms.has(slot)) continue;
5287
5258
  const noop = useAbstractForm({
5288
- schema: buildNoopWizardSchema(slot),
5259
+ schema: buildNoopWizardSchema(),
5289
5260
  key: slot
5290
5261
  });
5291
5262
  noopForms.set(slot, noop);
@@ -5296,7 +5267,7 @@ function useWizard(options) {
5296
5267
  const noop = lazyNoopScope.run(
5297
5268
  () => useAbstractForm(
5298
5269
  {
5299
- schema: buildNoopWizardSchema(key),
5270
+ schema: buildNoopWizardSchema(),
5300
5271
  key
5301
5272
  },
5302
5273
  { registry }
@@ -6380,4 +6351,4 @@ function escapeForInlineScript(json) {
6380
6351
  });
6381
6352
  }
6382
6353
 
6383
- export { AttaformErrorCode as A, DEFAULT_TIMINGS as D, defaultDisplayState as a, defineCoercion as b, injectWizard as c, defaultCoercionRules as d, escapeForInlineScript as e, isUnset as f, gate as g, useAbstractForm as h, injectForm as i, useRegister as j, useWizard as k, lazy as l, makeDefaultDisplayState as m, isPlainRecord as n, crossCopyState as o, getAtPath as p, humanize as q, slimKindOf as s, unset as u };
6354
+ export { AttaformErrorCode as A, injectWizard as a, isUnset as b, useAbstractForm as c, useRegister as d, escapeForInlineScript as e, useWizard as f, gate as g, getAtPath as h, injectForm as i, humanize as j, isPlainRecord as k, lazy as l, slimKindOf as s, unset as u };