attaform 0.28.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 (66) 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.oYrkP9dj.mjs → attaform-dev.BK6Ge2qR.mjs} +80 -341
  11. package/dist/dev/shared/{attaform-dev.Dr2YzS5B.mjs → attaform-dev.BQc5QV3Y.mjs} +11 -19
  12. package/dist/dev/shared/{attaform-dev.BR8u0YOZ.mjs → attaform-dev.BcNtyOmf.mjs} +4 -4
  13. package/dist/{shared/attaform.h0i6LijT.mjs → dev/shared/attaform-dev.BcYT6tFh.mjs} +152 -20
  14. package/dist/dev/shared/{attaform-dev.6qxD-Yqo.mjs → attaform-dev.BisFstxh.mjs} +227 -88
  15. package/dist/dev/shared/{attaform-dev.WmuhD_CZ.mjs → attaform-dev.CQ2rJiAX.mjs} +833 -656
  16. package/dist/dev/shared/{attaform-dev.P7cseiEG.mjs → attaform-dev.D6CLvaQT.mjs} +20 -11
  17. package/dist/dev/shared/{attaform-dev.D2I8e_Mm.mjs → attaform-dev.DTrHonpc.mjs} +225 -238
  18. package/dist/dev/shared/{attaform-dev.BXE2cr0L.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 +9 -7
  27. package/dist/index.mjs +5 -5
  28. package/dist/nuxt.d.mts +11 -20
  29. package/dist/nuxt.mjs +0 -1
  30. package/dist/runtime/plugins/attaform.mjs +3 -3
  31. package/dist/shared/{attaform.uLbun31C.mjs → attaform.B3resMQ1.mjs} +19 -11
  32. package/dist/shared/{attaform.Cs2Rbdlo.mjs → attaform.BK0cgu2K.mjs} +123 -139
  33. package/dist/{dev/shared/attaform-dev.By4PRjt0.mjs → shared/attaform.BRDDQeHV.mjs} +136 -26
  34. package/dist/shared/{attaform.NLmerepI.mjs → attaform.BXneBxEj.mjs} +71 -334
  35. package/dist/shared/{attaform.D6DCnnQu.mjs → attaform.ByWP6kSx.mjs} +4 -4
  36. package/dist/shared/{attaform.CJP3RkGa.mjs → attaform.CJ8DpRGj.mjs} +223 -238
  37. package/dist/shared/{attaform.C09fpdLS.mjs → attaform.CUfrMK7t.mjs} +227 -88
  38. package/dist/shared/{attaform.wfY8XFvm.mjs → attaform.CdZIEf7_.mjs} +11 -19
  39. package/dist/shared/{attaform.JfSWdEcb.d.mts → attaform.Clz0ArIi.d.mts} +1 -1
  40. package/dist/shared/{attaform.B8k8JrmK.mjs → attaform.DNJOWjQw.mjs} +826 -612
  41. package/dist/shared/{attaform.B4VkS43-.d.mts → attaform.Rc9u4Vfw.d.mts} +1 -1
  42. package/dist/shared/{attaform.D5V4tZWq.d.mts → attaform.UGyOK83T.d.mts} +200 -218
  43. package/dist/shared/{attaform.Dq4vWxuG.mjs → attaform.WiGdIqgx.mjs} +1 -3
  44. package/dist/shared/{attaform.Cgu-hdSb.d.mts → attaform.bKLzMU0o.d.mts} +321 -523
  45. package/dist/transforms.d.mts +0 -22
  46. package/dist/transforms.mjs +1 -1
  47. package/dist/vite.d.mts +13 -4
  48. package/dist/vite.mjs +8 -2
  49. package/dist/zod-v3.d.mts +6 -4
  50. package/dist/zod-v3.mjs +6 -6
  51. package/dist/zod-v4.d.mts +18 -31
  52. package/dist/zod-v4.mjs +6 -6
  53. package/dist/zod.d.mts +4 -4
  54. package/dist/zod.mjs +5 -5
  55. package/package.json +19 -15
  56. package/skills/attaform/SKILL.md +6 -3
  57. package/skills/attaform/references/custom-components.md +8 -3
  58. package/skills/attaform/references/errors.md +8 -3
  59. package/skills/attaform/references/saving.md +77 -0
  60. package/skills/attaform/references/wizards.md +10 -8
  61. package/dist/chunks/fingerprint.mjs +0 -183
  62. package/dist/chunks/fingerprint2.mjs +0 -159
  63. package/dist/dev/chunks/fingerprint.mjs +0 -183
  64. package/dist/dev/chunks/fingerprint2.mjs +0 -159
  65. package/dist/dev/shared/attaform-dev.BJGA_UOS.mjs +0 -36
  66. package/dist/shared/attaform.BJGA_UOS.mjs +0 -36
@@ -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.Dq4vWxuG.mjs';
3
- import { c as armDomBinding } from './attaform.uLbun31C.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, i as isShadowedKey, c as safeOwnHas, a as safeOwnRead, b as safeAssign, d as diffAndApply, p as pickDefined, s as structuralSnapshot, n as normalizeNumericOption, e as DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS, f as applyChangedKeys, R as RESERVED_KEY_PREFIX, g as DEFAULT_MAX_RECURSION_DEPTH, h as ANONYMOUS_WIZARD_KEY_PREFIX } from './attaform.h0i6LijT.mjs';
6
- import { i as isPathPrefix, e as canonicalizePath, h as cellEntriesFor, s as segmentsForPathKey, k as keyForSegments, b as ROOT_PATH_KEY, S as SubmitErrorHandlerError, t as toError, j as groupErrorsByKey, n as normalizeErrorInput, R as ROOT_PATH, l as normalizeErrorInputs, m as coerceToPathKey, a as InvalidUseFormConfigError, d as ReservedFormKeyError } from './attaform.wfY8XFvm.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. */
@@ -99,42 +99,32 @@ function earliestNonNull(a, b) {
99
99
  return a < b ? a : b;
100
100
  }
101
101
  const DEFAULT_TIMINGS = { showDelay: 120, minVisible: 120 };
102
+ const { showDelay, minVisible } = DEFAULT_TIMINGS;
102
103
  const FOCUS_OUT_GRACE = 16;
103
- const defaultFamily = /* @__PURE__ */ new WeakSet();
104
- function isDefaultDisplayState(fn) {
105
- return defaultFamily.has(fn);
106
- }
107
- function makeDefaultDisplayState({
108
- showDelay,
109
- minVisible
110
- }) {
111
- const reducer = (prev, { field, formMeta, validatingSince, transformingSince, now }) => {
112
- const verdict = computeVerdict(field, formMeta);
113
- if (!isGateOpen(field, formMeta)) return { display: verdict };
114
- const inFlightSince = earliestNonNull(validatingSince, transformingSince);
115
- if (inFlightSince === null) {
116
- if (prev.display === "pending") {
117
- const shownAt = prev.pendingShownAt ?? now;
118
- if (now < shownAt + minVisible)
119
- return { display: "pending", pendingShownAt: shownAt, reviewAt: shownAt + minVisible };
120
- }
121
- return { display: verdict };
122
- }
123
- if (prev.display === "pending")
124
- return { display: "pending", pendingShownAt: prev.pendingShownAt ?? now };
125
- const window = field.focused === false ? Math.min(showDelay, FOCUS_OUT_GRACE) : showDelay;
126
- if (now - inFlightSince < window) {
127
- 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
+ };
128
117
  }
129
- return { display: "pending", pendingShownAt: now, reviewAt: now + minVisible };
130
- };
131
- defaultFamily.add(reducer);
132
- return reducer;
133
- }
134
- const defaultDisplayState = makeDefaultDisplayState(DEFAULT_TIMINGS);
135
- function resolveGetDisplayState(config) {
136
- return config ?? defaultDisplayState;
137
- }
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
+ };
138
128
 
139
129
  function hashStableString(input, seed = 0) {
140
130
  let h1 = 3735928559 ^ seed;
@@ -187,6 +177,17 @@ function humanize(segment) {
187
177
  }
188
178
 
189
179
  const NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND");
180
+ function mapKeyForSegment(map, segment, declared) {
181
+ if (map.has(segment)) return segment;
182
+ if (typeof segment !== "number") return segment;
183
+ const asString = String(segment);
184
+ if (map.has(asString)) return asString;
185
+ return declared === "string" ? asString : segment;
186
+ }
187
+ function isRebuildableContainer(root, segment) {
188
+ if (root === null || root === void 0 || typeof root !== "object") return true;
189
+ return typeof segment === "number" ? Array.isArray(root) : isPlainRecord(root);
190
+ }
190
191
  function descendStep(value, segment) {
191
192
  if (value === null || value === void 0) return NOT_FOUND;
192
193
  if (typeof value !== "object") return NOT_FOUND;
@@ -195,6 +196,11 @@ function descendStep(value, segment) {
195
196
  if (!(segment in value)) return NOT_FOUND;
196
197
  return value[segment];
197
198
  }
199
+ if (value instanceof Map) {
200
+ const key2 = mapKeyForSegment(value, segment);
201
+ if (!value.has(key2)) return NOT_FOUND;
202
+ return value.get(key2);
203
+ }
198
204
  const record = value;
199
205
  const key = typeof segment === "number" ? String(segment) : segment;
200
206
  if (isShadowedKey(key)) {
@@ -206,16 +212,27 @@ function descendStep(value, segment) {
206
212
  }
207
213
  function getAtPath(root, path) {
208
214
  if (path.length === 0) return root;
209
- let current = root;
210
- for (const segment of path) {
211
- const next = descendStep(current, segment);
212
- if (next === NOT_FOUND) return void 0;
213
- 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;
214
225
  }
215
- return current;
216
226
  }
217
227
  function hasAtPath(root, path) {
218
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) {
219
236
  let current = root;
220
237
  for (let i = 0; i < path.length - 1; i++) {
221
238
  const segment = path[i];
@@ -227,11 +244,14 @@ function hasAtPath(root, path) {
227
244
  if (current === null || current === void 0) return false;
228
245
  if (typeof current !== "object") return false;
229
246
  if (Array.isArray(current)) {
230
- return typeof last === "number" && last in current;
247
+ return typeof last === "number" && consumerHas(current, last);
248
+ }
249
+ if (current instanceof Map) {
250
+ return current.has(mapKeyForSegment(current, last));
231
251
  }
232
252
  const key = typeof last === "number" ? String(last) : last;
233
253
  if (isShadowedKey(key)) return safeOwnHas(current, key);
234
- return key in current;
254
+ return consumerHas(current, key);
235
255
  }
236
256
  function isPlainRecord(value) {
237
257
  if (value === null || typeof value !== "object") return false;
@@ -239,29 +259,30 @@ function isPlainRecord(value) {
239
259
  const proto = Object.getPrototypeOf(value);
240
260
  return proto === null || proto === Object.prototype;
241
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
+ };
242
269
  function setAtPath(root, path, value) {
243
- return setAtPathOffset(root, path, value, 0);
244
- }
245
- function setAtPathOffset(root, path, value, offset) {
246
- if (offset >= path.length) return value;
247
- const head = path[offset];
248
- const nextOffset = offset + 1;
249
- if (typeof head === "number") {
250
- const arr = Array.isArray(root) ? [...root] : [];
251
- while (arr.length <= head) arr.push(void 0);
252
- arr[head] = setAtPathOffset(arr[head], path, value, nextOffset);
253
- return arr;
254
- }
255
- const rec = isPlainRecord(root) ? { ...root } : {};
256
- safeAssign(rec, head, setAtPathOffset(safeOwnRead(rec, head), path, value, nextOffset));
257
- return rec;
270
+ return setAtPathWithSchemaFill(root, NO_SCHEMA_FILL, path, value);
258
271
  }
259
272
  const NO_IN_PLACE = { applied: false };
260
273
  function tryInPlaceLeafWrite(root, path, value) {
261
274
  if (path.length === 0) return NO_IN_PLACE;
275
+ try {
276
+ return descendAndWrite(root, path, value);
277
+ } catch {
278
+ return NO_IN_PLACE;
279
+ }
280
+ }
281
+ function descendAndWrite(root, path, value) {
262
282
  let node = root;
263
283
  for (let i = 0; i < path.length; i++) {
264
284
  const seg = path[i];
285
+ if (node instanceof Map) return NO_IN_PLACE;
265
286
  if (Array.isArray(node)) {
266
287
  if (typeof seg !== "number" || seg < 0 || seg >= node.length) return NO_IN_PLACE;
267
288
  } else if (isPlainRecord(node)) {
@@ -296,17 +317,40 @@ function mergeStructuralImpl(schema, scratch, consumer, defaultValue) {
296
317
  if (Array.isArray(consumer)) {
297
318
  return mergeStructuralArray(schema, scratch, consumer);
298
319
  }
320
+ if (consumer instanceof Map) {
321
+ return mergeStructuralMap(schema, scratch, consumer);
322
+ }
299
323
  if (isPlainRecord(consumer)) {
300
324
  if (!isPlainRecord(defaultValue)) {
301
325
  return consumer;
302
326
  }
303
- const out = { ...consumer };
327
+ const out = spreadConsumerRecord(consumer);
304
328
  const filledAny = fillMissingKeysFromDefault(schema, scratch, consumer, defaultValue, out);
305
329
  const recursedAny = recurseIntoConsumerKeys(schema, scratch, consumer, defaultValue, out);
306
330
  return filledAny || recursedAny ? out : consumer;
307
331
  }
308
332
  return consumer;
309
333
  }
334
+ function mergeStructuralMap(schema, scratch, consumer) {
335
+ if (consumer.size === 0) return consumer;
336
+ let entryDefault;
337
+ let entryDefaultRead = false;
338
+ let out = null;
339
+ for (const [key, entry] of consumer) {
340
+ if (typeof key !== "string" && typeof key !== "number") continue;
341
+ scratch.push(key);
342
+ if (!entryDefaultRead) {
343
+ entryDefault = schema.getDefaultAtPath(scratch);
344
+ entryDefaultRead = true;
345
+ }
346
+ const merged = mergeStructuralImpl(schema, scratch, entry, entryDefault);
347
+ scratch.pop();
348
+ if (merged === entry) continue;
349
+ out ?? (out = new Map(consumer));
350
+ out.set(key, merged);
351
+ }
352
+ return out ?? consumer;
353
+ }
310
354
  function mergeStructuralArray(schema, scratch, consumer) {
311
355
  const shape = schema.arrayShapeAtPath(scratch);
312
356
  const isTuple = typeof shape === "number";
@@ -314,7 +358,7 @@ function mergeStructuralArray(schema, scratch, consumer) {
314
358
  let cachedElementDefault;
315
359
  let cachedElementDefaultRead = false;
316
360
  let mutated = targetLen > consumer.length;
317
- const out = consumer.slice();
361
+ const out = copyConsumerArray(consumer);
318
362
  while (out.length < targetLen) out.push(void 0);
319
363
  for (let i = 0; i < targetLen; i++) {
320
364
  scratch.push(i);
@@ -328,7 +372,7 @@ function mergeStructuralArray(schema, scratch, consumer) {
328
372
  }
329
373
  elemDefault = cachedElementDefault;
330
374
  }
331
- const consumerElem = i < consumer.length ? consumer[i] : void 0;
375
+ const consumerElem = i < consumer.length ? readConsumerIndex(consumer, i) : void 0;
332
376
  const merged = mergeStructuralImpl(schema, scratch, consumerElem, elemDefault);
333
377
  scratch.pop();
334
378
  if (merged !== consumerElem) {
@@ -356,7 +400,7 @@ function fillMissingKeysFromDefault(schema, scratch, consumer, defaultValue, out
356
400
  }
357
401
  function recurseIntoConsumerKeys(schema, scratch, consumer, defaultValue, out) {
358
402
  let mutated = false;
359
- for (const key of Object.keys(consumer)) {
403
+ for (const key of consumerKeys(consumer)) {
360
404
  const cVal = safeOwnRead(consumer, key);
361
405
  if (cVal === void 0) continue;
362
406
  scratch.push(key);
@@ -377,6 +421,21 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
377
421
  if (startIdx >= fullPath.length) return value;
378
422
  const head = fullPath[startIdx];
379
423
  const isLeafStep = startIdx === fullPath.length - 1;
424
+ if (root instanceof Map) {
425
+ const next = new Map(root);
426
+ const key = mapKeyForSegment(root, head, schema.entryKeyKindAtPath(fullPath.slice(0, startIdx)));
427
+ if (isLeafStep) {
428
+ next.set(key, value);
429
+ return next;
430
+ }
431
+ let childRoot2 = next.get(key);
432
+ if (childRoot2 === void 0 || childRoot2 !== null && typeof childRoot2 !== "object") {
433
+ childRoot2 = schema.getDefaultAtPath(fullPath.slice(0, startIdx + 1));
434
+ }
435
+ next.set(key, setAtPathWithSchemaFillImpl(childRoot2, schema, fullPath, value, startIdx + 1));
436
+ return next;
437
+ }
438
+ if (!isRebuildableContainer(root, head)) return root;
380
439
  if (typeof head === "number") {
381
440
  const arr = Array.isArray(root) ? [...root] : [];
382
441
  const prefix = fullPath.slice(0, startIdx);
@@ -414,10 +473,10 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
414
473
  }
415
474
  const rec = isPlainRecord(root) ? { ...root } : {};
416
475
  if (isLeafStep) {
417
- rec[head] = value;
476
+ safeAssign(rec, head, value);
418
477
  return rec;
419
478
  }
420
- const existing = rec[head];
479
+ const existing = safeOwnRead(rec, head);
421
480
  let childRoot;
422
481
  if (existing === void 0 || existing !== null && typeof existing !== "object") {
423
482
  const intermPath = [...fullPath.slice(0, startIdx + 1)];
@@ -426,7 +485,11 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
426
485
  } else {
427
486
  childRoot = existing;
428
487
  }
429
- rec[head] = setAtPathWithSchemaFillImpl(childRoot, schema, fullPath, value, startIdx + 1);
488
+ safeAssign(
489
+ rec,
490
+ head,
491
+ setAtPathWithSchemaFillImpl(childRoot, schema, fullPath, value, startIdx + 1)
492
+ );
430
493
  return rec;
431
494
  }
432
495
 
@@ -443,17 +506,18 @@ function isUnderStubAncestor(state, segments) {
443
506
  }
444
507
  return false;
445
508
  }
446
- function buildFieldStateAccessor(state, formInstanceId, getFormMetaBase, options) {
509
+ function buildFieldStateAccessor(state, formInstanceId, getFormMetaBase, sweep) {
447
510
  const cache = /* @__PURE__ */ new Map();
448
- const predicate = options?.getDisplayState;
511
+ sweep.onEvict((key) => cache.delete(key));
449
512
  return function getFieldState(pathInput) {
450
513
  const { segments, key } = canonicalizePath(pathInput);
451
514
  const cached = cache.get(key);
452
515
  if (cached !== void 0) return cached;
453
516
  const c = computed(
454
- () => 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)
455
518
  );
456
519
  cache.set(key, c);
520
+ sweep.track(segments, key);
457
521
  return c;
458
522
  };
459
523
  }
@@ -467,7 +531,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
467
531
  const record = state.fields.get(key);
468
532
  const value = state.getValueAtPath(segments);
469
533
  const original = state.originals.get(key)?.value;
470
- const pristine = state.isPristineAtPath(segments);
534
+ const pristine = state.isPristineAtPathByKey(key, segments);
471
535
  const cell = state.errorCells.get(key);
472
536
  const schemaForKey = cell !== void 0 && cell.schema.length > 0 ? cell.schema : void 0;
473
537
  const blankForKey = state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments) ? [makeBlankRequiredError(segments)] : void 0;
@@ -479,7 +543,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
479
543
  const validating = (state.fieldValidationCounts.get(key) ?? 0) > 0;
480
544
  const transforming = (state.fieldTransformCounts.get(key) ?? 0) > 0;
481
545
  const transformError = state.transformErrors.get(key) ?? null;
482
- const gated = state.pathHasAsyncValidation(segments) && !state.firstValidationDone.value;
546
+ const gated = state.pathHasAsyncValidationByKey(key, segments) && !state.firstValidationDone.value;
483
547
  const isOrphan = segments.length > 0 && !hasAtPath(state.form.value, segments) && isUnderStubAncestor(state, segments);
484
548
  const valid = !gated && errors.length === 0 && !validating && !isOrphan;
485
549
  const elementRecord = state.domBinding.value?.elements.get(key);
@@ -522,7 +586,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
522
586
  meta: resolved.meta
523
587
  };
524
588
  }
525
- function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase, getDisplayState) {
589
+ function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase) {
526
590
  const base = buildLeafFieldStateBase(state, segments, key, formInstanceId);
527
591
  const validatingSince = state.fieldValidatingSince.get(key) ?? null;
528
592
  const transformingSince = state.fieldTransformingSince.get(key) ?? null;
@@ -535,15 +599,14 @@ function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBa
535
599
  transformingSince,
536
600
  false,
537
601
  // revealedDescendantError: leaves have no descendants
538
- false,
602
+ false
539
603
  // isRoot: a leaf is never the form root
540
- getDisplayState
541
604
  );
542
605
  }
543
606
  function visitActiveLeafPaths(value, base, visit) {
544
607
  if (Array.isArray(value)) {
545
608
  for (let i = 0; i < value.length; i++) {
546
- const child = value[i];
609
+ const child = readConsumerIndex(value, i);
547
610
  if (Array.isArray(child) || isPlainRecord(child)) {
548
611
  visitActiveLeafPaths(child, [...base, i], visit);
549
612
  } else {
@@ -553,8 +616,8 @@ function visitActiveLeafPaths(value, base, visit) {
553
616
  return;
554
617
  }
555
618
  if (isPlainRecord(value)) {
556
- for (const k of Object.keys(value)) {
557
- const child = value[k];
619
+ for (const k of consumerKeys(value)) {
620
+ const child = readConsumerProp(value, k);
558
621
  if (Array.isArray(child) || isPlainRecord(child)) {
559
622
  visitActiveLeafPaths(child, [...base, k], visit);
560
623
  } else {
@@ -635,7 +698,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
635
698
  pristine = false;
636
699
  dirty = true;
637
700
  }
638
- const errors = aggregateErrorsAt(state, segments);
701
+ const errors = aggregateErrorsAt(state, segments, key);
639
702
  const revealedDescendantError = errors.length > 0 && errors.some((e) => {
640
703
  const ePath = e.path;
641
704
  if (ePath.length === segments.length && ePath.every((s, i) => s === segments[i])) return false;
@@ -643,7 +706,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
643
706
  if (ePath.length === 1 && ePath[0] === "") return blurredAfterInteraction;
644
707
  return blurredLeafSegments.some((s) => isPathPrefix(ePath, s));
645
708
  });
646
- if (!asyncPending && state.pathHasAsyncValidation(segments)) asyncPending = true;
709
+ if (!asyncPending && state.pathHasAsyncValidationByKey(key, segments)) asyncPending = true;
647
710
  if ((state.fieldValidationCounts.get(key) ?? 0) > 0) {
648
711
  validating = true;
649
712
  const since = state.fieldValidatingSince.get(key);
@@ -714,7 +777,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
714
777
  revealedDescendantError
715
778
  };
716
779
  }
717
- function buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase, getDisplayState) {
780
+ function buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase) {
718
781
  const { base, validatingSince, transformingSince, revealedDescendantError } = buildContainerFieldStateBase(state, segments, key, formInstanceId);
719
782
  return decorateWithDerivedProps(
720
783
  base,
@@ -724,14 +787,12 @@ function buildContainerFieldState(state, segments, key, formInstanceId, getFormM
724
787
  validatingSince,
725
788
  transformingSince,
726
789
  revealedDescendantError,
727
- segments.length === 0,
728
- getDisplayState
790
+ segments.length === 0
729
791
  );
730
792
  }
731
- function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, transformingSince, revealedDescendantError, isRoot, getDisplayState) {
793
+ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, transformingSince, revealedDescendantError, isRoot) {
732
794
  const firstError = base.errors[0];
733
795
  const firstOwnError = base.ownErrors[0];
734
- const predicate = getDisplayState ?? state.getDisplayState;
735
796
  const formMeta = getFormMetaBase();
736
797
  const ctx = {
737
798
  field: base,
@@ -742,16 +803,9 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
742
803
  // flight) so the reducer returns the plain verdict and hydration matches.
743
804
  now: state.ssr ? 0 : Date.now()
744
805
  };
745
- let machine;
746
- let rollupApplies = isDefaultDisplayState(predicate);
747
- try {
748
- machine = state.displayEngine.resolve(key, ctx, predicate);
749
- } catch (err) {
750
- machine = state.displayEngine.resolve(key, ctx, defaultDisplayState);
751
- rollupApplies = true;
752
- }
753
- const submitValidating = rollupApplies && isRoot && state.submitting.value && state.activeValidations.value > 0;
754
- 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;
755
809
  const displayState = base.disabled === true ? "idle" : resolvedDisplayState;
756
810
  return {
757
811
  ...base,
@@ -764,26 +818,33 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
764
818
  firstOwnError
765
819
  };
766
820
  }
767
- function aggregateErrorsAt(state, prefix) {
821
+ function aggregateErrorsAt(state, prefix, prefixKey) {
822
+ const candidates = state.errorWindowAt(prefix, prefixKey);
823
+ if (candidates.length === 0) return [];
768
824
  const formValue = state.form.value;
825
+ const cells = state.errorCells;
769
826
  const buckets = /* @__PURE__ */ new Map();
770
- const collect = (errs) => {
771
- for (const [pathKey, list] of errs) {
772
- if (list.length === 0) continue;
773
- const segs = segmentsForPathKey(pathKey);
774
- if (segs === null) continue;
775
- if (!isPathPrefix(prefix, segs)) continue;
776
- if (segs.length > 0 && !hasAtPath(formValue, segs)) continue;
777
- const ordinal = state.ensurePathOrdinal(pathKey);
778
- const existing = buckets.get(ordinal);
779
- if (existing === void 0) buckets.set(ordinal, [...list]);
780
- else existing.push(...list);
781
- }
782
- };
783
- collect(cellEntriesFor(state.errorCells, "schema"));
784
- collect(state.derivedBlankErrors.value);
785
- 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
+ }
786
846
  if (buckets.size === 0) return [];
847
+ if (buckets.size === 1) return [...buckets.values()][0];
787
848
  return [...buckets.entries()].sort(([a], [b]) => a - b).flatMap(([, errs]) => errs);
788
849
  }
789
850
  const EMPTY_ELEMENTS = Object.freeze([]);
@@ -796,6 +857,10 @@ function liveKeysAtPath(state, segments) {
796
857
  for (let i = 0; i < value.length; i += 1) keys[i] = String(i);
797
858
  return keys;
798
859
  }
860
+ if (value instanceof Map) {
861
+ return mapSegmentKeys(value)?.map(String) ?? [];
862
+ }
863
+ if (value instanceof Set) return [];
799
864
  if (typeof value === "object") return Object.keys(value);
800
865
  return [];
801
866
  }
@@ -806,6 +871,12 @@ function liveContainerHasKey(state, segments, key) {
806
871
  const index = Number(key);
807
872
  return Number.isInteger(index) && index >= 0 && index < value.length && String(index) === key;
808
873
  }
874
+ if (value instanceof Map) {
875
+ if (value.has(key)) return true;
876
+ const index = Number(key);
877
+ return Number.isInteger(index) && index >= 0 && String(index) === key && value.has(index);
878
+ }
879
+ if (value instanceof Set) return false;
809
880
  return Object.hasOwn(value, key);
810
881
  }
811
882
  function isArrayPath(state, segments) {
@@ -829,6 +900,7 @@ function makeReadonlyCoercion(snapshot) {
829
900
  }
830
901
 
831
902
  const INTEGER_SEGMENT = /^(?:0|[1-9]\d*)$/;
903
+ const RELEASED = /* @__PURE__ */ Symbol();
832
904
  const EMPTY_DESCENT = Object.freeze({});
833
905
  function keyToSegment(key) {
834
906
  return INTEGER_SEGMENT.test(key) ? Number(key) : key;
@@ -858,12 +930,18 @@ function callableInvokeShim(method, surface, getDescent) {
858
930
  function buildTree(spec) {
859
931
  const containerCache = /* @__PURE__ */ new Map();
860
932
  const existsCache = /* @__PURE__ */ new Map();
933
+ spec.sweep.onEvict((key) => {
934
+ containerCache.delete(`${key}+A`);
935
+ containerCache.delete(`${key}+O`);
936
+ existsCache.delete(key);
937
+ });
861
938
  function schemaHasPath(segs) {
862
- const cacheKey = JSON.stringify(segs);
939
+ const cacheKey = keyForSegments(segs).key;
863
940
  const cached = existsCache.get(cacheKey);
864
941
  if (cached !== void 0) return cached;
865
942
  const result = spec.schema.getSlimPrimitiveTypesAtPath(segs).size > 0;
866
943
  existsCache.set(cacheKey, result);
944
+ spec.sweep.track(segs, cacheKey);
867
945
  return result;
868
946
  }
869
947
  function descend(segs) {
@@ -873,7 +951,8 @@ function buildTree(spec) {
873
951
  }
874
952
  function containerAt(segments) {
875
953
  const isArrayLike = spec.isArrayAt(segments);
876
- const cacheKey = `${JSON.stringify(segments)}+${isArrayLike ? "A" : "O"}`;
954
+ const pathKey = keyForSegments(segments).key;
955
+ const cacheKey = `${pathKey}+${isArrayLike ? "A" : "O"}`;
877
956
  const existing = containerCache.get(cacheKey);
878
957
  if (existing !== void 0) return existing;
879
958
  const isFixedObject = spec.schema.isFixedObjectAtPath(segments);
@@ -963,46 +1042,42 @@ function buildTree(spec) {
963
1042
  }
964
1043
  });
965
1044
  containerCache.set(cacheKey, proxy);
1045
+ spec.sweep.track(segments, pathKey);
966
1046
  return proxy;
967
1047
  }
968
1048
  return containerAt([]);
969
1049
  }
970
- function buildErrorsSurface(state) {
1050
+ function buildErrorsSurface(state, sweep) {
971
1051
  const treeCache = /* @__PURE__ */ new Map();
1052
+ sweep.onEvict((key) => treeCache.delete(key));
972
1053
  const materialize = (segments) => {
973
- const cacheKey = JSON.stringify(segments);
1054
+ const cacheKey = keyForSegments(segments).key;
974
1055
  let tree = treeCache.get(cacheKey);
975
1056
  if (tree === void 0) {
976
1057
  const frozen = [...segments];
977
1058
  tree = computed(() => materializeErrors(state, frozen));
978
1059
  treeCache.set(cacheKey, tree);
1060
+ sweep.track(segments, cacheKey);
979
1061
  }
980
1062
  return tree.value;
981
1063
  };
982
1064
  const resolveLeaf = (path) => {
983
1065
  const isContainerSelfAccess = path.length > 1 && path[path.length - 1] === "";
984
- const collectAtKey = (key2, active2, into) => {
985
- const cell = state.errorCells.get(key2);
986
- if (active2) {
987
- const b = state.derivedBlankErrors.value.get(key2);
988
- if (cell !== void 0) into.push(...cell.schema);
989
- if (b !== void 0) into.push(...b);
990
- }
991
- if (cell !== void 0) into.push(...cell.user);
992
- };
993
1066
  const merged = [];
994
1067
  if (isContainerSelfAccess) {
995
1068
  const containerPath = path.slice(0, -1);
996
- const containerKey = canonicalizePath(containerPath).key;
997
- const literalKey = canonicalizePath(path).key;
1069
+ const container = canonicalizePath(containerPath);
1070
+ const literal = canonicalizePath(path);
998
1071
  const active2 = hasAtPath(state.form.value, containerPath);
999
- collectAtKey(containerKey, active2, merged);
1000
- 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
+ }
1001
1076
  return merged;
1002
1077
  }
1003
- const { key } = canonicalizePath(path);
1078
+ const { key, segments } = canonicalizePath(path);
1004
1079
  const active = hasAtPath(state.form.value, path);
1005
- collectAtKey(key, active, merged);
1080
+ collectErrorsAt(state, key, segments, active, merged);
1006
1081
  return merged;
1007
1082
  };
1008
1083
  return buildTree({
@@ -1020,64 +1095,80 @@ function buildErrorsSurface(state) {
1020
1095
  // `errors()` / `errors([])` / `errors(path)` are all the subtree
1021
1096
  // aggregate — the same helper `meta.errors` reads, so the surfaces
1022
1097
  // never drift.
1023
- call: (path) => aggregateErrorsAt(state, path),
1024
- surface: "form.errors"
1098
+ call: (path) => aggregateErrorsAt(state, path, keyForSegments(path).key),
1099
+ surface: "form.errors",
1100
+ sweep
1025
1101
  });
1026
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
+ }
1027
1113
  function errorAwareContainerKeys(state, segments) {
1028
1114
  const keys = new Set(liveKeysAtPath(state, segments));
1029
1115
  const formValue = state.form.value;
1030
- const walk = (store, applyActivePathFilter) => {
1031
- for (const [pathKey, errors] of store) {
1032
- if (errors.length === 0) continue;
1033
- const decoded = segmentsForPathKey(pathKey);
1034
- if (decoded === null) continue;
1035
- if (decoded.length <= segments.length) continue;
1036
- if (!isPathPrefix(segments, decoded)) continue;
1037
- if (applyActivePathFilter && !hasAtPath(formValue, decoded)) continue;
1038
- const nextSeg = decoded[segments.length];
1039
- keys.add(typeof nextSeg === "number" ? String(nextSeg) : nextSeg);
1040
- }
1041
- };
1042
- walk(cellEntriesFor(state.errorCells, "schema"), true);
1043
- walk(state.derivedBlankErrors.value, true);
1044
- 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);
1045
1135
  return [...keys];
1046
1136
  }
1047
1137
  function materializeErrors(state, containerSegments) {
1048
- const liveContainer = getAtPath(state.form.value, containerSegments);
1138
+ const formValue = state.form.value;
1139
+ const liveContainer = getAtPath(formValue, containerSegments);
1049
1140
  const tree = Array.isArray(liveContainer) ? [] : {};
1050
- const collect = (store, applyActivePathFilter) => {
1051
- entries: for (const [pathKey, errors] of store) {
1052
- if (errors.length === 0) continue;
1053
- const fullPath = segmentsForPathKey(pathKey);
1054
- if (fullPath === null) continue;
1055
- if (fullPath.length === 0) {
1056
- if (containerSegments.length === 0) placeAt(tree, [ROOT_PATH_KEY], errors);
1057
- continue;
1058
- }
1059
- if (fullPath.length < containerSegments.length) continue;
1060
- for (let i = 0; i < containerSegments.length; i++) {
1061
- if (fullPath[i] !== containerSegments[i]) continue entries;
1062
- }
1063
- if (applyActivePathFilter && !hasAtPath(state.form.value, fullPath)) continue;
1064
- const relativePath = fullPath.slice(containerSegments.length);
1065
- let placePath;
1066
- if (relativePath.length === 0) {
1067
- placePath = [""];
1068
- } else if (state.schema.isLeafAtPath(fullPath)) {
1069
- placePath = relativePath;
1070
- } else if (state.schema.getSlimPrimitiveTypesAtPath(fullPath).size > 0) {
1071
- placePath = [...relativePath, ""];
1072
- } else {
1073
- placePath = relativePath;
1074
- }
1075
- 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;
1076
1151
  }
1077
- };
1078
- collect(cellEntriesFor(state.errorCells, "schema"), true);
1079
- collect(state.derivedBlankErrors.value, true);
1080
- 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);
1081
1172
  return tree;
1082
1173
  }
1083
1174
  function placeAt(tree, path, errors) {
@@ -1140,7 +1231,7 @@ const FIELD_STATE_KEYS = /* @__PURE__ */ new Set([
1140
1231
  "placeholder",
1141
1232
  "meta"
1142
1233
  ]);
1143
- function buildFieldsSurface(state, getFieldStateAt) {
1234
+ function buildFieldsSurface(state, getFieldStateAt, sweep) {
1144
1235
  const snapshotAt = (segments) => {
1145
1236
  const view = getFieldStateAt(segments).value;
1146
1237
  const snapshot = {};
@@ -1148,8 +1239,9 @@ function buildFieldsSurface(state, getFieldStateAt) {
1148
1239
  return snapshot;
1149
1240
  };
1150
1241
  const viewCache = /* @__PURE__ */ new Map();
1242
+ sweep.onEvict((key) => viewCache.delete(key));
1151
1243
  function viewAt(segments) {
1152
- const cacheKey = JSON.stringify(segments);
1244
+ const cacheKey = keyForSegments(segments).key;
1153
1245
  const existing = viewCache.get(cacheKey);
1154
1246
  if (existing !== void 0) return existing;
1155
1247
  const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(
@@ -1199,6 +1291,7 @@ function buildFieldsSurface(state, getFieldStateAt) {
1199
1291
  }
1200
1292
  });
1201
1293
  viewCache.set(cacheKey, proxy);
1294
+ sweep.track(segments, cacheKey);
1202
1295
  return proxy;
1203
1296
  }
1204
1297
  return buildTree({
@@ -1213,7 +1306,8 @@ function buildFieldsSurface(state, getFieldStateAt) {
1213
1306
  // container's rollup); a path the schema doesn't have is a typo and
1214
1307
  // reads `undefined`. The root (`fields()`) is always declared.
1215
1308
  call: (path) => state.schema.getSlimPrimitiveTypesAtPath(path).size > 0 ? viewAt(path) : void 0,
1216
- surface: "form.fields"
1309
+ surface: "form.fields",
1310
+ sweep
1217
1311
  });
1218
1312
  }
1219
1313
  function materializeFields(state, containerSegments, snapshotAt) {
@@ -1247,18 +1341,34 @@ function materializeFormValue(node) {
1247
1341
  }
1248
1342
  return out;
1249
1343
  }
1250
- function buildValuesSurface(form) {
1344
+ function buildValuesSurface(form, onFormChange) {
1251
1345
  const inner = computed(() => readonly(form.value));
1252
- const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(
1253
- () => materializeFormValue(inner.value)
1254
- );
1346
+ let held = null;
1347
+ const snapshot = computed(() => {
1348
+ const box = { value: materializeFormValue(inner.value) };
1349
+ held = box;
1350
+ return box;
1351
+ });
1352
+ onFormChange(() => {
1353
+ if (held === null) return;
1354
+ held.value = RELEASED;
1355
+ held = null;
1356
+ });
1357
+ const readSnapshot = () => {
1358
+ const box = snapshot.value;
1359
+ return box.value === RELEASED ? materializeFormValue(inner.value) : box.value;
1360
+ };
1361
+ const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(() => readSnapshot());
1255
1362
  const target = (() => {
1256
1363
  });
1257
1364
  return new Proxy(target, {
1258
1365
  apply(_, __, args) {
1259
1366
  const arg = args[0];
1260
- if (arg === void 0) return inner.value;
1261
- return getAtPath(inner.value, canonicalizePath(arg).segments);
1367
+ if (arg === void 0) return readSnapshot();
1368
+ const segments = canonicalizePath(arg).segments;
1369
+ const node = getAtPath(inner.value, segments);
1370
+ if (node === null || typeof node !== "object") return node;
1371
+ return getAtPath(readSnapshot(), segments);
1262
1372
  },
1263
1373
  get(_, key) {
1264
1374
  if (typeof key === "symbol") {
@@ -1540,9 +1650,12 @@ function cloneVariantSnapshot(value) {
1540
1650
  for (let i = 0; i < raw.length; i++) out2[i] = cloneVariantSnapshot(raw[i]);
1541
1651
  return out2;
1542
1652
  }
1653
+ if (!isPlainRecord(raw)) return raw;
1543
1654
  const src = raw;
1544
1655
  const out = {};
1545
- for (const k of Object.keys(src)) safeAssign(out, k, cloneVariantSnapshot(src[k]));
1656
+ for (const k of consumerKeys(src)) {
1657
+ safeAssign(out, k, cloneVariantSnapshot(readConsumerProp(src, k)));
1658
+ }
1546
1659
  return out;
1547
1660
  }
1548
1661
  function createArrayBookkeeping(deps) {
@@ -1716,8 +1829,8 @@ function deriveSubmitErrors(err) {
1716
1829
  messageless: true
1717
1830
  };
1718
1831
  }
1719
- function buildProcessForm(state, formInstanceId, options = {}) {
1720
- const invalidPolicy = options.onInvalidSubmit ?? "focus-first-error";
1832
+ function buildProcessForm(state, options = {}) {
1833
+ const applyInvalidSubmit = options.applyInvalidSubmit;
1721
1834
  function validate(pathInput) {
1722
1835
  const result = ref({
1723
1836
  pending: true,
@@ -1810,7 +1923,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
1810
1923
  };
1811
1924
  }
1812
1925
  async function runRefinementValidation(data, path) {
1813
- return await state.schema.validateAtPath(data, path);
1926
+ return stampFormKey(await state.schema.validateAtPath(data, path), state.formKey);
1814
1927
  }
1815
1928
  function composeWithDerivedBlank(refinement, scope) {
1816
1929
  const blankErrors = collectScopedBlankErrors(state, scope);
@@ -1856,7 +1969,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
1856
1969
  }
1857
1970
  }
1858
1971
  if (generationStillValid) {
1859
- applyInvalidSubmitPolicy(state, formInstanceId, invalidPolicy);
1972
+ applyInvalidSubmit?.();
1860
1973
  }
1861
1974
  if (onError !== void 0) {
1862
1975
  try {
@@ -1873,7 +1986,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
1873
1986
  await onSubmit(merged.data);
1874
1987
  if (hasUserErrorEntries(state)) {
1875
1988
  if (state.submissionGeneration.value === genAtEntry) {
1876
- applyInvalidSubmitPolicy(state, formInstanceId, invalidPolicy);
1989
+ applyInvalidSubmit?.();
1877
1990
  }
1878
1991
  return;
1879
1992
  }
@@ -1891,7 +2004,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
1891
2004
  if (segments === null) continue;
1892
2005
  state.setUserErrorsForPath([...segments], bucket);
1893
2006
  }
1894
- applyInvalidSubmitPolicy(state, formInstanceId, invalidPolicy);
2007
+ applyInvalidSubmit?.();
1895
2008
  }
1896
2009
  }
1897
2010
  } finally {
@@ -1906,6 +2019,10 @@ function buildProcessForm(state, formInstanceId, options = {}) {
1906
2019
  };
1907
2020
  return { validate, parse, handleSubmit };
1908
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
+ }
1909
2026
  function toSegments(pathInput) {
1910
2027
  return canonicalizePath(pathInput).segments;
1911
2028
  }
@@ -1939,21 +2056,6 @@ function collectScopedBlankErrors(state, scope) {
1939
2056
  }
1940
2057
  return errors;
1941
2058
  }
1942
- function applyInvalidSubmitPolicy(state, formInstanceId, policy) {
1943
- if (policy === "none") return;
1944
- const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
1945
- if (target === null) return;
1946
- if (policy === "scroll-to-first-error") {
1947
- target.element.scrollIntoView();
1948
- return;
1949
- }
1950
- if (policy === "focus-first-error") {
1951
- target.element.focus({ focusVisible: true });
1952
- return;
1953
- }
1954
- target.element.scrollIntoView();
1955
- target.element.focus({ preventScroll: true, focusVisible: true });
1956
- }
1957
2059
 
1958
2060
  function slimKindOf(value) {
1959
2061
  if (value === null) return "null";
@@ -1999,15 +2101,16 @@ function walk(schema, store, path, value) {
1999
2101
  if (!accepted.has(kind)) {
2000
2102
  return false;
2001
2103
  }
2104
+ if (schema.isOpaqueLeafAtPath(path)) return true;
2002
2105
  if (Array.isArray(value)) {
2003
2106
  for (let i = 0; i < value.length; i++) {
2004
- if (!walk(schema, store, [...path, i], value[i])) return false;
2107
+ if (!walk(schema, store, [...path, i], readConsumerIndex(value, i))) return false;
2005
2108
  }
2006
2109
  return true;
2007
2110
  }
2008
2111
  if (isPlainRecord(value)) {
2009
- for (const key of Object.keys(value)) {
2010
- if (!walk(schema, store, [...path, key], value[key])) {
2112
+ for (const key of consumerKeys(value)) {
2113
+ if (!walk(schema, store, [...path, key], readConsumerProp(value, key))) {
2011
2114
  return false;
2012
2115
  }
2013
2116
  }
@@ -2016,135 +2119,94 @@ function walk(schema, store, path, value) {
2016
2119
  return true;
2017
2120
  }
2018
2121
 
2019
- function defineCoercion(entry) {
2020
- return entry;
2021
- }
2022
2122
  const IDENTITY = (v) => v;
2023
- const EMPTY_INDEX = /* @__PURE__ */ new Map();
2024
- const defaultCoercionRules = [
2025
- defineCoercion({
2026
- input: "string",
2027
- output: "number",
2028
- transform: (s) => {
2029
- const trimmed = s.trim();
2030
- if (trimmed === "") return { coerced: false };
2031
- const n = Number(trimmed);
2032
- if (!Number.isFinite(n)) return { coerced: false };
2033
- return { coerced: true, value: n };
2034
- }
2035
- }),
2036
- defineCoercion({
2037
- input: "string",
2038
- output: "boolean",
2039
- transform: (s) => {
2040
- const normalized = s.trim().toLowerCase();
2041
- if (normalized === "true") return { coerced: true, value: true };
2042
- if (normalized === "false") return { coerced: true, value: false };
2043
- return { coerced: false };
2044
- }
2045
- })
2046
- ];
2047
- function resolveCoercionIndex(config) {
2048
- if (config === false) return EMPTY_INDEX;
2049
- const rules = config === void 0 || config === true ? defaultCoercionRules : config;
2050
- return indexRules(rules);
2051
- }
2052
- function indexRules(rules) {
2053
- const idx = /* @__PURE__ */ new Map();
2054
- for (const entry of rules) {
2055
- const candidate = entry;
2056
- if (candidate === null || typeof candidate !== "object" || typeof candidate.transform !== "function") {
2057
- continue;
2058
- }
2059
- const key = `${entry.input}->${entry.output}`;
2060
- if (idx.has(key) && false) ;
2061
- idx.set(key, entry);
2123
+ function resolveCoerceEnabled(config) {
2124
+ return config !== false;
2125
+ }
2126
+ function memberSlimTypes(schema, segments, accepted) {
2127
+ if (accepted.has("array")) return schema.getSlimPrimitiveTypesAtPath([...segments, 0]);
2128
+ if (accepted.has("set")) {
2129
+ return schema.getSlimPrimitiveTypesAtPath([...segments, SET_MEMBER_SEGMENT]);
2062
2130
  }
2063
- return idx;
2131
+ return void 0;
2064
2132
  }
2065
- function buildCoerceFn(schema, segments, index) {
2066
- if (index === EMPTY_INDEX) return IDENTITY;
2067
- if (index.size === 0) return IDENTITY;
2133
+ function buildCoerceFn(schema, segments, enabled) {
2134
+ if (!enabled) return IDENTITY;
2068
2135
  const accepted = schema.getSlimPrimitiveTypesAtPath(segments);
2069
- const elementAccepted = accepted.has("array") || accepted.has("set") ? schema.getSlimPrimitiveTypesAtPath([...segments, 0]) : void 0;
2070
- return (value) => coerceValue(value, accepted, elementAccepted, index);
2136
+ const elementAccepted = memberSlimTypes(schema, segments, accepted);
2137
+ return (value) => coerceValue(value, accepted, elementAccepted);
2071
2138
  }
2072
- function buildElementCoerceFn(schema, segments, index) {
2073
- if (index === EMPTY_INDEX) return void 0;
2074
- if (index.size === 0) return void 0;
2139
+ function buildElementCoerceFn(schema, segments, enabled) {
2140
+ if (!enabled) return void 0;
2075
2141
  const accepted = schema.getSlimPrimitiveTypesAtPath(segments);
2076
- if (!accepted.has("array") && !accepted.has("set")) return void 0;
2077
- const elementAccepted = schema.getSlimPrimitiveTypesAtPath([...segments, 0]);
2078
- return (value) => coerceScalar(value, elementAccepted, index);
2142
+ const elementAccepted = memberSlimTypes(schema, segments, accepted);
2143
+ if (elementAccepted === void 0) return void 0;
2144
+ return (value) => coerceScalar(value, elementAccepted);
2079
2145
  }
2080
2146
  function pickScalarTarget(accepted) {
2081
2147
  if (accepted.has("string")) return null;
2082
2148
  if (accepted.has("number")) return "number";
2083
2149
  if (accepted.has("boolean")) return "boolean";
2084
- if (accepted.has("bigint")) return "bigint";
2085
2150
  return null;
2086
2151
  }
2087
- 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) {
2088
2165
  if (accepted.size === 0) return value;
2089
2166
  const sourceKind = slimKindOf(value);
2090
2167
  if (accepted.has(sourceKind)) return value;
2168
+ if (sourceKind !== "string") return value;
2091
2169
  const target = pickScalarTarget(accepted);
2092
- if (target === null) return value;
2093
- const entry = index.get(`${sourceKind}->${target}`);
2094
- if (entry === void 0) return value;
2095
- let result;
2096
- try {
2097
- result = entry.transform(value);
2098
- } catch (err) {
2099
- return value;
2100
- }
2101
- if (!result.coerced) return value;
2102
- const returnedKind = slimKindOf(result.value);
2103
- if (returnedKind !== entry.output) {
2104
- return value;
2105
- }
2106
- if (entry.output === "number" && !Number.isFinite(result.value)) {
2107
- return value;
2108
- }
2109
- return result.value;
2170
+ if (target === "number") return toNumber(value);
2171
+ if (target === "boolean") return toBoolean(value);
2172
+ return value;
2110
2173
  }
2111
- function coerceArrayMembers(arr, elementAccepted, index) {
2174
+ function coerceArrayMembers(arr, elementAccepted) {
2112
2175
  let changed = false;
2113
2176
  const out = [];
2114
2177
  for (const el of arr) {
2115
- const next = coerceScalar(el, elementAccepted, index);
2178
+ const next = coerceScalar(el, elementAccepted);
2116
2179
  if (next !== el) changed = true;
2117
2180
  out.push(next);
2118
2181
  }
2119
2182
  return changed ? out : arr;
2120
2183
  }
2121
- function coerceSetMembers(set, elementAccepted, index) {
2184
+ function coerceSetMembers(set, elementAccepted) {
2122
2185
  let changed = false;
2123
2186
  const out = [];
2124
2187
  for (const el of set) {
2125
- const next = coerceScalar(el, elementAccepted, index);
2188
+ const next = coerceScalar(el, elementAccepted);
2126
2189
  if (next !== el) changed = true;
2127
2190
  out.push(next);
2128
2191
  }
2129
2192
  return changed ? new Set(out) : set;
2130
2193
  }
2131
- function coerceValue(value, accepted, elementAccepted, index) {
2194
+ function coerceValue(value, accepted, elementAccepted) {
2132
2195
  if (Array.isArray(value)) {
2133
2196
  if (!accepted.has("array") || elementAccepted === void 0) return value;
2134
- return coerceArrayMembers(value, elementAccepted, index);
2197
+ return coerceArrayMembers(value, elementAccepted);
2135
2198
  }
2136
2199
  if (value instanceof Set) {
2137
2200
  if (!accepted.has("set") || elementAccepted === void 0) return value;
2138
- return coerceSetMembers(value, elementAccepted, index);
2201
+ return coerceSetMembers(value, elementAccepted);
2139
2202
  }
2140
- return coerceScalar(value, accepted, index);
2203
+ return coerceScalar(value, accepted);
2141
2204
  }
2142
2205
 
2143
2206
  const EMPTY_TRANSFORMS = Object.freeze([]);
2144
2207
  function buildRegister(state, formInstanceId, instanceConfig) {
2145
- const coerceIndex = instanceConfig?.coerce !== void 0 ? resolveCoercionIndex(instanceConfig.coerce) : state.coerceIndex;
2208
+ const coerceEnabled = instanceConfig?.coerce !== void 0 ? resolveCoerceEnabled(instanceConfig.coerce) : state.coerceEnabled;
2146
2209
  const instanceMeta = instanceConfig?.instanceMeta;
2147
- const formAutoAria = instanceConfig?.autoAria ?? true;
2148
2210
  const getDisplayStateAt = instanceConfig?.getDisplayStateAt;
2149
2211
  const withInstanceMeta = (meta) => {
2150
2212
  if (instanceMeta === void 0) return meta;
@@ -2184,16 +2246,15 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2184
2246
  const coerce = buildCoerceFn(
2185
2247
  state.schema,
2186
2248
  segments,
2187
- coerceIndex
2249
+ coerceEnabled
2188
2250
  );
2189
2251
  const coerceElement = buildElementCoerceFn(
2190
2252
  state.schema,
2191
2253
  segments,
2192
- coerceIndex
2254
+ coerceEnabled
2193
2255
  );
2194
2256
  const { aria } = computeFieldIdentity(formInstanceId, state.formKey, pathKey);
2195
2257
  const isRequired = state.schema.isRequiredAtPath(segments);
2196
- const ariaEnabled = options?.autoAria ?? formAutoAria;
2197
2258
  const ariaDisplayState = getDisplayStateAt !== void 0 ? computed(() => getDisplayStateAt(segments)) : void 0;
2198
2259
  const markBlank = () => state.setValueAtPath(segments, slimDefault, withInstanceMeta({ blank: true }));
2199
2260
  const internalRv = {
@@ -2295,7 +2356,6 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2295
2356
  // --- Aria (internal; consumed by the directive) ---
2296
2357
  aria,
2297
2358
  isRequired,
2298
- ariaEnabled,
2299
2359
  ...ariaDisplayState !== void 0 ? { ariaDisplayState } : {}
2300
2360
  };
2301
2361
  return shallowReadonly(internalRv);
@@ -2317,8 +2377,8 @@ function walkUnsetSentinels(values, schema) {
2317
2377
  const cleaned = walkCore(values, [], schema, paths, true);
2318
2378
  return { cleanedValues: cleaned, paths };
2319
2379
  }
2320
- function isOpaqueLeaf(value) {
2321
- return value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || typeof value === "function";
2380
+ function isRecursable(value) {
2381
+ return Array.isArray(value) || isPlainRecord(value);
2322
2382
  }
2323
2383
  function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2324
2384
  if (isUnset(input)) {
@@ -2332,20 +2392,21 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2332
2392
  return input;
2333
2393
  }
2334
2394
  if (input === null) return null;
2335
- if (isOpaqueLeaf(input)) return input;
2395
+ if (!isRecursable(input)) return input;
2336
2396
  if (Array.isArray(input)) {
2337
2397
  const out = new Array(input.length);
2338
2398
  let mutated = false;
2339
2399
  for (let i = 0; i < input.length; i++) {
2340
- const walked = walkCore(input[i], [...segments, i], schema, paths, synthesizeSchemaKeys);
2400
+ const original = readConsumerIndex(input, i);
2401
+ const walked = walkCore(original, [...segments, i], schema, paths, synthesizeSchemaKeys);
2341
2402
  out[i] = walked;
2342
- if (walked !== input[i]) mutated = true;
2403
+ if (walked !== original) mutated = true;
2343
2404
  }
2344
2405
  return mutated ? out : input;
2345
2406
  }
2346
2407
  if (typeof input === "object") {
2347
2408
  const obj = input;
2348
- const inputKeys = Object.keys(obj);
2409
+ const inputKeys = consumerKeys(obj);
2349
2410
  let keys = inputKeys;
2350
2411
  let mutated = false;
2351
2412
  let inputKeysSet = null;
@@ -2353,7 +2414,7 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2353
2414
  inputKeysSet = new Set(inputKeys);
2354
2415
  const allKeys = new Set(inputKeys);
2355
2416
  const slim = schema.getDefaultAtPath(segments);
2356
- if (slim !== null && slim !== void 0 && typeof slim === "object" && !Array.isArray(slim) && !isOpaqueLeaf(slim)) {
2417
+ if (isPlainRecord(slim)) {
2357
2418
  for (const k of Object.keys(slim)) allKeys.add(k);
2358
2419
  }
2359
2420
  keys = allKeys;
@@ -2361,7 +2422,7 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2361
2422
  }
2362
2423
  const out = {};
2363
2424
  for (const key of keys) {
2364
- const orig = obj[key];
2425
+ const orig = readConsumerProp(obj, key);
2365
2426
  if (synthesizeSchemaKeys && orig === void 0 && inputKeysSet?.has(key) === true) {
2366
2427
  safeAssign(out, key, void 0);
2367
2428
  mutated = true;
@@ -2382,22 +2443,12 @@ function walkUnspecified(slim, segments, paths) {
2382
2443
  }
2383
2444
  return slim;
2384
2445
  }
2385
- if (isOpaqueLeaf(slim)) {
2386
- return slim;
2387
- }
2388
- if (Array.isArray(slim)) return slim;
2389
- if (slim !== null && typeof slim === "object") {
2390
- const out = {};
2391
- for (const key of Object.keys(slim)) {
2392
- safeAssign(
2393
- out,
2394
- key,
2395
- walkUnspecified(slim[key], [...segments, key], paths)
2396
- );
2397
- }
2398
- return out;
2446
+ if (!isPlainRecord(slim)) return slim;
2447
+ const out = {};
2448
+ for (const key of Object.keys(slim)) {
2449
+ safeAssign(out, key, walkUnspecified(slim[key], [...segments, key], paths));
2399
2450
  }
2400
- return slim;
2451
+ return out;
2401
2452
  }
2402
2453
  function substituteUnsetSentinels(value, prefix, schema) {
2403
2454
  const paths = [];
@@ -2433,11 +2484,11 @@ function expandUnsetAt(segments, schema, paths) {
2433
2484
  paths.push(canonicalizePath(segments).key);
2434
2485
  return slim;
2435
2486
  }
2436
- if (isOpaqueLeaf(slim)) {
2487
+ if (Array.isArray(slim)) return slim;
2488
+ if (!isPlainRecord(slim)) {
2437
2489
  paths.push(canonicalizePath(segments).key);
2438
2490
  return slim;
2439
2491
  }
2440
- if (Array.isArray(slim)) return slim;
2441
2492
  const result = {};
2442
2493
  for (const key of Object.keys(slim)) {
2443
2494
  result[key] = expandUnsetAt([...segments, key], schema, paths);
@@ -2447,14 +2498,14 @@ function expandUnsetAt(segments, schema, paths) {
2447
2498
  function walkAuthoredFromConstraints(value, prefix, out) {
2448
2499
  if (prefix.length > 0) out.add(canonicalizePath(prefix).key);
2449
2500
  if (isPlainRecord(value)) {
2450
- for (const k of Object.keys(value)) {
2451
- walkAuthoredFromConstraints(value[k], [...prefix, k], out);
2501
+ for (const k of consumerKeys(value)) {
2502
+ walkAuthoredFromConstraints(readConsumerProp(value, k), [...prefix, k], out);
2452
2503
  }
2453
2504
  return;
2454
2505
  }
2455
2506
  if (Array.isArray(value)) {
2456
2507
  for (let i = 0; i < value.length; i++) {
2457
- walkAuthoredFromConstraints(value[i], [...prefix, i], out);
2508
+ walkAuthoredFromConstraints(readConsumerIndex(value, i), [...prefix, i], out);
2458
2509
  }
2459
2510
  }
2460
2511
  }
@@ -2468,11 +2519,50 @@ const DERIVED_DISPLAY_KEYS = /* @__PURE__ */ new Set([
2468
2519
  "firstError",
2469
2520
  "firstOwnError"
2470
2521
  ]);
2471
- const META_SPECIAL_KEYS = /* @__PURE__ */ new Set(["errors", "validating", "valid", "transforming", "busy"]);
2472
- const BASE_MIRROR_KEYS = [...FIELD_STATE_KEYS].filter((k) => !DERIVED_DISPLAY_KEYS.has(k));
2473
- const META_MIRROR_KEYS = [...FIELD_STATE_KEYS].filter((k) => !META_SPECIAL_KEYS.has(k));
2474
- function defineGetter(target, key, get) {
2475
- 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
+ });
2476
2566
  }
2477
2567
  function buildFormApi(state, formInstanceId, options = {}) {
2478
2568
  const instanceBag = pickDefined({
@@ -2499,32 +2589,26 @@ function buildFormApi(state, formInstanceId, options = {}) {
2499
2589
  const rootBaseComputed = computed(
2500
2590
  () => buildContainerFieldStateBase(state, ROOT_PATH, ROOT_PATH_KEY, formInstanceId).base
2501
2591
  );
2502
- const metaBase = {
2503
- instanceId: formInstanceId,
2504
- get submitting() {
2505
- return state.submitting.value;
2506
- },
2507
- get submissionAttempts() {
2508
- return state.submissionAttempts.value;
2509
- },
2510
- get departAttempts() {
2511
- return state.departAttempts.value;
2512
- },
2513
- get submitError() {
2514
- return state.submitError.value;
2515
- },
2516
- get submitted() {
2517
- 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];
2518
2610
  }
2519
- };
2520
- for (const k of BASE_MIRROR_KEYS) {
2521
- defineGetter(
2522
- metaBase,
2523
- k,
2524
- () => rootBaseComputed.value[k]
2525
- );
2526
- }
2527
- defineGetter(metaBase, "errorCount", () => rootBaseComputed.value.errors.length);
2611
+ });
2528
2612
  const getFormMetaBase = () => {
2529
2613
  void state.submitting.value;
2530
2614
  void state.submissionAttempts.value;
@@ -2533,26 +2617,41 @@ function buildFormApi(state, formInstanceId, options = {}) {
2533
2617
  void state.submitted.value;
2534
2618
  return metaBase;
2535
2619
  };
2536
- const fieldStateAccessorOptions = options.getDisplayState !== void 0 ? { getDisplayState: options.getDisplayState } : void 0;
2620
+ const pathSweep = state.pathSweep;
2537
2621
  const getRootFieldStateAt = buildFieldStateAccessor(
2538
2622
  state,
2539
2623
  formInstanceId,
2540
2624
  getFormMetaBase,
2541
- fieldStateAccessorOptions
2625
+ pathSweep
2542
2626
  );
2543
2627
  const getDisplayStateAt = (segments) => getRootFieldStateAt(segments).value.displayState;
2544
2628
  const registerConfig = {
2545
- ...pickDefined({ instanceMeta, coerce: options.coerce, autoAria: options.autoAria }),
2629
+ ...pickDefined({ instanceMeta, coerce: options.coerce }),
2546
2630
  getDisplayStateAt
2547
2631
  };
2548
2632
  const register = buildRegister(state, formInstanceId, registerConfig);
2549
- const processOptions = pickDefined({ onInvalidSubmit: options.onInvalidSubmit });
2550
- 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
+ };
2551
2648
  const {
2552
2649
  validate: validateBuilt,
2553
2650
  parse: parseBuilt,
2554
2651
  handleSubmit
2555
- } = buildProcessForm(state, formInstanceId, processOptions);
2652
+ } = buildProcessForm(state, {
2653
+ applyInvalidSubmit: applyInvalidSubmitPolicyPublic
2654
+ });
2556
2655
  const validate = (pathInput) => validateBuilt(pathInput);
2557
2656
  const parse = (arg1, arg2) => {
2558
2657
  const isPathArg = typeof arg1 === "string" || Array.isArray(arg1);
@@ -2564,6 +2663,10 @@ function buildFormApi(state, formInstanceId, options = {}) {
2564
2663
  const segments = canonicalizePath(pathInput).segments;
2565
2664
  return computed(() => getAtPath(state.form.value, segments));
2566
2665
  }
2666
+ function pathStoresFunctions(segments) {
2667
+ if (state.schema.isOpaqueLeafAtPath(segments)) return false;
2668
+ return state.schema.getSlimPrimitiveTypesAtPath(segments).has("function");
2669
+ }
2567
2670
  function setValueImpl(pathOrValue, maybeValue) {
2568
2671
  const argc = arguments.length;
2569
2672
  const isPathForm = argc >= 2 && (typeof pathOrValue === "string" || Array.isArray(pathOrValue));
@@ -2616,7 +2719,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2616
2719
  };
2617
2720
  if (isUnset(maybeValue)) return writeUnsetAt();
2618
2721
  let resolvedValue;
2619
- if (typeof maybeValue === "function") {
2722
+ if (typeof maybeValue === "function" && !pathStoresFunctions(segments)) {
2620
2723
  const current = state.getValueAtPath(segments);
2621
2724
  const prev = current === void 0 ? state.schema.getDefaultAtPath(segments) : current;
2622
2725
  resolvedValue = maybeValue(prev);
@@ -2634,7 +2737,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2634
2737
  reMarkBlanksAfterSubstitution(walked.paths);
2635
2738
  return true;
2636
2739
  }
2637
- const errorsProxy = buildErrorsSurface(state);
2740
+ const errorsProxy = buildErrorsSurface(state, pathSweep);
2638
2741
  function flattenUserErrors() {
2639
2742
  const all = [];
2640
2743
  for (const cell of state.errorCells.values()) all.push(...cell.user);
@@ -2676,22 +2779,21 @@ function buildFormApi(state, formInstanceId, options = {}) {
2676
2779
  () => state.firstValidationDone.value && state.errorCells.size === 0 && state.derivedBlankErrors.value.size === 0 && !validating.value
2677
2780
  );
2678
2781
  const history = options.history;
2679
- const formHistory = readonly(
2782
+ const formHistory = history === void 0 ? inertHistory() : readonly(
2680
2783
  reactive({
2681
- undo: history?.undo ?? (() => false),
2682
- redo: history?.redo ?? (() => false),
2683
- clear: history?.clear ?? (() => {
2684
- }),
2685
- canUndo: history?.canUndo ?? computed(() => false),
2686
- canRedo: history?.canRedo ?? computed(() => false),
2687
- 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
2688
2790
  })
2689
2791
  );
2690
2792
  const metaErrors = computed(
2691
- () => aggregateErrorsAt(state, [])
2793
+ () => aggregateErrorsAt(state, [], ROOT_PATH_KEY)
2692
2794
  );
2693
2795
  const rootFieldState = getRootFieldStateAt([]);
2694
- const metaTarget = {
2796
+ const metaOwn = {
2695
2797
  // Whole-form work signals compose the LIFECYCLE counters with the
2696
2798
  // per-leaf rollup: a submit-time validate shows up as
2697
2799
  // activeValidations, per-field debounced validators as
@@ -2720,21 +2822,19 @@ function buildFormApi(state, formInstanceId, options = {}) {
2720
2822
  // identifier).
2721
2823
  instanceId: formInstanceId
2722
2824
  };
2723
- for (const k of META_MIRROR_KEYS) {
2724
- defineGetter(
2725
- metaTarget,
2726
- k,
2727
- () => rootFieldState.value[k]
2728
- );
2729
- }
2730
- 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
+ });
2731
2830
  const formMeta = readonly(reactive(metaTarget));
2732
2831
  const reset = (nextDefaultValues) => {
2733
2832
  if (nextDefaultValues === void 0) {
2734
2833
  state.reset();
2735
2834
  } else {
2736
- const walked = walkUnsetSentinels(
2835
+ const walked = substituteUnsetSentinels(
2737
2836
  nextDefaultValues,
2837
+ [],
2738
2838
  state.schema
2739
2839
  );
2740
2840
  state.reset(walked.cleanedValues);
@@ -2766,21 +2866,6 @@ function buildFormApi(state, formInstanceId, options = {}) {
2766
2866
  } catch {
2767
2867
  }
2768
2868
  }
2769
- const focusFirstError = (options2) => {
2770
- const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
2771
- if (target === null) return false;
2772
- target.element.focus({ focusVisible: true, ...options2 });
2773
- return true;
2774
- };
2775
- const scrollToFirstError = (options2) => {
2776
- const target = state.domBinding.value?.getFirstErrorElement(formInstanceId) ?? null;
2777
- if (target === null) return false;
2778
- target.element.scrollIntoView(options2);
2779
- return true;
2780
- };
2781
- const applyInvalidSubmitPolicyPublic = (policy) => {
2782
- applyInvalidSubmitPolicy(state, formInstanceId, policy ?? defaultInvalidSubmitPolicy);
2783
- };
2784
2869
  const fieldArrays = buildFieldArrayApi(state);
2785
2870
  const blankPathsView = computed(() => {
2786
2871
  const keys = /* @__PURE__ */ new Set();
@@ -2808,8 +2893,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
2808
2893
  };
2809
2894
  return Object.freeze(view);
2810
2895
  });
2811
- const valuesProxy = buildValuesSurface(state.form);
2812
- const fieldStateProxy = buildFieldsSurface(state, getRootFieldStateAt);
2896
+ const valuesProxy = buildValuesSurface(state.form, state.onFormChange);
2897
+ const fieldStateProxy = buildFieldsSurface(state, getRootFieldStateAt, pathSweep);
2813
2898
  const needsLazyGate = state.defaultValuesFactory.value !== void 0 || state.hasSsrPrefetch;
2814
2899
  function gated(fn) {
2815
2900
  if (!needsLazyGate) return fn;
@@ -2928,8 +3013,53 @@ function buildFormApi(state, formInstanceId, options = {}) {
2928
3013
  return api;
2929
3014
  }
2930
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
+
2931
3055
  const IDLE = Object.freeze({ display: "idle" });
2932
3056
  const MAX_DELAY = 2147483647;
3057
+ const PENDING_LIVENESS_MS = 250;
3058
+ function withLiveness(machine, now) {
3059
+ if (machine.display !== "pending") return machine;
3060
+ if (machine.reviewAt !== void 0 && Number.isFinite(machine.reviewAt)) return machine;
3061
+ return { ...machine, reviewAt: now + PENDING_LIVENESS_MS };
3062
+ }
2933
3063
  function createDisplayEngine(ssr) {
2934
3064
  const machines = /* @__PURE__ */ new Map();
2935
3065
  const tick = ref(0);
@@ -2958,7 +3088,7 @@ function createDisplayEngine(ssr) {
2958
3088
  return;
2959
3089
  }
2960
3090
  if (timer !== null && timerTarget === target) return;
2961
- if (target === lastFiredTarget) {
3091
+ if (target === lastFiredTarget && target <= now) {
2962
3092
  clearTimer();
2963
3093
  return;
2964
3094
  }
@@ -2977,8 +3107,9 @@ function createDisplayEngine(ssr) {
2977
3107
  function resolve(key, ctx, reducer) {
2978
3108
  void tick.value;
2979
3109
  const prev = machines.get(key) ?? IDLE;
2980
- const machine = reducer(prev, ctx);
2981
- if (ssr) return machine;
3110
+ const reduced = reducer(prev, ctx);
3111
+ if (ssr) return reduced;
3112
+ const machine = withLiveness(reduced, ctx.now);
2982
3113
  const active = machine.display !== "idle" || machine.reviewAt !== void 0 && Number.isFinite(machine.reviewAt);
2983
3114
  if (active) machines.set(key, machine);
2984
3115
  else machines.delete(key);
@@ -3009,6 +3140,58 @@ function createDisplayEngine(ssr) {
3009
3140
  return engine;
3010
3141
  }
3011
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
+
3012
3195
  function mergeSparseHydration(schemaDefaults, sparse, schema) {
3013
3196
  return mergeDeep(schemaDefaults, sparse, [], schema);
3014
3197
  }
@@ -3070,6 +3253,7 @@ async function runFactoryAndApply(st, factory) {
3070
3253
  st.schema
3071
3254
  );
3072
3255
  st.applyFormReplacement(full, { hydration: true });
3256
+ st.adoptResolvedDefaults(value);
3073
3257
  st.scheduleFieldValidation(
3074
3258
  [],
3075
3259
  true
@@ -3149,12 +3333,10 @@ function applyDuStubs(schema, data, options = {}) {
3149
3333
  }
3150
3334
  function walkDuStubs(schema, value, path, warned) {
3151
3335
  if (value === null || value === void 0 || typeof value !== "object") return value;
3152
- if (value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || typeof value === "function") {
3153
- return value;
3154
- }
3155
3336
  if (Array.isArray(value)) {
3156
3337
  return value.map((item, i) => walkDuStubs(schema, item, [...path, i]));
3157
3338
  }
3339
+ if (!isPlainRecord(value)) return value;
3158
3340
  const rec = value;
3159
3341
  const du = schema.getUnionDiscriminatorAtPath(path);
3160
3342
  if (du !== void 0) {
@@ -3166,8 +3348,8 @@ function walkDuStubs(schema, value, path, warned) {
3166
3348
  }
3167
3349
  }
3168
3350
  const out = {};
3169
- for (const k of Object.keys(rec)) {
3170
- safeAssign(out, k, walkDuStubs(schema, rec[k], [...path, k]));
3351
+ for (const k of consumerKeys(rec)) {
3352
+ safeAssign(out, k, walkDuStubs(schema, readConsumerProp(rec, k), [...path, k]));
3171
3353
  }
3172
3354
  return out;
3173
3355
  }
@@ -3177,23 +3359,25 @@ function stripSymbolsDeep(value) {
3177
3359
  let mutated2 = false;
3178
3360
  const out2 = new Array(value.length);
3179
3361
  for (let i = 0; i < value.length; i++) {
3180
- const cleaned = stripSymbolsDeep(value[i]);
3362
+ const original = readConsumerIndex(value, i);
3363
+ const cleaned = stripSymbolsDeep(original);
3181
3364
  out2[i] = cleaned;
3182
- if (cleaned !== value[i]) mutated2 = true;
3365
+ if (cleaned !== original) mutated2 = true;
3183
3366
  }
3184
3367
  return mutated2 ? out2 : value;
3185
3368
  }
3186
3369
  const proto = Object.getPrototypeOf(value);
3187
3370
  if (proto !== Object.prototype && proto !== null) return value;
3188
- const symKeys = Object.getOwnPropertySymbols(value);
3189
- const stringKeys = Object.keys(value);
3371
+ const symKeys = consumerSymbolKeys(value);
3372
+ const stringKeys = consumerKeys(value);
3190
3373
  let mutated = symKeys.length > 0;
3191
3374
  const out = {};
3192
3375
  const src = value;
3193
3376
  for (const k of stringKeys) {
3194
- const cleaned = stripSymbolsDeep(src[k]);
3377
+ const original = readConsumerProp(src, k);
3378
+ const cleaned = stripSymbolsDeep(original);
3195
3379
  out[k] = cleaned;
3196
- if (cleaned !== src[k]) mutated = true;
3380
+ if (cleaned !== original) mutated = true;
3197
3381
  }
3198
3382
  return mutated ? out : value;
3199
3383
  }
@@ -3218,16 +3402,15 @@ function walkAuthoredFromSchemaDiff(withDefaults, withoutDefaults, prefix, out)
3218
3402
  out.add(canonicalizePath(prefix).key);
3219
3403
  }
3220
3404
  }
3221
- function computeBaselineResponse(schema, strict, source) {
3405
+ function computeBaselineResponse(schema, source) {
3222
3406
  const completed = source === void 0 ? void 0 : mergeStructural(schema, [], source);
3223
3407
  return schema.getDefaultValues({
3224
3408
  useDefaultSchemaValues: true,
3225
- constraints: completed,
3226
- strict
3409
+ constraints: completed
3227
3410
  });
3228
3411
  }
3229
- function initialFirstValidationGate(schema, strict) {
3230
- return !strict || schema.needsAsyncValidation?.() !== true;
3412
+ function initialFirstValidationGate(schema) {
3413
+ return schema.needsAsyncValidation?.() !== true;
3231
3414
  }
3232
3415
  function seedOriginalsFromBaseline(st, baseline, ensureOrdinals) {
3233
3416
  st.originals.clear();
@@ -3239,7 +3422,7 @@ function seedOriginalsFromBaseline(st, baseline, ensureOrdinals) {
3239
3422
  });
3240
3423
  }
3241
3424
  function queueInitialAsyncValidation(st) {
3242
- if (!st.ssr && st.strict && st.schema.needsAsyncValidation?.() === true) {
3425
+ if (!st.ssr && st.schema.needsAsyncValidation?.() === true) {
3243
3426
  queueMicrotask(() => scheduleFieldValidation(
3244
3427
  st,
3245
3428
  [],
@@ -3281,10 +3464,6 @@ function ensurePathOrdinal(st, key) {
3281
3464
  }
3282
3465
  return ordinal;
3283
3466
  }
3284
- function pathHasAsyncValidation(st, path) {
3285
- const { key } = canonicalizePath(path);
3286
- return pathHasAsyncValidationByKey(st, key, path);
3287
- }
3288
3467
  function pathHasAsyncValidationByKey(st, key, segments) {
3289
3468
  const cached = st.pathAsyncCache.get(key);
3290
3469
  if (cached !== void 0) return cached;
@@ -3427,10 +3606,15 @@ function commitWritePatches(st, patches, meta) {
3427
3606
  const now = (/* @__PURE__ */ new Date()).toISOString();
3428
3607
  for (const patch of patches) {
3429
3608
  const { key } = canonicalizePath(patch.path);
3430
- if (patch.kind === "added" && !st.originals.has(key)) {
3609
+ if (!st.originals.has(key)) {
3431
3610
  st.originals.set(key, { segments: patch.path, value: void 0 });
3432
3611
  }
3433
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
+ }
3434
3618
  }
3435
3619
  for (const listener of st.formChangeListeners) {
3436
3620
  try {
@@ -3635,10 +3819,7 @@ function setValueAtPath(st, path, value, meta) {
3635
3819
  if (newlyAuthored && st.schema.isPreprocessOrCoerceLeaf(path)) {
3636
3820
  const modeForAuthoringTransition = meta?.instance?.validateOn ?? st.fieldValidationMode;
3637
3821
  if (modeForAuthoringTransition === "change") {
3638
- scheduleFieldValidation(st, path, false, {
3639
- ...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
3640
- ...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
3641
- });
3822
+ scheduleFieldValidation(st, path, false, meta?.instance);
3642
3823
  }
3643
3824
  }
3644
3825
  return true;
@@ -3654,15 +3835,12 @@ function setValueAtPath(st, path, value, meta) {
3654
3835
  st.arrayIdentity.realign(path);
3655
3836
  } else if (isContainer(currentValue) && !isContainer(value)) {
3656
3837
  if (subtreeHadRealBaseline(st, path, currentValue)) {
3657
- st.removedSubtrees.add(canonicalizePath(path).key);
3838
+ st.removedSubtrees.add(pathKey);
3658
3839
  }
3659
3840
  }
3660
3841
  const effectiveModeAfterWrite = meta?.instance?.validateOn ?? st.fieldValidationMode;
3661
3842
  if (effectiveModeAfterWrite === "change") {
3662
- scheduleFieldValidation(st, path, false, {
3663
- ...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
3664
- ...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
3665
- });
3843
+ scheduleFieldValidation(st, path, false, meta?.instance);
3666
3844
  }
3667
3845
  return true;
3668
3846
  }
@@ -3723,12 +3901,11 @@ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variant
3723
3901
  path: [...parentPath, ...err.path]
3724
3902
  }));
3725
3903
  applySchemaErrorsForSubtree(st, parentPath, reStamped);
3726
- const { key: parentKey2 } = canonicalizePath(parentPath);
3727
- const prevValidation = st.fieldValidationState.get(parentKey2);
3904
+ const prevValidation = st.fieldValidationState.get(parentKey);
3728
3905
  if (prevValidation !== void 0) {
3729
3906
  if (prevValidation.timer !== null) clearTimeout(prevValidation.timer);
3730
3907
  prevValidation.aborted = true;
3731
- st.fieldValidationState.delete(parentKey2);
3908
+ st.fieldValidationState.delete(parentKey);
3732
3909
  }
3733
3910
  appliedSync = true;
3734
3911
  }
@@ -3736,17 +3913,14 @@ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variant
3736
3913
  applyFormReplacement(st, nextForm, meta);
3737
3914
  for (const k of newBlankPaths) st.blankPaths.add(k);
3738
3915
  if (reshapeMode === "change" && !appliedSync) {
3739
- scheduleFieldValidation(st, parentPath, false, {
3740
- ...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
3741
- ...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
3742
- });
3916
+ scheduleFieldValidation(st, parentPath, false, meta?.instance);
3743
3917
  }
3744
3918
  return true;
3745
3919
  }
3746
- function scheduleFieldValidation(st, path, immediate, override) {
3747
- const effectiveMode = override?.mode ?? st.fieldValidationMode;
3920
+ function scheduleFieldValidation(st, path, immediate, instance) {
3921
+ const effectiveMode = instance?.validateOn ?? st.fieldValidationMode;
3748
3922
  if (effectiveMode === "submit") return;
3749
- const effectiveDebounce = override?.debounceMs ?? st.fieldValidationDebounceMs;
3923
+ const effectiveDebounce = instance?.debounceMs ?? st.fieldValidationDebounceMs;
3750
3924
  const { key } = canonicalizePath(path);
3751
3925
  const prev = st.fieldValidationState.get(key);
3752
3926
  if (prev !== void 0) {
@@ -4020,10 +4194,7 @@ function markFocused(st, path, focused, meta) {
4020
4194
  });
4021
4195
  }
4022
4196
  if (changed) {
4023
- scheduleFieldValidation(st, path, true, {
4024
- ...meta?.instance?.validateOn !== void 0 ? { mode: meta.instance.validateOn } : {},
4025
- ...meta?.instance?.debounceMs !== void 0 ? { debounceMs: meta.instance.debounceMs } : {}
4026
- });
4197
+ scheduleFieldValidation(st, path, true, meta?.instance);
4027
4198
  }
4028
4199
  }
4029
4200
  }
@@ -4035,10 +4206,9 @@ function markInteracted(st, path) {
4035
4206
  }
4036
4207
  function touchAtPath(st, segments) {
4037
4208
  const formValue = st.form.value;
4038
- for (const [, entry] of st.originals) {
4209
+ for (const [leafKey, entry] of st.originals) {
4039
4210
  if (!isPathPrefix(segments, entry.segments)) continue;
4040
4211
  if (!hasAtPath(formValue, entry.segments)) continue;
4041
- const leafKey = canonicalizePath(entry.segments).key;
4042
4212
  const current = st.fields.get(leafKey);
4043
4213
  if (current?.touched === true) continue;
4044
4214
  touchFieldRecord(st, leafKey, entry.segments, { touched: true });
@@ -4048,11 +4218,10 @@ function interactAtPath(st, segments) {
4048
4218
  if (st.effectiveDisabled.value) return false;
4049
4219
  const formValue = st.form.value;
4050
4220
  let interactedAny = false;
4051
- for (const [, entry] of st.originals) {
4221
+ for (const [leafKey, entry] of st.originals) {
4052
4222
  if (!isPathPrefix(segments, entry.segments)) continue;
4053
4223
  if (!hasAtPath(formValue, entry.segments)) continue;
4054
4224
  interactedAny = true;
4055
- const leafKey = canonicalizePath(entry.segments).key;
4056
4225
  const current = st.fields.get(leafKey);
4057
4226
  if (current?.touched === true && current.interacted === true && current.blurredAfterInteraction === true) {
4058
4227
  continue;
@@ -4096,9 +4265,24 @@ function activate(st) {
4096
4265
  if (factory === void 0) return Promise.resolve();
4097
4266
  return fireFactory(st, factory);
4098
4267
  }
4268
+ function adoptResolvedDefaults(st, value) {
4269
+ st.defaultValues = structuralSnapshot(
4270
+ mergeSparseHydration(
4271
+ st.defaultValues,
4272
+ value,
4273
+ st.schema
4274
+ )
4275
+ );
4276
+ seedOriginalsFromBaseline(st, computeBaselineResponse(st.schema, st.defaultValues).data, false);
4277
+ }
4099
4278
  function reset(st, nextDefaultValues) {
4100
- const resetSource = nextDefaultValues ?? st.defaultValues;
4101
- const resetResponse = computeBaselineResponse(st.schema, st.strict, resetSource);
4279
+ const resetSource = nextDefaultValues === void 0 ? st.defaultValues : mergeSparseHydration(
4280
+ st.defaultValues,
4281
+ nextDefaultValues,
4282
+ st.schema
4283
+ );
4284
+ st.defaultValues = structuralSnapshot(resetSource);
4285
+ const resetResponse = computeBaselineResponse(st.schema, resetSource);
4102
4286
  const next = resetResponse.data;
4103
4287
  rebuildAuthoredPaths(st, resetSource, next);
4104
4288
  applyFormReplacement(st, next);
@@ -4106,25 +4290,23 @@ function reset(st, nextDefaultValues) {
4106
4290
  st.removedSubtrees.clear();
4107
4291
  seedOriginalsFromBaseline(st, next, false);
4108
4292
  if (nextDefaultValues !== void 0) {
4109
- st.blankPaths.clear();
4110
- st.originalBlankPaths.clear();
4111
- } else {
4112
- st.blankPaths.clear();
4113
- for (const key of st.originalBlankPaths) {
4114
- st.blankPaths.add(key);
4115
- }
4293
+ const mentioned = /* @__PURE__ */ new Set();
4294
+ walkAuthoredFromConstraints(nextDefaultValues, [], mentioned);
4295
+ for (const key of mentioned) st.originalBlankPaths.delete(key);
4296
+ }
4297
+ st.blankPaths.clear();
4298
+ for (const key of st.originalBlankPaths) {
4299
+ st.blankPaths.add(key);
4116
4300
  }
4117
4301
  st.errorCells.clear();
4118
- if (st.strict && !resetResponse.success) {
4302
+ if (!resetResponse.success) {
4119
4303
  replaceErrorChannel(st, "schema", resetResponse.errors);
4120
4304
  }
4121
- if (st.strict) {
4122
- const syncResult = st.schema.validateAtPath(st.form.value, void 0, { sync: true });
4123
- if (!(syncResult instanceof Promise) && !syncResult.success) {
4124
- applySchemaErrorsForSubtree(st, [], syncResult.errors);
4125
- }
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);
4126
4308
  }
4127
- st.firstValidationDone.value = initialFirstValidationGate(st.schema, st.strict);
4309
+ st.firstValidationDone.value = initialFirstValidationGate(st.schema);
4128
4310
  queueInitialAsyncValidation(st);
4129
4311
  const now = (/* @__PURE__ */ new Date()).toISOString();
4130
4312
  for (const [pathKey, record] of st.fields) {
@@ -4214,10 +4396,6 @@ function clearFieldRecordFlags(st, pathKey) {
4214
4396
  if (record === void 0) return;
4215
4397
  st.fields.set(pathKey, withClearedHistoryFlags(record, (/* @__PURE__ */ new Date()).toISOString()));
4216
4398
  }
4217
- function isPristineAtPath(st, path) {
4218
- const { key, segments } = canonicalizePath(path);
4219
- return isPristineAtPathByKey(st, key, segments);
4220
- }
4221
4399
  function isPristineAtPathByKey(st, key, segments) {
4222
4400
  if (st.blankPaths.has(key) !== st.originalBlankPaths.has(key)) return false;
4223
4401
  const entry = st.originals.get(key);
@@ -4251,12 +4429,8 @@ function getFieldRecord(st, path) {
4251
4429
  const { key } = canonicalizePath(path);
4252
4430
  return st.fields.get(key);
4253
4431
  }
4254
- function getOriginalAtPath(st, path) {
4255
- const { key } = canonicalizePath(path);
4256
- return st.originals.get(key)?.value;
4257
- }
4258
4432
  function createFormStore(options) {
4259
- const { formKey, schema, defaultValues, strict = true, hydration } = options;
4433
+ const { formKey, schema, defaultValues, hydration } = options;
4260
4434
  const ssr = options.ssr === true;
4261
4435
  const ssrPrefetch = options.ssrPrefetch;
4262
4436
  const rememberVariants = options.rememberVariants !== false;
@@ -4264,22 +4438,16 @@ function createFormStore(options) {
4264
4438
  const fieldValidationDebounceMs = normalizeNumericOption({
4265
4439
  value: options.debounceMs ?? DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS,
4266
4440
  source: "useForm.debounceMs",
4267
- allowInfinity: false,
4268
4441
  min: 0,
4269
4442
  defaultValue: DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS
4270
4443
  });
4271
- const coerceIndex = resolveCoercionIndex(options.coerce);
4272
- const resolvedGetDisplayState = resolveGetDisplayState(options.getDisplayState);
4444
+ const coerceEnabled = resolveCoerceEnabled(options.coerce);
4273
4445
  const cleanupHooks = [];
4274
4446
  const modules = /* @__PURE__ */ new Map();
4275
4447
  const fieldValidatingSince = reactive(/* @__PURE__ */ new Map());
4276
4448
  const displayEngine = createDisplayEngine(ssr);
4277
4449
  cleanupHooks.push(() => displayEngine.dispose());
4278
- const schemaResponse = computeBaselineResponse(
4279
- schema,
4280
- strict,
4281
- defaultValues
4282
- );
4450
+ const schemaResponse = computeBaselineResponse(schema, defaultValues);
4283
4451
  const schemaInitialData = schemaResponse.data;
4284
4452
  const authoredPaths = /* @__PURE__ */ new Set();
4285
4453
  const initialData = hydration !== void 0 ? hydration.form : structuralSnapshot(schemaInitialData);
@@ -4292,16 +4460,15 @@ function createFormStore(options) {
4292
4460
  const v = getAtPath(toRaw(form.value), arraySegs);
4293
4461
  return Array.isArray(v) ? v.length : 0;
4294
4462
  });
4295
- const fields = reactive(/* @__PURE__ */ new Map());
4463
+ const fields = shallowReactive(/* @__PURE__ */ new Map());
4296
4464
  const domBinding = shallowRef(null);
4297
- const errorCells = reactive(/* @__PURE__ */ new Map());
4298
- const originals = reactive(/* @__PURE__ */ new Map());
4465
+ const errorCells = shallowReactive(/* @__PURE__ */ new Map());
4466
+ const originals = shallowReactive(/* @__PURE__ */ new Map());
4299
4467
  const removedSubtrees = /* @__PURE__ */ new Set();
4300
- const initialTransientList = hydration?.blankPaths ?? options.initialBlankPaths ?? [];
4301
4468
  const blankPaths = reactive(/* @__PURE__ */ new Set());
4302
4469
  const originalBlankPaths = /* @__PURE__ */ new Set();
4303
- for (const raw of initialTransientList) {
4304
- 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) {
4305
4472
  blankPaths.add(key);
4306
4473
  originalBlankPaths.add(key);
4307
4474
  }
@@ -4318,6 +4485,9 @@ function createFormStore(options) {
4318
4485
  }
4319
4486
  return result;
4320
4487
  });
4488
+ const errorPathIndex = computed(
4489
+ () => buildErrorPathIndex(errorCells, derivedBlankErrors.value)
4490
+ );
4321
4491
  const submitting = ref(false);
4322
4492
  const activeSubmissions = ref(0);
4323
4493
  const submissionAttempts = ref(0);
@@ -4342,7 +4512,7 @@ function createFormStore(options) {
4342
4512
  const defaultsResolved = ref(false);
4343
4513
  const activated = ref(false);
4344
4514
  const activationPromise = ref(void 0);
4345
- const firstValidationDone = ref(initialFirstValidationGate(schema, strict));
4515
+ const firstValidationDone = ref(initialFirstValidationGate(schema));
4346
4516
  watch(activeValidations, (now, prev) => {
4347
4517
  if (prev > 0 && now === 0) {
4348
4518
  firstValidationDone.value = true;
@@ -4360,6 +4530,33 @@ function createFormStore(options) {
4360
4530
  const activeTransforms = ref(0);
4361
4531
  const transformRuns = /* @__PURE__ */ new Map();
4362
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
+ };
4363
4560
  const arrayBookkeeping = createArrayBookkeeping({
4364
4561
  form,
4365
4562
  fields,
@@ -4377,6 +4574,7 @@ function createFormStore(options) {
4377
4574
  touchFieldRecord: (pathKey, path, patch) => touchFieldRecord(st, pathKey, path, patch),
4378
4575
  decFieldValidation: (key) => decFieldValidation(st, key)
4379
4576
  });
4577
+ const bind = (fn) => (...args) => fn(st, ...args);
4380
4578
  const st = {
4381
4579
  // --- public data (the FormStore contract's state members) ---
4382
4580
  formKey,
@@ -4384,10 +4582,11 @@ function createFormStore(options) {
4384
4582
  fields,
4385
4583
  errorCells,
4386
4584
  derivedBlankErrors,
4585
+ errorWindowAt,
4387
4586
  originals,
4587
+ pathSweep,
4388
4588
  schema,
4389
4589
  ssr,
4390
- getDisplayState: resolvedGetDisplayState,
4391
4590
  submitting,
4392
4591
  activeSubmissions,
4393
4592
  submissionAttempts,
@@ -4415,12 +4614,20 @@ function createFormStore(options) {
4415
4614
  displayEngine,
4416
4615
  domBinding,
4417
4616
  modules,
4418
- coerceIndex,
4617
+ coerceEnabled,
4419
4618
  blankPaths,
4420
4619
  originalBlankPaths,
4421
4620
  // --- kernel-internal state ---
4422
- strict,
4423
- defaultValues,
4621
+ // Defensive copy, not a fix for an observed alias: today
4622
+ // `getDefaultValues` happens to build a fresh tree, so form storage
4623
+ // does not currently share structure with the consumer's object.
4624
+ // That is an adapter implementation detail rather than a contract,
4625
+ // and this field is now durable state that every `reset()` reads, so
4626
+ // it should not depend on it. The copy also means a consumer who
4627
+ // keeps a reference to the literal they passed cannot mutate the
4628
+ // form's defaults from outside. `reset()` snapshots for a harder
4629
+ // reason (see there) where an alias IS reachable.
4630
+ defaultValues: structuralSnapshot(defaultValues),
4424
4631
  ssrPrefetch,
4425
4632
  rememberVariants,
4426
4633
  fieldValidationMode,
@@ -4447,16 +4654,20 @@ function createFormStore(options) {
4447
4654
  transformTokenSeq: 0,
4448
4655
  warnedDisabledWrite: false,
4449
4656
  // --- methods: thin per-instance skins over the module kernel ---
4450
- rehydrate: () => rehydrate(st),
4451
- activate: () => activate(st),
4452
- pathHasAsyncValidation: (path) => pathHasAsyncValidation(st, path),
4453
- pathHasAsyncValidationByKey: (key, segments) => pathHasAsyncValidationByKey(st, key, segments),
4454
- applyFormReplacement: (next, meta) => applyFormReplacement(st, next, meta),
4455
- setValueAtPath: (path, value, meta) => setValueAtPath(st, path, value, meta),
4456
- getValueAtPath: (path) => getValueAtPath(st, path),
4457
- arrayElementKey: (path) => arrayElementKey(st, path),
4458
- reset: (nextDefaultValues) => reset(st, nextDefaultValues),
4459
- 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.
4460
4671
  setSchemaErrorsForPath: (path, entries) => setErrorChannelForKey(
4461
4672
  st,
4462
4673
  canonicalizePath(path).key,
@@ -4465,7 +4676,7 @@ function createFormStore(options) {
4465
4676
  ),
4466
4677
  setAllSchemaErrors: (entries) => replaceErrorChannel(st, "schema", entries),
4467
4678
  clearSchemaErrors: (path) => clearErrorChannel(st, "schema", path),
4468
- applySchemaErrorsForSubtree: (path, entries) => applySchemaErrorsForSubtree(st, path, entries),
4679
+ applySchemaErrorsForSubtree: bind(applySchemaErrorsForSubtree),
4469
4680
  setAllUserErrors: (entries) => replaceErrorChannel(st, "user", entries),
4470
4681
  setUserErrorsForPath: (path, entries) => setErrorChannelForKey(
4471
4682
  st,
@@ -4474,37 +4685,34 @@ function createFormStore(options) {
4474
4685
  entries.length === 0 ? NO_ERRORS : [...entries]
4475
4686
  ),
4476
4687
  clearUserErrors: (path) => clearErrorChannel(st, "user", path),
4477
- restoreErrorCells: (entries) => restoreErrorCells(st, entries),
4478
- getErrorsForPath: (path) => getErrorsForPath(st, path),
4479
- ensurePathOrdinal: (key) => ensurePathOrdinal(st, key),
4480
- noteDomConnected: (path) => noteDomConnected(st, path),
4481
- noteDomDisconnected: (path) => noteDomDisconnected(st, path),
4482
- markFocused: (path, focused, meta) => markFocused(st, path, focused, meta),
4483
- markInteracted: (path) => markInteracted(st, path),
4484
- touchAtPath: (segments) => touchAtPath(st, segments),
4485
- interactAtPath: (segments) => interactAtPath(st, segments),
4486
- markConnectedOptimistically: (path) => markConnectedOptimistically(st, path),
4487
- isPristineAtPath: (path) => isPristineAtPath(st, path),
4488
- isPristineAtPathByKey: (key, segments) => isPristineAtPathByKey(st, key, segments),
4489
- hasStructuralChangeUnder: (path) => hasStructuralChangeUnder(st, path),
4490
- hasRemovedSubtreeUnder: (path) => hasRemovedSubtreeUnder(st, path),
4491
- getFieldRecord: (path) => getFieldRecord(st, path),
4492
- getOriginalAtPath: (path) => getOriginalAtPath(st, path),
4493
- cancelFieldValidation: () => cancelFieldValidation(st),
4494
- beginTransform: (key, holder) => beginTransform(st, key, holder),
4495
- isCurrentTransform: (key, token) => isCurrentTransform(st, key, token),
4496
- endTransform: (key, token) => endTransform(st, key, token),
4497
- setTransformError: (key, err) => setTransformError(st, key, err),
4498
- cancelTransforms: () => cancelTransforms(st),
4499
- cancelTransformsUnder: (prefix) => cancelTransformsUnder(st, prefix),
4500
- settleTransforms: (path) => settleTransforms(st, path),
4501
- scheduleFieldValidation: (path, immediate, override) => scheduleFieldValidation(st, path, immediate, override),
4502
- onFormChange: (listener) => onFormChange(st, listener),
4503
- onSubmitSuccess: (listener) => onSubmitSuccess(st, listener),
4504
- onReset: (listener) => onReset(st, listener),
4505
- emitSubmitSuccess: () => emitSubmitSuccess(st),
4506
- registerCleanup: (fn) => registerCleanup(st, fn),
4507
- 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)
4508
4716
  };
4509
4717
  rebuildAuthoredPaths(st, defaultValues, schemaInitialData);
4510
4718
  seedOriginalsFromBaseline(st, schemaInitialData, true);
@@ -4543,7 +4751,7 @@ function createFormStore(options) {
4543
4751
  blurredAfterInteraction: false
4544
4752
  });
4545
4753
  });
4546
- if (strict && !schemaResponse.success) {
4754
+ if (!schemaResponse.success) {
4547
4755
  replaceErrorChannel(st, "schema", schemaResponse.errors);
4548
4756
  }
4549
4757
  }
@@ -4574,19 +4782,18 @@ function useAbstractForm(configuration, options) {
4574
4782
  const resolvedDefaults = resolveTrichotomy(configuration.defaultValues);
4575
4783
  const materialisedDefaults = resolvedDefaults.kind === "sync" ? resolvedDefaults.value : void 0;
4576
4784
  const { defaultValues: _droppedDefaults, ...configWithoutDefaults } = configuration;
4577
- const trichotomyOverride = materialisedDefaults === void 0 ? configWithoutDefaults : { ...configWithoutDefaults, defaultValues: materialisedDefaults };
4578
- const merged = mergeWithDefaults(registry.defaults, trichotomyOverride);
4579
- const maxRecursionDepth = normalizeNumericOption({
4580
- value: merged.maxRecursionDepth ?? DEFAULT_MAX_RECURSION_DEPTH,
4581
- source: "useForm.maxRecursionDepth",
4582
- allowInfinity: true,
4583
- min: 0,
4584
- defaultValue: DEFAULT_MAX_RECURSION_DEPTH
4585
- });
4586
- const resolvedSchema = getComputedSchema(key, configuration.schema, { maxRecursionDepth });
4785
+ const materialisedConfiguration = materialisedDefaults === void 0 ? configWithoutDefaults : { ...configWithoutDefaults, defaultValues: materialisedDefaults };
4587
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;
4588
4790
  const hadPendingHydration = registry.pendingHydration.has(key);
4589
- const state = existing ?? buildFreshState(key, resolvedSchema, merged, registry);
4791
+ const state = existing ?? buildFreshState(
4792
+ key,
4793
+ resolvedSchema,
4794
+ materialisedConfiguration,
4795
+ registry
4796
+ );
4590
4797
  if (existing !== void 0) ; else if (resolvedDefaults.kind === "sync") {
4591
4798
  state.defaultsResolved.value = true;
4592
4799
  }
@@ -4594,6 +4801,7 @@ function useAbstractForm(configuration, options) {
4594
4801
  const factory = resolvedDefaults.factory;
4595
4802
  state.defaultValuesFactory.value = factory;
4596
4803
  if (hadPendingHydration) {
4804
+ state.adoptResolvedDefaults(toRaw(state.form.value));
4597
4805
  state.hydrating.value = false;
4598
4806
  state.defaultsResolved.value = true;
4599
4807
  } else if (registry.ssr) {
@@ -4610,8 +4818,8 @@ function useAbstractForm(configuration, options) {
4610
4818
  const releaseConsumer = registry.trackConsumer(key);
4611
4819
  onScopeDispose(releaseConsumer);
4612
4820
  }
4613
- if (existing === void 0 && merged.history !== void 0) {
4614
- const historyModule = merged.history.attach(state);
4821
+ if (existing === void 0 && materialisedConfiguration.history !== void 0) {
4822
+ const historyModule = materialisedConfiguration.history.attach(state);
4615
4823
  state.modules.set(HISTORY_MODULE_KEY, historyModule);
4616
4824
  state.registerCleanup(() => historyModule.dispose());
4617
4825
  }
@@ -4624,36 +4832,16 @@ function useAbstractForm(configuration, options) {
4624
4832
  provide(kFormInstanceId, formInstanceId);
4625
4833
  }
4626
4834
  const apiOptions = pickDefined({
4627
- onInvalidSubmit: merged.onInvalidSubmit,
4835
+ focusOnInvalidSubmit: materialisedConfiguration.focusOnInvalidSubmit,
4628
4836
  history: state.modules.get(HISTORY_MODULE_KEY),
4629
- validateOn: merged.validateOn,
4630
- debounceMs: merged.debounceMs,
4631
- getDisplayState: merged.getDisplayState,
4632
- coerce: merged.coerce,
4633
- rememberVariants: merged.rememberVariants,
4634
- autoAria: merged.autoAria
4837
+ validateOn: materialisedConfiguration.validateOn,
4838
+ debounceMs: materialisedConfiguration.debounceMs,
4839
+ coerce: materialisedConfiguration.coerce,
4840
+ rememberVariants: materialisedConfiguration.rememberVariants
4635
4841
  });
4636
4842
  const api = buildFormApi(state, formInstanceId, apiOptions);
4637
4843
  return api;
4638
4844
  }
4639
- function mergeWithDefaults(defaults, configuration) {
4640
- return {
4641
- ...configuration,
4642
- ...pickDefined({
4643
- strict: configuration.strict ?? defaults.strict,
4644
- onInvalidSubmit: configuration.onInvalidSubmit ?? defaults.onInvalidSubmit,
4645
- history: configuration.history ?? defaults.history,
4646
- rememberVariants: configuration.rememberVariants ?? defaults.rememberVariants,
4647
- disabled: configuration.disabled ?? defaults.disabled,
4648
- coerce: configuration.coerce ?? defaults.coerce,
4649
- validateOn: configuration.validateOn ?? defaults.validateOn,
4650
- debounceMs: configuration.debounceMs ?? defaults.debounceMs,
4651
- getDisplayState: configuration.getDisplayState ?? defaults.getDisplayState,
4652
- maxRecursionDepth: configuration.maxRecursionDepth ?? defaults.maxRecursionDepth,
4653
- autoAria: configuration.autoAria ?? defaults.autoAria
4654
- })
4655
- };
4656
- }
4657
4845
  const HISTORY_MODULE_KEY = "history";
4658
4846
  function buildFreshState(key, schema, configuration, registry) {
4659
4847
  const pending = registry.pendingHydration.get(key);
@@ -4673,13 +4861,11 @@ function buildFreshState(key, schema, configuration, registry) {
4673
4861
  hydration: pending,
4674
4862
  ssr: registry.ssr,
4675
4863
  ...pickDefined({
4676
- strict: configuration.strict,
4677
4864
  validateOn: configuration.validateOn,
4678
4865
  debounceMs: configuration.debounceMs,
4679
4866
  rememberVariants: configuration.rememberVariants,
4680
4867
  disabled: configuration.disabled,
4681
4868
  coerce: configuration.coerce,
4682
- getDisplayState: configuration.getDisplayState,
4683
4869
  initialBlankPaths
4684
4870
  }),
4685
4871
  // Server-only: bind the SSR prefetch coordination handles. `enqueue`
@@ -4775,12 +4961,13 @@ function makeRegisterValueProxy(capturedRegisterValue) {
4775
4961
  get(_target, prop) {
4776
4962
  if (prop === "__v_isRef") return true;
4777
4963
  if (prop === "value") return capturedRegisterValue.value;
4964
+ if (prop === "isBound") return capturedRegisterValue.value !== void 0;
4778
4965
  const v = capturedRegisterValue.value;
4779
4966
  if (v === void 0) return void 0;
4780
4967
  return Reflect.get(v, prop);
4781
4968
  },
4782
4969
  has(_target, prop) {
4783
- if (prop === "__v_isRef" || prop === "value") return true;
4970
+ if (prop === "__v_isRef" || prop === "value" || prop === "isBound") return true;
4784
4971
  const v = capturedRegisterValue.value;
4785
4972
  if (v === void 0) return false;
4786
4973
  return Reflect.has(v, prop);
@@ -4801,7 +4988,7 @@ function makeRegisterValueProxy(capturedRegisterValue) {
4801
4988
  }
4802
4989
  });
4803
4990
  }
4804
- function useRegister() {
4991
+ function useRegister(options) {
4805
4992
  const instance = getCurrentInstance();
4806
4993
  if (instance === null) {
4807
4994
  return makeRegisterValueProxy(shallowRef(void 0));
@@ -4840,7 +5027,7 @@ function useRegister() {
4840
5027
  if (el !== null && el !== void 0 && typeof el === "object") {
4841
5028
  el[REGISTER_OWNER_MARKER] = true;
4842
5029
  }
4843
- if (capturedRegisterValue.value === void 0) ;
5030
+ if (capturedRegisterValue.value === void 0 && options?.optional !== true) ;
4844
5031
  });
4845
5032
  return makeRegisterValueProxy(capturedRegisterValue);
4846
5033
  }
@@ -4925,38 +5112,36 @@ function createWizardHistory(param) {
4925
5112
  };
4926
5113
  }
4927
5114
 
4928
- const NOOP_FINGERPRINT = "attaform:wizard-noop";
4929
5115
  const EMPTY_SLIM_KINDS = /* @__PURE__ */ new Set();
4930
- function buildNoopWizardSchema(formKey) {
4931
- const emptyValue = {};
4932
- const success = {
4933
- success: true,
4934
- data: emptyValue,
4935
- errors: void 0,
4936
- formKey
4937
- };
4938
- const defaultsResponse = {
4939
- success: true,
4940
- data: emptyValue,
4941
- errors: void 0,
4942
- formKey
4943
- };
4944
- return {
4945
- fingerprint: () => Promise.resolve(NOOP_FINGERPRINT),
4946
- 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,
4947
5127
  getDefaultAtPath: () => void 0,
4948
5128
  getEmptyValueAtPath: () => void 0,
4949
5129
  isPreprocessOrCoerceLeaf: () => false,
5130
+ isOpaqueLeafAtPath: () => false,
4950
5131
  arrayShapeAtPath: () => null,
4951
5132
  isFixedObjectAtPath: (path) => path.length === 0,
5133
+ // The noop schema declares no shape at all, so nothing under it is
5134
+ // addressable, root included.
5135
+ entryKeyKindAtPath: () => void 0,
4952
5136
  getSchemasAtPath: () => [],
4953
- validateAtPath: () => success,
5137
+ validateAtPath: () => NOOP_SUCCESS,
4954
5138
  getSlimPrimitiveTypesAtPath: () => new Set(EMPTY_SLIM_KINDS),
4955
5139
  isLeafAtPath: () => false,
4956
5140
  isRequiredAtPath: () => false,
4957
5141
  getUnionDiscriminatorAtPath: () => void 0,
4958
5142
  hasDiscriminatedUnions: () => false
4959
- };
5143
+ });
5144
+ return NOOP_SCHEMA;
4960
5145
  }
4961
5146
 
4962
5147
  function buildCallableReadonlySnapshotProxy(opts) {
@@ -5071,7 +5256,7 @@ function useWizard(options) {
5071
5256
  if (typeof slot !== "string") continue;
5072
5257
  if (noopForms.has(slot)) continue;
5073
5258
  const noop = useAbstractForm({
5074
- schema: buildNoopWizardSchema(slot),
5259
+ schema: buildNoopWizardSchema(),
5075
5260
  key: slot
5076
5261
  });
5077
5262
  noopForms.set(slot, noop);
@@ -5082,7 +5267,7 @@ function useWizard(options) {
5082
5267
  const noop = lazyNoopScope.run(
5083
5268
  () => useAbstractForm(
5084
5269
  {
5085
- schema: buildNoopWizardSchema(key),
5270
+ schema: buildNoopWizardSchema(),
5086
5271
  key
5087
5272
  },
5088
5273
  { registry }
@@ -5710,6 +5895,24 @@ function useWizard(options) {
5710
5895
  const target = list[idx + 1];
5711
5896
  moveTo(target.key);
5712
5897
  }
5898
+ let cancelDeferredAdvance = null;
5899
+ function advanceWhenInFlightSubmitLands(store, key) {
5900
+ cancelDeferredAdvance?.();
5901
+ const attemptsAtRequest = store.submissionAttempts.value;
5902
+ const off = store.onSubmitSuccess(() => {
5903
+ off();
5904
+ cancelDeferredAdvance = null;
5905
+ if (store.submissionAttempts.value !== attemptsAtRequest) return;
5906
+ if (activeKey.value !== key) return;
5907
+ advanceOne();
5908
+ });
5909
+ cancelDeferredAdvance = off;
5910
+ }
5911
+ function inFlightActiveStore() {
5912
+ const store = registry.forms.get(activeKey.value);
5913
+ if (store === void 0 || store.activeSubmissions.value === 0) return void 0;
5914
+ return store;
5915
+ }
5713
5916
  async function next() {
5714
5917
  if (submitting.value) {
5715
5918
  return;
@@ -5723,7 +5926,12 @@ function useWizard(options) {
5723
5926
  return;
5724
5927
  }
5725
5928
  const active = list[idx];
5726
- if (active !== void 0 && active.isGate) {
5929
+ if (active !== void 0 && active.isGate && !clearedGates.has(active.key)) {
5930
+ const inFlight = inFlightActiveStore();
5931
+ if (inFlight !== void 0) {
5932
+ advanceWhenInFlightSubmitLands(inFlight, activeKey.value);
5933
+ return;
5934
+ }
5727
5935
  await tryNext();
5728
5936
  return;
5729
5937
  }
@@ -5744,11 +5952,16 @@ function useWizard(options) {
5744
5952
  const form = activeForm.value;
5745
5953
  if (form === void 0) return false;
5746
5954
  const before = activeKey.value;
5955
+ const inFlight = inFlightActiveStore();
5956
+ if (inFlight !== void 0) {
5957
+ advanceWhenInFlightSubmitLands(inFlight, before);
5958
+ return false;
5959
+ }
5747
5960
  let ranClean = false;
5748
5961
  await asHandleSubmitSource(form).handleSubmit(() => {
5749
5962
  ranClean = true;
5750
5963
  })();
5751
- if (ranClean) advanceOne();
5964
+ if (ranClean && activeKey.value === before) advanceOne();
5752
5965
  return activeKey.value !== before;
5753
5966
  }
5754
5967
  function back() {
@@ -5988,6 +6201,7 @@ function useWizard(options) {
5988
6201
  onScopeDispose(() => {
5989
6202
  historyHandle.dispose();
5990
6203
  lazyNoopScope.stop();
6204
+ cancelDeferredAdvance?.();
5991
6205
  });
5992
6206
  }
5993
6207
  const explicitKey = options.key;
@@ -6137,4 +6351,4 @@ function escapeForInlineScript(json) {
6137
6351
  });
6138
6352
  }
6139
6353
 
6140
- 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, humanize as o, 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 };