attaform 0.28.0 → 0.29.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 (64) hide show
  1. package/dist/abstract.d.mts +5 -5
  2. package/dist/abstract.mjs +4 -4
  3. package/dist/chunks/fingerprint.mjs +1 -1
  4. package/dist/chunks/fingerprint2.mjs +2 -2
  5. package/dist/dev/abstract.mjs +4 -4
  6. package/dist/dev/chunks/devtools.mjs +1 -1
  7. package/dist/dev/chunks/fingerprint.mjs +1 -1
  8. package/dist/dev/chunks/fingerprint2.mjs +2 -2
  9. package/dist/dev/directive.mjs +1 -1
  10. package/dist/dev/history.mjs +1 -1
  11. package/dist/dev/index.mjs +5 -5
  12. package/dist/dev/runtime/plugins/attaform.mjs +1 -1
  13. package/dist/dev/shared/{attaform-dev.Dr2YzS5B.mjs → attaform-dev.A-TpJW0B.mjs} +11 -1
  14. package/dist/dev/shared/{attaform-dev.oYrkP9dj.mjs → attaform-dev.BO-71R54.mjs} +51 -158
  15. package/dist/dev/shared/{attaform-dev.6qxD-Yqo.mjs → attaform-dev.BgM6FdtA.mjs} +143 -36
  16. package/dist/{shared/attaform.h0i6LijT.mjs → dev/shared/attaform-dev.ButTkwHd.mjs} +149 -16
  17. package/dist/{shared/attaform.BJGA_UOS.mjs → dev/shared/attaform-dev.BxfsuwBR.mjs} +8 -0
  18. package/dist/dev/shared/{attaform-dev.P7cseiEG.mjs → attaform-dev.D8aoKb89.mjs} +13 -4
  19. package/dist/dev/shared/{attaform-dev.BXE2cr0L.mjs → attaform-dev.DD5m2W51.mjs} +1 -1
  20. package/dist/dev/shared/{attaform-dev.WmuhD_CZ.mjs → attaform-dev.DHuydLAC.mjs} +344 -96
  21. package/dist/dev/shared/{attaform-dev.BR8u0YOZ.mjs → attaform-dev.DrzObAZo.mjs} +4 -4
  22. package/dist/dev/shared/{attaform-dev.D2I8e_Mm.mjs → attaform-dev.q6UutkCx.mjs} +170 -132
  23. package/dist/dev/zod-v3.mjs +6 -6
  24. package/dist/dev/zod-v4.mjs +6 -6
  25. package/dist/dev/zod.mjs +5 -5
  26. package/dist/directive.d.mts +2 -2
  27. package/dist/directive.mjs +1 -1
  28. package/dist/history.d.mts +1 -1
  29. package/dist/history.mjs +1 -1
  30. package/dist/index.d.mts +9 -7
  31. package/dist/index.mjs +5 -5
  32. package/dist/nuxt.d.mts +10 -10
  33. package/dist/runtime/plugins/attaform.mjs +1 -1
  34. package/dist/shared/{attaform.C09fpdLS.mjs → attaform.B0dKL8ST.mjs} +143 -36
  35. package/dist/shared/{attaform.Cs2Rbdlo.mjs → attaform.BK0cgu2K.mjs} +123 -139
  36. package/dist/shared/{attaform.D6DCnnQu.mjs → attaform.BndjUUYX.mjs} +4 -4
  37. package/dist/{dev/shared/attaform-dev.BJGA_UOS.mjs → shared/attaform.BxfsuwBR.mjs} +8 -0
  38. package/dist/shared/{attaform.NLmerepI.mjs → attaform.C2MVyuxC.mjs} +42 -151
  39. package/dist/shared/{attaform.B4VkS43-.d.mts → attaform.CIWLMY-R.d.mts} +1 -1
  40. package/dist/shared/{attaform.B8k8JrmK.mjs → attaform.CZMAYwSK.mjs} +338 -95
  41. package/dist/shared/{attaform.wfY8XFvm.mjs → attaform.CZYt_5N_.mjs} +11 -1
  42. package/dist/shared/{attaform.Cgu-hdSb.d.mts → attaform.CsoeRi3P.d.mts} +224 -32
  43. package/dist/{dev/shared/attaform-dev.By4PRjt0.mjs → shared/attaform.Cvao8bW5.mjs} +132 -22
  44. package/dist/shared/{attaform.Dq4vWxuG.mjs → attaform.D0x-qSXm.mjs} +1 -1
  45. package/dist/shared/{attaform.CJP3RkGa.mjs → attaform.D1fnTifF.mjs} +168 -132
  46. package/dist/shared/{attaform.D5V4tZWq.d.mts → attaform.DDtqHYv1.d.mts} +88 -7
  47. package/dist/shared/{attaform.uLbun31C.mjs → attaform.DffRL5pP.mjs} +12 -4
  48. package/dist/shared/{attaform.JfSWdEcb.d.mts → attaform.axHXVQO7.d.mts} +1 -1
  49. package/dist/transforms.d.mts +0 -22
  50. package/dist/transforms.mjs +1 -1
  51. package/dist/vite.d.mts +13 -4
  52. package/dist/vite.mjs +3 -2
  53. package/dist/zod-v3.d.mts +6 -4
  54. package/dist/zod-v3.mjs +6 -6
  55. package/dist/zod-v4.d.mts +14 -27
  56. package/dist/zod-v4.mjs +6 -6
  57. package/dist/zod.d.mts +4 -4
  58. package/dist/zod.mjs +5 -5
  59. package/package.json +17 -14
  60. package/skills/attaform/SKILL.md +5 -2
  61. package/skills/attaform/references/custom-components.md +7 -2
  62. package/skills/attaform/references/errors.md +8 -3
  63. package/skills/attaform/references/saving.md +77 -0
  64. package/skills/attaform/references/wizards.md +10 -8
@@ -1,8 +1,8 @@
1
1
  import { computed, readonly, toRaw, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, nextTick, warn, reactive, shallowRef, toValue, watch, triggerRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, onBeforeMount, onBeforeUpdate, onMounted, effectScope } from 'vue';
2
- import { A as ANONYMOUS_FORM_KEY_PREFIX, i as isShadowedKey, 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-dev.By4PRjt0.mjs';
3
- import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform-dev.BXE2cr0L.mjs';
4
- import { R as REGISTER_OWNER_MARKER, d as armDomBinding, V as V_REGISTER_MARKER } from './attaform-dev.P7cseiEG.mjs';
5
- 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-dev.Dr2YzS5B.mjs';
2
+ import { A as ANONYMOUS_FORM_KEY_PREFIX, d as consumerHas, i as isShadowedKey, e as safeOwnHas, a as safeOwnRead, f as spreadConsumerRecord, g as copyConsumerArray, r as readConsumerIndex, b as safeAssign, h as consumerKeys, j as readConsumerProp, k as diffAndApply, p as pickDefined, s as structuralSnapshot, n as normalizeNumericOption, l as DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS, m as consumerSymbolKeys, o as applyChangedKeys, R as RESERVED_KEY_PREFIX, q as DEFAULT_MAX_RECURSION_DEPTH, t as ANONYMOUS_WIZARD_KEY_PREFIX } from './attaform-dev.ButTkwHd.mjs';
3
+ import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform-dev.DD5m2W51.mjs';
4
+ import { R as REGISTER_OWNER_MARKER, d as armDomBinding, V as V_REGISTER_MARKER } from './attaform-dev.D8aoKb89.mjs';
5
+ import { i as isPathPrefix, e as canonicalizePath, j as cellEntriesFor, s as segmentsForPathKey, k as keyForSegments, m as mapSegmentKeys, b as ROOT_PATH_KEY, S as SubmitErrorHandlerError, t as toError, l as groupErrorsByKey, n as normalizeErrorInput, h as SET_MEMBER_SEGMENT, R as ROOT_PATH, o as normalizeErrorInputs, q as coerceToPathKey, a as InvalidUseFormConfigError, d as ReservedFormKeyError } from './attaform-dev.A-TpJW0B.mjs';
6
6
 
7
7
  const AttaformErrorCode = {
8
8
  /** A required field is in the blank set — user hasn't supplied a value. */
@@ -77,6 +77,11 @@ function makeBlankRequiredError(segments) {
77
77
  }
78
78
  const NO_ERRORS = Object.freeze([]);
79
79
 
80
+ function crossCopyState(key, create) {
81
+ const carrier = globalThis;
82
+ return carrier[key] ?? (carrier[key] = create());
83
+ }
84
+
80
85
  function isGateOpen(field, formMeta) {
81
86
  return formMeta.submissionAttempts > 0 || field.blurredAfterInteraction === true;
82
87
  }
@@ -99,7 +104,10 @@ function earliestNonNull(a, b) {
99
104
  }
100
105
  const DEFAULT_TIMINGS = { showDelay: 120, minVisible: 120 };
101
106
  const FOCUS_OUT_GRACE = 16;
102
- const defaultFamily = /* @__PURE__ */ new WeakSet();
107
+ const defaultFamily = crossCopyState(
108
+ /* @__PURE__ */ Symbol.for("attaform:default-display-state-family"),
109
+ () => /* @__PURE__ */ new WeakSet()
110
+ );
103
111
  function isDefaultDisplayState(fn) {
104
112
  return defaultFamily.has(fn);
105
113
  }
@@ -186,6 +194,17 @@ function humanize(segment) {
186
194
  }
187
195
 
188
196
  const NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND");
197
+ function mapKeyForSegment(map, segment, declared) {
198
+ if (map.has(segment)) return segment;
199
+ if (typeof segment !== "number") return segment;
200
+ const asString = String(segment);
201
+ if (map.has(asString)) return asString;
202
+ return declared === "string" ? asString : segment;
203
+ }
204
+ function isRebuildableContainer(root, segment) {
205
+ if (root === null || root === void 0 || typeof root !== "object") return true;
206
+ return typeof segment === "number" ? Array.isArray(root) : isPlainRecord(root);
207
+ }
189
208
  function descendStep(value, segment) {
190
209
  if (value === null || value === void 0) return NOT_FOUND;
191
210
  if (typeof value !== "object") return NOT_FOUND;
@@ -194,6 +213,11 @@ function descendStep(value, segment) {
194
213
  if (!(segment in value)) return NOT_FOUND;
195
214
  return value[segment];
196
215
  }
216
+ if (value instanceof Map) {
217
+ const key2 = mapKeyForSegment(value, segment);
218
+ if (!value.has(key2)) return NOT_FOUND;
219
+ return value.get(key2);
220
+ }
197
221
  const record = value;
198
222
  const key = typeof segment === "number" ? String(segment) : segment;
199
223
  if (isShadowedKey(key)) {
@@ -226,11 +250,14 @@ function hasAtPath(root, path) {
226
250
  if (current === null || current === void 0) return false;
227
251
  if (typeof current !== "object") return false;
228
252
  if (Array.isArray(current)) {
229
- return typeof last === "number" && last in current;
253
+ return typeof last === "number" && consumerHas(current, last);
254
+ }
255
+ if (current instanceof Map) {
256
+ return current.has(mapKeyForSegment(current, last));
230
257
  }
231
258
  const key = typeof last === "number" ? String(last) : last;
232
259
  if (isShadowedKey(key)) return safeOwnHas(current, key);
233
- return key in current;
260
+ return consumerHas(current, key);
234
261
  }
235
262
  function isPlainRecord(value) {
236
263
  if (value === null || typeof value !== "object") return false;
@@ -245,6 +272,13 @@ function setAtPathOffset(root, path, value, offset) {
245
272
  if (offset >= path.length) return value;
246
273
  const head = path[offset];
247
274
  const nextOffset = offset + 1;
275
+ if (root instanceof Map) {
276
+ const next = new Map(root);
277
+ const key = mapKeyForSegment(root, head);
278
+ next.set(key, setAtPathOffset(root.get(key), path, value, nextOffset));
279
+ return next;
280
+ }
281
+ if (!isRebuildableContainer(root, head)) return root;
248
282
  if (typeof head === "number") {
249
283
  const arr = Array.isArray(root) ? [...root] : [];
250
284
  while (arr.length <= head) arr.push(void 0);
@@ -258,9 +292,17 @@ function setAtPathOffset(root, path, value, offset) {
258
292
  const NO_IN_PLACE = { applied: false };
259
293
  function tryInPlaceLeafWrite(root, path, value) {
260
294
  if (path.length === 0) return NO_IN_PLACE;
295
+ try {
296
+ return descendAndWrite(root, path, value);
297
+ } catch {
298
+ return NO_IN_PLACE;
299
+ }
300
+ }
301
+ function descendAndWrite(root, path, value) {
261
302
  let node = root;
262
303
  for (let i = 0; i < path.length; i++) {
263
304
  const seg = path[i];
305
+ if (node instanceof Map) return NO_IN_PLACE;
264
306
  if (Array.isArray(node)) {
265
307
  if (typeof seg !== "number" || seg < 0 || seg >= node.length) return NO_IN_PLACE;
266
308
  } else if (isPlainRecord(node)) {
@@ -295,17 +337,40 @@ function mergeStructuralImpl(schema, scratch, consumer, defaultValue) {
295
337
  if (Array.isArray(consumer)) {
296
338
  return mergeStructuralArray(schema, scratch, consumer);
297
339
  }
340
+ if (consumer instanceof Map) {
341
+ return mergeStructuralMap(schema, scratch, consumer);
342
+ }
298
343
  if (isPlainRecord(consumer)) {
299
344
  if (!isPlainRecord(defaultValue)) {
300
345
  return consumer;
301
346
  }
302
- const out = { ...consumer };
347
+ const out = spreadConsumerRecord(consumer);
303
348
  const filledAny = fillMissingKeysFromDefault(schema, scratch, consumer, defaultValue, out);
304
349
  const recursedAny = recurseIntoConsumerKeys(schema, scratch, consumer, defaultValue, out);
305
350
  return filledAny || recursedAny ? out : consumer;
306
351
  }
307
352
  return consumer;
308
353
  }
354
+ function mergeStructuralMap(schema, scratch, consumer) {
355
+ if (consumer.size === 0) return consumer;
356
+ let entryDefault;
357
+ let entryDefaultRead = false;
358
+ let out = null;
359
+ for (const [key, entry] of consumer) {
360
+ if (typeof key !== "string" && typeof key !== "number") continue;
361
+ scratch.push(key);
362
+ if (!entryDefaultRead) {
363
+ entryDefault = schema.getDefaultAtPath(scratch);
364
+ entryDefaultRead = true;
365
+ }
366
+ const merged = mergeStructuralImpl(schema, scratch, entry, entryDefault);
367
+ scratch.pop();
368
+ if (merged === entry) continue;
369
+ out ?? (out = new Map(consumer));
370
+ out.set(key, merged);
371
+ }
372
+ return out ?? consumer;
373
+ }
309
374
  function mergeStructuralArray(schema, scratch, consumer) {
310
375
  const shape = schema.arrayShapeAtPath(scratch);
311
376
  const isTuple = typeof shape === "number";
@@ -313,7 +378,7 @@ function mergeStructuralArray(schema, scratch, consumer) {
313
378
  let cachedElementDefault;
314
379
  let cachedElementDefaultRead = false;
315
380
  let mutated = targetLen > consumer.length;
316
- const out = consumer.slice();
381
+ const out = copyConsumerArray(consumer);
317
382
  while (out.length < targetLen) out.push(void 0);
318
383
  for (let i = 0; i < targetLen; i++) {
319
384
  scratch.push(i);
@@ -327,7 +392,7 @@ function mergeStructuralArray(schema, scratch, consumer) {
327
392
  }
328
393
  elemDefault = cachedElementDefault;
329
394
  }
330
- const consumerElem = i < consumer.length ? consumer[i] : void 0;
395
+ const consumerElem = i < consumer.length ? readConsumerIndex(consumer, i) : void 0;
331
396
  const merged = mergeStructuralImpl(schema, scratch, consumerElem, elemDefault);
332
397
  scratch.pop();
333
398
  if (merged !== consumerElem) {
@@ -355,7 +420,7 @@ function fillMissingKeysFromDefault(schema, scratch, consumer, defaultValue, out
355
420
  }
356
421
  function recurseIntoConsumerKeys(schema, scratch, consumer, defaultValue, out) {
357
422
  let mutated = false;
358
- for (const key of Object.keys(consumer)) {
423
+ for (const key of consumerKeys(consumer)) {
359
424
  const cVal = safeOwnRead(consumer, key);
360
425
  if (cVal === void 0) continue;
361
426
  scratch.push(key);
@@ -376,6 +441,21 @@ function setAtPathWithSchemaFillImpl(root, schema, fullPath, value, startIdx) {
376
441
  if (startIdx >= fullPath.length) return value;
377
442
  const head = fullPath[startIdx];
378
443
  const isLeafStep = startIdx === fullPath.length - 1;
444
+ if (root instanceof Map) {
445
+ const next = new Map(root);
446
+ const key = mapKeyForSegment(root, head, schema.entryKeyKindAtPath(fullPath.slice(0, startIdx)));
447
+ if (isLeafStep) {
448
+ next.set(key, value);
449
+ return next;
450
+ }
451
+ let childRoot2 = next.get(key);
452
+ if (childRoot2 === void 0 || childRoot2 !== null && typeof childRoot2 !== "object") {
453
+ childRoot2 = schema.getDefaultAtPath(fullPath.slice(0, startIdx + 1));
454
+ }
455
+ next.set(key, setAtPathWithSchemaFillImpl(childRoot2, schema, fullPath, value, startIdx + 1));
456
+ return next;
457
+ }
458
+ if (!isRebuildableContainer(root, head)) return root;
379
459
  if (typeof head === "number") {
380
460
  const arr = Array.isArray(root) ? [...root] : [];
381
461
  const prefix = fullPath.slice(0, startIdx);
@@ -443,9 +523,10 @@ function isUnderStubAncestor(state, segments) {
443
523
  }
444
524
  return false;
445
525
  }
446
- function buildFieldStateAccessor(state, formInstanceId, getFormMetaBase, options) {
526
+ function buildFieldStateAccessor(state, formInstanceId, getFormMetaBase, sweep, options) {
447
527
  const cache = /* @__PURE__ */ new Map();
448
528
  const predicate = options?.getDisplayState;
529
+ sweep.onEvict((key) => cache.delete(key));
449
530
  return function getFieldState(pathInput) {
450
531
  const { segments, key } = canonicalizePath(pathInput);
451
532
  const cached = cache.get(key);
@@ -454,6 +535,7 @@ function buildFieldStateAccessor(state, formInstanceId, getFormMetaBase, options
454
535
  () => state.schema.isLeafAtPath(segments) ? buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase, predicate) : buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase, predicate)
455
536
  );
456
537
  cache.set(key, c);
538
+ sweep.track(segments, key);
457
539
  return c;
458
540
  };
459
541
  }
@@ -543,7 +625,7 @@ function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBa
543
625
  function visitActiveLeafPaths(value, base, visit) {
544
626
  if (Array.isArray(value)) {
545
627
  for (let i = 0; i < value.length; i++) {
546
- const child = value[i];
628
+ const child = readConsumerIndex(value, i);
547
629
  if (Array.isArray(child) || isPlainRecord(child)) {
548
630
  visitActiveLeafPaths(child, [...base, i], visit);
549
631
  } else {
@@ -553,8 +635,8 @@ function visitActiveLeafPaths(value, base, visit) {
553
635
  return;
554
636
  }
555
637
  if (isPlainRecord(value)) {
556
- for (const k of Object.keys(value)) {
557
- const child = value[k];
638
+ for (const k of consumerKeys(value)) {
639
+ const child = readConsumerProp(value, k);
558
640
  if (Array.isArray(child) || isPlainRecord(child)) {
559
641
  visitActiveLeafPaths(child, [...base, k], visit);
560
642
  } else {
@@ -803,6 +885,10 @@ function liveKeysAtPath(state, segments) {
803
885
  for (let i = 0; i < value.length; i += 1) keys[i] = String(i);
804
886
  return keys;
805
887
  }
888
+ if (value instanceof Map) {
889
+ return mapSegmentKeys(value)?.map(String) ?? [];
890
+ }
891
+ if (value instanceof Set) return [];
806
892
  if (typeof value === "object") return Object.keys(value);
807
893
  return [];
808
894
  }
@@ -813,6 +899,12 @@ function liveContainerHasKey(state, segments, key) {
813
899
  const index = Number(key);
814
900
  return Number.isInteger(index) && index >= 0 && index < value.length && String(index) === key;
815
901
  }
902
+ if (value instanceof Map) {
903
+ if (value.has(key)) return true;
904
+ const index = Number(key);
905
+ return Number.isInteger(index) && index >= 0 && String(index) === key && value.has(index);
906
+ }
907
+ if (value instanceof Set) return false;
816
908
  return Object.hasOwn(value, key);
817
909
  }
818
910
  function isArrayPath(state, segments) {
@@ -839,6 +931,7 @@ function makeReadonlyCoercion(snapshot) {
839
931
  }
840
932
 
841
933
  const INTEGER_SEGMENT = /^(?:0|[1-9]\d*)$/;
934
+ const RELEASED = /* @__PURE__ */ Symbol();
842
935
  const EMPTY_DESCENT = Object.freeze({});
843
936
  function keyToSegment(key) {
844
937
  return INTEGER_SEGMENT.test(key) ? Number(key) : key;
@@ -868,12 +961,18 @@ function callableInvokeShim(method, surface, getDescent) {
868
961
  function buildTree(spec) {
869
962
  const containerCache = /* @__PURE__ */ new Map();
870
963
  const existsCache = /* @__PURE__ */ new Map();
964
+ spec.sweep.onEvict((key) => {
965
+ containerCache.delete(`${key}+A`);
966
+ containerCache.delete(`${key}+O`);
967
+ existsCache.delete(key);
968
+ });
871
969
  function schemaHasPath(segs) {
872
970
  const cacheKey = JSON.stringify(segs);
873
971
  const cached = existsCache.get(cacheKey);
874
972
  if (cached !== void 0) return cached;
875
973
  const result = spec.schema.getSlimPrimitiveTypesAtPath(segs).size > 0;
876
974
  existsCache.set(cacheKey, result);
975
+ spec.sweep.track(segs, cacheKey);
877
976
  return result;
878
977
  }
879
978
  function descend(segs) {
@@ -883,7 +982,8 @@ function buildTree(spec) {
883
982
  }
884
983
  function containerAt(segments) {
885
984
  const isArrayLike = spec.isArrayAt(segments);
886
- const cacheKey = `${JSON.stringify(segments)}+${isArrayLike ? "A" : "O"}`;
985
+ const pathKey = JSON.stringify(segments);
986
+ const cacheKey = `${pathKey}+${isArrayLike ? "A" : "O"}`;
887
987
  const existing = containerCache.get(cacheKey);
888
988
  if (existing !== void 0) return existing;
889
989
  const isFixedObject = spec.schema.isFixedObjectAtPath(segments);
@@ -973,12 +1073,14 @@ function buildTree(spec) {
973
1073
  }
974
1074
  });
975
1075
  containerCache.set(cacheKey, proxy);
1076
+ spec.sweep.track(segments, pathKey);
976
1077
  return proxy;
977
1078
  }
978
1079
  return containerAt([]);
979
1080
  }
980
- function buildErrorsSurface(state) {
1081
+ function buildErrorsSurface(state, sweep) {
981
1082
  const treeCache = /* @__PURE__ */ new Map();
1083
+ sweep.onEvict((key) => treeCache.delete(key));
982
1084
  const materialize = (segments) => {
983
1085
  const cacheKey = JSON.stringify(segments);
984
1086
  let tree = treeCache.get(cacheKey);
@@ -986,6 +1088,7 @@ function buildErrorsSurface(state) {
986
1088
  const frozen = [...segments];
987
1089
  tree = computed(() => materializeErrors(state, frozen));
988
1090
  treeCache.set(cacheKey, tree);
1091
+ sweep.track(segments, cacheKey);
989
1092
  }
990
1093
  return tree.value;
991
1094
  };
@@ -1031,7 +1134,8 @@ function buildErrorsSurface(state) {
1031
1134
  // aggregate — the same helper `meta.errors` reads, so the surfaces
1032
1135
  // never drift.
1033
1136
  call: (path) => aggregateErrorsAt(state, path),
1034
- surface: "form.errors"
1137
+ surface: "form.errors",
1138
+ sweep
1035
1139
  });
1036
1140
  }
1037
1141
  function errorAwareContainerKeys(state, segments) {
@@ -1150,7 +1254,7 @@ const FIELD_STATE_KEYS = /* @__PURE__ */ new Set([
1150
1254
  "placeholder",
1151
1255
  "meta"
1152
1256
  ]);
1153
- function buildFieldsSurface(state, getFieldStateAt) {
1257
+ function buildFieldsSurface(state, getFieldStateAt, sweep) {
1154
1258
  const snapshotAt = (segments) => {
1155
1259
  const view = getFieldStateAt(segments).value;
1156
1260
  const snapshot = {};
@@ -1158,6 +1262,7 @@ function buildFieldsSurface(state, getFieldStateAt) {
1158
1262
  return snapshot;
1159
1263
  };
1160
1264
  const viewCache = /* @__PURE__ */ new Map();
1265
+ sweep.onEvict((key) => viewCache.delete(key));
1161
1266
  function viewAt(segments) {
1162
1267
  const cacheKey = JSON.stringify(segments);
1163
1268
  const existing = viewCache.get(cacheKey);
@@ -1212,6 +1317,7 @@ function buildFieldsSurface(state, getFieldStateAt) {
1212
1317
  }
1213
1318
  });
1214
1319
  viewCache.set(cacheKey, proxy);
1320
+ sweep.track(segments, cacheKey);
1215
1321
  return proxy;
1216
1322
  }
1217
1323
  return buildTree({
@@ -1226,7 +1332,8 @@ function buildFieldsSurface(state, getFieldStateAt) {
1226
1332
  // container's rollup); a path the schema doesn't have is a typo and
1227
1333
  // reads `undefined`. The root (`fields()`) is always declared.
1228
1334
  call: (path) => state.schema.getSlimPrimitiveTypesAtPath(path).size > 0 ? viewAt(path) : void 0,
1229
- surface: "form.fields"
1335
+ surface: "form.fields",
1336
+ sweep
1230
1337
  });
1231
1338
  }
1232
1339
  function materializeFields(state, containerSegments, snapshotAt) {
@@ -1260,18 +1367,34 @@ function materializeFormValue(node) {
1260
1367
  }
1261
1368
  return out;
1262
1369
  }
1263
- function buildValuesSurface(form) {
1370
+ function buildValuesSurface(form, onFormChange) {
1264
1371
  const inner = computed(() => readonly(form.value));
1265
- const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(
1266
- () => materializeFormValue(inner.value)
1267
- );
1372
+ let held = null;
1373
+ const snapshot = computed(() => {
1374
+ const box = { value: materializeFormValue(inner.value) };
1375
+ held = box;
1376
+ return box;
1377
+ });
1378
+ onFormChange(() => {
1379
+ if (held === null) return;
1380
+ held.value = RELEASED;
1381
+ held = null;
1382
+ });
1383
+ const readSnapshot = () => {
1384
+ const box = snapshot.value;
1385
+ return box.value === RELEASED ? materializeFormValue(inner.value) : box.value;
1386
+ };
1387
+ const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(() => readSnapshot());
1268
1388
  const target = (() => {
1269
1389
  });
1270
1390
  return new Proxy(target, {
1271
1391
  apply(_, __, args) {
1272
1392
  const arg = args[0];
1273
- if (arg === void 0) return inner.value;
1274
- return getAtPath(inner.value, canonicalizePath(arg).segments);
1393
+ if (arg === void 0) return readSnapshot();
1394
+ const segments = canonicalizePath(arg).segments;
1395
+ const node = getAtPath(inner.value, segments);
1396
+ if (node === null || typeof node !== "object") return node;
1397
+ return getAtPath(readSnapshot(), segments);
1275
1398
  },
1276
1399
  get(_, key) {
1277
1400
  if (typeof key === "symbol") {
@@ -1556,9 +1679,12 @@ function cloneVariantSnapshot(value) {
1556
1679
  for (let i = 0; i < raw.length; i++) out2[i] = cloneVariantSnapshot(raw[i]);
1557
1680
  return out2;
1558
1681
  }
1682
+ if (!isPlainRecord(raw)) return raw;
1559
1683
  const src = raw;
1560
1684
  const out = {};
1561
- for (const k of Object.keys(src)) safeAssign(out, k, cloneVariantSnapshot(src[k]));
1685
+ for (const k of consumerKeys(src)) {
1686
+ safeAssign(out, k, cloneVariantSnapshot(readConsumerProp(src, k)));
1687
+ }
1562
1688
  return out;
1563
1689
  }
1564
1690
  function createArrayBookkeeping(deps) {
@@ -1706,6 +1832,45 @@ function buildFieldArrayApi(state) {
1706
1832
  };
1707
1833
  }
1708
1834
 
1835
+ const SWEEP_SLICE = 8;
1836
+ function createDynamicPathSweep(state) {
1837
+ const dynamicKeys = /* @__PURE__ */ new Set();
1838
+ const evictors = [];
1839
+ const isDynamicPath = (segments) => {
1840
+ for (let i = 0; i < segments.length; i++) {
1841
+ if (typeof segments[i] === "number") return true;
1842
+ if (!state.schema.isFixedObjectAtPath(segments.slice(0, i))) return true;
1843
+ }
1844
+ return false;
1845
+ };
1846
+ let sweepCursor = null;
1847
+ state.onFormChange((next) => {
1848
+ if (dynamicKeys.size === 0) return;
1849
+ const raw = toRaw(next);
1850
+ for (let i = 0; i < SWEEP_SLICE; i++) {
1851
+ sweepCursor ?? (sweepCursor = dynamicKeys.values());
1852
+ const step = sweepCursor.next();
1853
+ if (step.done === true) {
1854
+ sweepCursor = null;
1855
+ break;
1856
+ }
1857
+ const segments = segmentsForPathKey(step.value);
1858
+ if (segments !== null && hasAtPath(raw, segments)) continue;
1859
+ dynamicKeys.delete(step.value);
1860
+ for (const evict of evictors) evict(step.value);
1861
+ }
1862
+ });
1863
+ return {
1864
+ track(segments, key) {
1865
+ if (dynamicKeys.has(key)) return;
1866
+ if (isDynamicPath(segments)) dynamicKeys.add(key);
1867
+ },
1868
+ onEvict(evict) {
1869
+ evictors.push(evict);
1870
+ }
1871
+ };
1872
+ }
1873
+
1709
1874
  const warnedNoScopeStores = /* @__PURE__ */ new WeakSet() ;
1710
1875
  function isErrorInputLike(value) {
1711
1876
  if (value instanceof Error) return true;
@@ -1853,6 +2018,11 @@ function buildProcessForm(state, formInstanceId, options = {}) {
1853
2018
  event.preventDefault();
1854
2019
  }
1855
2020
  if (state.activeSubmissions.value > 0) {
2021
+ if (event === void 0) {
2022
+ console.warn(
2023
+ `[attaform] handleSubmit: a submit is already in flight on form "${String(state.formKey)}", so this call was ignored; its callback never ran. Await the first submit before starting another, or move the work into that submit's callback.`
2024
+ );
2025
+ }
1856
2026
  return;
1857
2027
  }
1858
2028
  const genAtEntry = state.submissionGeneration.value;
@@ -2039,15 +2209,16 @@ function walk(schema, store, path, value) {
2039
2209
  reportRejection(store, path, kind, accepted);
2040
2210
  return false;
2041
2211
  }
2212
+ if (schema.isOpaqueLeafAtPath(path)) return true;
2042
2213
  if (Array.isArray(value)) {
2043
2214
  for (let i = 0; i < value.length; i++) {
2044
- if (!walk(schema, store, [...path, i], value[i])) return false;
2215
+ if (!walk(schema, store, [...path, i], readConsumerIndex(value, i))) return false;
2045
2216
  }
2046
2217
  return true;
2047
2218
  }
2048
2219
  if (isPlainRecord(value)) {
2049
- for (const key of Object.keys(value)) {
2050
- if (!walk(schema, store, [...path, key], value[key])) {
2220
+ for (const key of consumerKeys(value)) {
2221
+ if (!walk(schema, store, [...path, key], readConsumerProp(value, key))) {
2051
2222
  return false;
2052
2223
  }
2053
2224
  }
@@ -2142,19 +2313,26 @@ function indexRules(rules) {
2142
2313
  }
2143
2314
  return idx;
2144
2315
  }
2316
+ function memberSlimTypes(schema, segments, accepted) {
2317
+ if (accepted.has("array")) return schema.getSlimPrimitiveTypesAtPath([...segments, 0]);
2318
+ if (accepted.has("set")) {
2319
+ return schema.getSlimPrimitiveTypesAtPath([...segments, SET_MEMBER_SEGMENT]);
2320
+ }
2321
+ return void 0;
2322
+ }
2145
2323
  function buildCoerceFn(schema, segments, index) {
2146
2324
  if (index === EMPTY_INDEX) return IDENTITY;
2147
2325
  if (index.size === 0) return IDENTITY;
2148
2326
  const accepted = schema.getSlimPrimitiveTypesAtPath(segments);
2149
- const elementAccepted = accepted.has("array") || accepted.has("set") ? schema.getSlimPrimitiveTypesAtPath([...segments, 0]) : void 0;
2327
+ const elementAccepted = memberSlimTypes(schema, segments, accepted);
2150
2328
  return (value) => coerceValue(value, accepted, elementAccepted, index);
2151
2329
  }
2152
2330
  function buildElementCoerceFn(schema, segments, index) {
2153
2331
  if (index === EMPTY_INDEX) return void 0;
2154
2332
  if (index.size === 0) return void 0;
2155
2333
  const accepted = schema.getSlimPrimitiveTypesAtPath(segments);
2156
- if (!accepted.has("array") && !accepted.has("set")) return void 0;
2157
- const elementAccepted = schema.getSlimPrimitiveTypesAtPath([...segments, 0]);
2334
+ const elementAccepted = memberSlimTypes(schema, segments, accepted);
2335
+ if (elementAccepted === void 0) return void 0;
2158
2336
  return (value) => coerceScalar(value, elementAccepted, index);
2159
2337
  }
2160
2338
  function pickScalarTarget(accepted) {
@@ -2445,8 +2623,8 @@ function walkUnsetSentinels(values, schema) {
2445
2623
  const cleaned = walkCore(values, [], schema, paths, true);
2446
2624
  return { cleanedValues: cleaned, paths };
2447
2625
  }
2448
- function isOpaqueLeaf(value) {
2449
- return value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || typeof value === "function";
2626
+ function isRecursable(value) {
2627
+ return Array.isArray(value) || isPlainRecord(value);
2450
2628
  }
2451
2629
  function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2452
2630
  if (isUnset(input)) {
@@ -2460,20 +2638,21 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2460
2638
  return input;
2461
2639
  }
2462
2640
  if (input === null) return null;
2463
- if (isOpaqueLeaf(input)) return input;
2641
+ if (!isRecursable(input)) return input;
2464
2642
  if (Array.isArray(input)) {
2465
2643
  const out = new Array(input.length);
2466
2644
  let mutated = false;
2467
2645
  for (let i = 0; i < input.length; i++) {
2468
- const walked = walkCore(input[i], [...segments, i], schema, paths, synthesizeSchemaKeys);
2646
+ const original = readConsumerIndex(input, i);
2647
+ const walked = walkCore(original, [...segments, i], schema, paths, synthesizeSchemaKeys);
2469
2648
  out[i] = walked;
2470
- if (walked !== input[i]) mutated = true;
2649
+ if (walked !== original) mutated = true;
2471
2650
  }
2472
2651
  return mutated ? out : input;
2473
2652
  }
2474
2653
  if (typeof input === "object") {
2475
2654
  const obj = input;
2476
- const inputKeys = Object.keys(obj);
2655
+ const inputKeys = consumerKeys(obj);
2477
2656
  let keys = inputKeys;
2478
2657
  let mutated = false;
2479
2658
  let inputKeysSet = null;
@@ -2481,7 +2660,7 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2481
2660
  inputKeysSet = new Set(inputKeys);
2482
2661
  const allKeys = new Set(inputKeys);
2483
2662
  const slim = schema.getDefaultAtPath(segments);
2484
- if (slim !== null && slim !== void 0 && typeof slim === "object" && !Array.isArray(slim) && !isOpaqueLeaf(slim)) {
2663
+ if (isPlainRecord(slim)) {
2485
2664
  for (const k of Object.keys(slim)) allKeys.add(k);
2486
2665
  }
2487
2666
  keys = allKeys;
@@ -2489,7 +2668,7 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2489
2668
  }
2490
2669
  const out = {};
2491
2670
  for (const key of keys) {
2492
- const orig = obj[key];
2671
+ const orig = readConsumerProp(obj, key);
2493
2672
  if (synthesizeSchemaKeys && orig === void 0 && inputKeysSet?.has(key) === true) {
2494
2673
  safeAssign(out, key, void 0);
2495
2674
  mutated = true;
@@ -2510,22 +2689,12 @@ function walkUnspecified(slim, segments, paths) {
2510
2689
  }
2511
2690
  return slim;
2512
2691
  }
2513
- if (isOpaqueLeaf(slim)) {
2514
- return slim;
2515
- }
2516
- if (Array.isArray(slim)) return slim;
2517
- if (slim !== null && typeof slim === "object") {
2518
- const out = {};
2519
- for (const key of Object.keys(slim)) {
2520
- safeAssign(
2521
- out,
2522
- key,
2523
- walkUnspecified(slim[key], [...segments, key], paths)
2524
- );
2525
- }
2526
- return out;
2692
+ if (!isPlainRecord(slim)) return slim;
2693
+ const out = {};
2694
+ for (const key of Object.keys(slim)) {
2695
+ safeAssign(out, key, walkUnspecified(slim[key], [...segments, key], paths));
2527
2696
  }
2528
- return slim;
2697
+ return out;
2529
2698
  }
2530
2699
  function substituteUnsetSentinels(value, prefix, schema) {
2531
2700
  const paths = [];
@@ -2561,11 +2730,11 @@ function expandUnsetAt(segments, schema, paths) {
2561
2730
  paths.push(canonicalizePath(segments).key);
2562
2731
  return slim;
2563
2732
  }
2564
- if (isOpaqueLeaf(slim)) {
2733
+ if (Array.isArray(slim)) return slim;
2734
+ if (!isPlainRecord(slim)) {
2565
2735
  paths.push(canonicalizePath(segments).key);
2566
2736
  return slim;
2567
2737
  }
2568
- if (Array.isArray(slim)) return slim;
2569
2738
  const result = {};
2570
2739
  for (const key of Object.keys(slim)) {
2571
2740
  result[key] = expandUnsetAt([...segments, key], schema, paths);
@@ -2575,14 +2744,14 @@ function expandUnsetAt(segments, schema, paths) {
2575
2744
  function walkAuthoredFromConstraints(value, prefix, out) {
2576
2745
  if (prefix.length > 0) out.add(canonicalizePath(prefix).key);
2577
2746
  if (isPlainRecord(value)) {
2578
- for (const k of Object.keys(value)) {
2579
- walkAuthoredFromConstraints(value[k], [...prefix, k], out);
2747
+ for (const k of consumerKeys(value)) {
2748
+ walkAuthoredFromConstraints(readConsumerProp(value, k), [...prefix, k], out);
2580
2749
  }
2581
2750
  return;
2582
2751
  }
2583
2752
  if (Array.isArray(value)) {
2584
2753
  for (let i = 0; i < value.length; i++) {
2585
- walkAuthoredFromConstraints(value[i], [...prefix, i], out);
2754
+ walkAuthoredFromConstraints(readConsumerIndex(value, i), [...prefix, i], out);
2586
2755
  }
2587
2756
  }
2588
2757
  }
@@ -2662,10 +2831,12 @@ function buildFormApi(state, formInstanceId, options = {}) {
2662
2831
  return metaBase;
2663
2832
  };
2664
2833
  const fieldStateAccessorOptions = options.getDisplayState !== void 0 ? { getDisplayState: options.getDisplayState } : void 0;
2834
+ const pathSweep = createDynamicPathSweep(state);
2665
2835
  const getRootFieldStateAt = buildFieldStateAccessor(
2666
2836
  state,
2667
2837
  formInstanceId,
2668
2838
  getFormMetaBase,
2839
+ pathSweep,
2669
2840
  fieldStateAccessorOptions
2670
2841
  );
2671
2842
  const getDisplayStateAt = (segments) => getRootFieldStateAt(segments).value.displayState;
@@ -2692,6 +2863,10 @@ function buildFormApi(state, formInstanceId, options = {}) {
2692
2863
  const segments = canonicalizePath(pathInput).segments;
2693
2864
  return computed(() => getAtPath(state.form.value, segments));
2694
2865
  }
2866
+ function pathStoresFunctions(segments) {
2867
+ if (state.schema.isOpaqueLeafAtPath(segments)) return false;
2868
+ return state.schema.getSlimPrimitiveTypesAtPath(segments).has("function");
2869
+ }
2695
2870
  function setValueImpl(pathOrValue, maybeValue) {
2696
2871
  const argc = arguments.length;
2697
2872
  const isPathForm = argc >= 2 && (typeof pathOrValue === "string" || Array.isArray(pathOrValue));
@@ -2744,7 +2919,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2744
2919
  };
2745
2920
  if (isUnset(maybeValue)) return writeUnsetAt();
2746
2921
  let resolvedValue;
2747
- if (typeof maybeValue === "function") {
2922
+ if (typeof maybeValue === "function" && !pathStoresFunctions(segments)) {
2748
2923
  const current = state.getValueAtPath(segments);
2749
2924
  const prev = current === void 0 ? state.schema.getDefaultAtPath(segments) : current;
2750
2925
  resolvedValue = maybeValue(prev);
@@ -2762,7 +2937,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2762
2937
  reMarkBlanksAfterSubstitution(walked.paths);
2763
2938
  return true;
2764
2939
  }
2765
- const errorsProxy = buildErrorsSurface(state);
2940
+ const errorsProxy = buildErrorsSurface(state, pathSweep);
2766
2941
  function flattenUserErrors() {
2767
2942
  const all = [];
2768
2943
  for (const cell of state.errorCells.values()) all.push(...cell.user);
@@ -2861,8 +3036,9 @@ function buildFormApi(state, formInstanceId, options = {}) {
2861
3036
  if (nextDefaultValues === void 0) {
2862
3037
  state.reset();
2863
3038
  } else {
2864
- const walked = walkUnsetSentinels(
3039
+ const walked = substituteUnsetSentinels(
2865
3040
  nextDefaultValues,
3041
+ [],
2866
3042
  state.schema
2867
3043
  );
2868
3044
  state.reset(walked.cleanedValues);
@@ -2936,8 +3112,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
2936
3112
  };
2937
3113
  return Object.freeze(view);
2938
3114
  });
2939
- const valuesProxy = buildValuesSurface(state.form);
2940
- const fieldStateProxy = buildFieldsSurface(state, getRootFieldStateAt);
3115
+ const valuesProxy = buildValuesSurface(state.form, state.onFormChange);
3116
+ const fieldStateProxy = buildFieldsSurface(state, getRootFieldStateAt, pathSweep);
2941
3117
  const needsLazyGate = state.defaultValuesFactory.value !== void 0 || state.hasSsrPrefetch;
2942
3118
  function gated(fn) {
2943
3119
  if (!needsLazyGate) return fn;
@@ -3085,6 +3261,12 @@ function shortenSourceFrame(frame) {
3085
3261
 
3086
3262
  const IDLE = Object.freeze({ display: "idle" });
3087
3263
  const MAX_DELAY = 2147483647;
3264
+ const PENDING_LIVENESS_MS = 250;
3265
+ function withLiveness(machine, now) {
3266
+ if (machine.display !== "pending") return machine;
3267
+ if (machine.reviewAt !== void 0 && Number.isFinite(machine.reviewAt)) return machine;
3268
+ return { ...machine, reviewAt: now + PENDING_LIVENESS_MS };
3269
+ }
3088
3270
  function createDisplayEngine(ssr) {
3089
3271
  const machines = /* @__PURE__ */ new Map();
3090
3272
  const tick = ref(0);
@@ -3113,7 +3295,7 @@ function createDisplayEngine(ssr) {
3113
3295
  return;
3114
3296
  }
3115
3297
  if (timer !== null && timerTarget === target) return;
3116
- if (target === lastFiredTarget) {
3298
+ if (target === lastFiredTarget && target <= now) {
3117
3299
  clearTimer();
3118
3300
  return;
3119
3301
  }
@@ -3132,8 +3314,9 @@ function createDisplayEngine(ssr) {
3132
3314
  function resolve(key, ctx, reducer) {
3133
3315
  void tick.value;
3134
3316
  const prev = machines.get(key) ?? IDLE;
3135
- const machine = reducer(prev, ctx);
3136
- if (ssr) return machine;
3317
+ const reduced = reducer(prev, ctx);
3318
+ if (ssr) return reduced;
3319
+ const machine = withLiveness(reduced, ctx.now);
3137
3320
  const active = machine.display !== "idle" || machine.reviewAt !== void 0 && Number.isFinite(machine.reviewAt);
3138
3321
  if (active) machines.set(key, machine);
3139
3322
  else machines.delete(key);
@@ -3230,6 +3413,7 @@ async function runFactoryAndApply(st, factory) {
3230
3413
  st.schema
3231
3414
  );
3232
3415
  st.applyFormReplacement(full, { hydration: true });
3416
+ st.adoptResolvedDefaults(value);
3233
3417
  st.scheduleFieldValidation(
3234
3418
  [],
3235
3419
  true
@@ -3314,12 +3498,10 @@ function applyDuStubs(schema, data, options = {}) {
3314
3498
  }
3315
3499
  function walkDuStubs(schema, value, path, warned) {
3316
3500
  if (value === null || value === void 0 || typeof value !== "object") return value;
3317
- if (value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || typeof value === "function") {
3318
- return value;
3319
- }
3320
3501
  if (Array.isArray(value)) {
3321
3502
  return value.map((item, i) => walkDuStubs(schema, item, [...path, i], warned));
3322
3503
  }
3504
+ if (!isPlainRecord(value)) return value;
3323
3505
  const rec = value;
3324
3506
  const du = schema.getUnionDiscriminatorAtPath(path);
3325
3507
  if (du !== void 0) {
@@ -3342,8 +3524,8 @@ function walkDuStubs(schema, value, path, warned) {
3342
3524
  }
3343
3525
  }
3344
3526
  const out = {};
3345
- for (const k of Object.keys(rec)) {
3346
- safeAssign(out, k, walkDuStubs(schema, rec[k], [...path, k], warned));
3527
+ for (const k of consumerKeys(rec)) {
3528
+ safeAssign(out, k, walkDuStubs(schema, readConsumerProp(rec, k), [...path, k], warned));
3347
3529
  }
3348
3530
  return out;
3349
3531
  }
@@ -3353,23 +3535,25 @@ function stripSymbolsDeep(value) {
3353
3535
  let mutated2 = false;
3354
3536
  const out2 = new Array(value.length);
3355
3537
  for (let i = 0; i < value.length; i++) {
3356
- const cleaned = stripSymbolsDeep(value[i]);
3538
+ const original = readConsumerIndex(value, i);
3539
+ const cleaned = stripSymbolsDeep(original);
3357
3540
  out2[i] = cleaned;
3358
- if (cleaned !== value[i]) mutated2 = true;
3541
+ if (cleaned !== original) mutated2 = true;
3359
3542
  }
3360
3543
  return mutated2 ? out2 : value;
3361
3544
  }
3362
3545
  const proto = Object.getPrototypeOf(value);
3363
3546
  if (proto !== Object.prototype && proto !== null) return value;
3364
- const symKeys = Object.getOwnPropertySymbols(value);
3365
- const stringKeys = Object.keys(value);
3547
+ const symKeys = consumerSymbolKeys(value);
3548
+ const stringKeys = consumerKeys(value);
3366
3549
  let mutated = symKeys.length > 0;
3367
3550
  const out = {};
3368
3551
  const src = value;
3369
3552
  for (const k of stringKeys) {
3370
- const cleaned = stripSymbolsDeep(src[k]);
3553
+ const original = readConsumerProp(src, k);
3554
+ const cleaned = stripSymbolsDeep(original);
3371
3555
  out[k] = cleaned;
3372
- if (cleaned !== src[k]) mutated = true;
3556
+ if (cleaned !== original) mutated = true;
3373
3557
  }
3374
3558
  return mutated ? out : value;
3375
3559
  }
@@ -4290,8 +4474,27 @@ function activate(st) {
4290
4474
  if (factory === void 0) return Promise.resolve();
4291
4475
  return fireFactory(st, factory);
4292
4476
  }
4477
+ function adoptResolvedDefaults(st, value) {
4478
+ st.defaultValues = structuralSnapshot(
4479
+ mergeSparseHydration(
4480
+ st.defaultValues,
4481
+ value,
4482
+ st.schema
4483
+ )
4484
+ );
4485
+ seedOriginalsFromBaseline(
4486
+ st,
4487
+ computeBaselineResponse(st.schema, st.strict, st.defaultValues).data,
4488
+ false
4489
+ );
4490
+ }
4293
4491
  function reset(st, nextDefaultValues) {
4294
- const resetSource = nextDefaultValues ?? st.defaultValues;
4492
+ const resetSource = nextDefaultValues === void 0 ? st.defaultValues : mergeSparseHydration(
4493
+ st.defaultValues,
4494
+ nextDefaultValues,
4495
+ st.schema
4496
+ );
4497
+ st.defaultValues = structuralSnapshot(resetSource);
4295
4498
  const resetResponse = computeBaselineResponse(st.schema, st.strict, resetSource);
4296
4499
  const next = resetResponse.data;
4297
4500
  rebuildAuthoredPaths(st, resetSource, next);
@@ -4300,13 +4503,13 @@ function reset(st, nextDefaultValues) {
4300
4503
  st.removedSubtrees.clear();
4301
4504
  seedOriginalsFromBaseline(st, next, false);
4302
4505
  if (nextDefaultValues !== void 0) {
4303
- st.blankPaths.clear();
4304
- st.originalBlankPaths.clear();
4305
- } else {
4306
- st.blankPaths.clear();
4307
- for (const key of st.originalBlankPaths) {
4308
- st.blankPaths.add(key);
4309
- }
4506
+ const mentioned = /* @__PURE__ */ new Set();
4507
+ walkAuthoredFromConstraints(nextDefaultValues, [], mentioned);
4508
+ for (const key of mentioned) st.originalBlankPaths.delete(key);
4509
+ }
4510
+ st.blankPaths.clear();
4511
+ for (const key of st.originalBlankPaths) {
4512
+ st.blankPaths.add(key);
4310
4513
  }
4311
4514
  st.errorCells.clear();
4312
4515
  if (st.strict && !resetResponse.success) {
@@ -4622,7 +4825,16 @@ function createFormStore(options) {
4622
4825
  originalBlankPaths,
4623
4826
  // --- kernel-internal state ---
4624
4827
  strict,
4625
- defaultValues,
4828
+ // Defensive copy, not a fix for an observed alias: today
4829
+ // `getDefaultValues` happens to build a fresh tree, so form storage
4830
+ // does not currently share structure with the consumer's object.
4831
+ // That is an adapter implementation detail rather than a contract,
4832
+ // and this field is now durable state that every `reset()` reads, so
4833
+ // it should not depend on it. The copy also means a consumer who
4834
+ // keeps a reference to the literal they passed cannot mutate the
4835
+ // form's defaults from outside. `reset()` snapshots for a harder
4836
+ // reason (see there) where an alias IS reachable.
4837
+ defaultValues: structuralSnapshot(defaultValues),
4626
4838
  ssrPrefetch,
4627
4839
  rememberVariants,
4628
4840
  fieldValidationMode,
@@ -4651,6 +4863,7 @@ function createFormStore(options) {
4651
4863
  // --- methods: thin per-instance skins over the module kernel ---
4652
4864
  rehydrate: () => rehydrate(st),
4653
4865
  activate: () => activate(st),
4866
+ adoptResolvedDefaults: (value) => adoptResolvedDefaults(st, value),
4654
4867
  pathHasAsyncValidation: (path) => pathHasAsyncValidation(st, path),
4655
4868
  pathHasAsyncValidationByKey: (key, segments) => pathHasAsyncValidationByKey(st, key, segments),
4656
4869
  applyFormReplacement: (next, meta) => applyFormReplacement(st, next, meta),
@@ -4804,6 +5017,7 @@ function useAbstractForm(configuration, options) {
4804
5017
  const factory = resolvedDefaults.factory;
4805
5018
  state.defaultValuesFactory.value = factory;
4806
5019
  if (hadPendingHydration) {
5020
+ state.adoptResolvedDefaults(toRaw(state.form.value));
4807
5021
  state.hydrating.value = false;
4808
5022
  state.defaultsResolved.value = true;
4809
5023
  } else if (registry.ssr) {
@@ -5032,12 +5246,13 @@ function makeRegisterValueProxy(capturedRegisterValue) {
5032
5246
  get(_target, prop) {
5033
5247
  if (prop === "__v_isRef") return true;
5034
5248
  if (prop === "value") return capturedRegisterValue.value;
5249
+ if (prop === "isBound") return capturedRegisterValue.value !== void 0;
5035
5250
  const v = capturedRegisterValue.value;
5036
5251
  if (v === void 0) return void 0;
5037
5252
  return Reflect.get(v, prop);
5038
5253
  },
5039
5254
  has(_target, prop) {
5040
- if (prop === "__v_isRef" || prop === "value") return true;
5255
+ if (prop === "__v_isRef" || prop === "value" || prop === "isBound") return true;
5041
5256
  const v = capturedRegisterValue.value;
5042
5257
  if (v === void 0) return false;
5043
5258
  return Reflect.has(v, prop);
@@ -5058,7 +5273,7 @@ function makeRegisterValueProxy(capturedRegisterValue) {
5058
5273
  }
5059
5274
  });
5060
5275
  }
5061
- function useRegister() {
5276
+ function useRegister(options) {
5062
5277
  const instance = getCurrentInstance();
5063
5278
  if (instance === null) {
5064
5279
  warnOutsideSetup();
@@ -5098,7 +5313,7 @@ function useRegister() {
5098
5313
  if (el !== null && el !== void 0 && typeof el === "object") {
5099
5314
  el[REGISTER_OWNER_MARKER] = true;
5100
5315
  }
5101
- if (capturedRegisterValue.value === void 0) {
5316
+ if (capturedRegisterValue.value === void 0 && options?.optional !== true) {
5102
5317
  warnNoParentRV(instance);
5103
5318
  }
5104
5319
  });
@@ -5118,7 +5333,7 @@ function warnNoParentRV(instance) {
5118
5333
  warnedNoParentRV.add(instance);
5119
5334
  const frame = captureUserCallSite();
5120
5335
  console.warn(
5121
- `[attaform] useRegister: no parent registerValue prop; RegisterValue fields will read as undefined. Pass v-register on the parent: \`<YourComponent v-register="form.register('field')" />\`.` + (frame !== void 0 ? ` ${frame}` : "")
5336
+ `[attaform] useRegister: no parent registerValue prop; RegisterValue fields will read as undefined. Pass v-register on the parent: \`<YourComponent v-register="form.register('field')" />\`. If this component is meant to work without a form too, say so with \`useRegister({ optional: true })\` and branch on \`rv?.isBound\`.` + (frame !== void 0 ? ` ${frame}` : "")
5122
5337
  );
5123
5338
  }
5124
5339
 
@@ -5224,8 +5439,12 @@ function buildNoopWizardSchema(formKey) {
5224
5439
  getDefaultAtPath: () => void 0,
5225
5440
  getEmptyValueAtPath: () => void 0,
5226
5441
  isPreprocessOrCoerceLeaf: () => false,
5442
+ isOpaqueLeafAtPath: () => false,
5227
5443
  arrayShapeAtPath: () => null,
5228
5444
  isFixedObjectAtPath: (path) => path.length === 0,
5445
+ // The noop schema declares no shape at all, so nothing under it is
5446
+ // addressable, root included.
5447
+ entryKeyKindAtPath: () => void 0,
5229
5448
  getSchemasAtPath: () => [],
5230
5449
  validateAtPath: () => success,
5231
5450
  getSlimPrimitiveTypesAtPath: () => new Set(EMPTY_SLIM_KINDS),
@@ -6024,6 +6243,24 @@ function useWizard(options) {
6024
6243
  const target = list[idx + 1];
6025
6244
  moveTo(target.key);
6026
6245
  }
6246
+ let cancelDeferredAdvance = null;
6247
+ function advanceWhenInFlightSubmitLands(store, key) {
6248
+ cancelDeferredAdvance?.();
6249
+ const attemptsAtRequest = store.submissionAttempts.value;
6250
+ const off = store.onSubmitSuccess(() => {
6251
+ off();
6252
+ cancelDeferredAdvance = null;
6253
+ if (store.submissionAttempts.value !== attemptsAtRequest) return;
6254
+ if (activeKey.value !== key) return;
6255
+ advanceOne();
6256
+ });
6257
+ cancelDeferredAdvance = off;
6258
+ }
6259
+ function inFlightActiveStore() {
6260
+ const store = registry.forms.get(activeKey.value);
6261
+ if (store === void 0 || store.activeSubmissions.value === 0) return void 0;
6262
+ return store;
6263
+ }
6027
6264
  async function next() {
6028
6265
  if (submitting.value) {
6029
6266
  {
@@ -6050,7 +6287,12 @@ function useWizard(options) {
6050
6287
  return;
6051
6288
  }
6052
6289
  const active = list[idx];
6053
- if (active !== void 0 && active.isGate) {
6290
+ if (active !== void 0 && active.isGate && !clearedGates.has(active.key)) {
6291
+ const inFlight = inFlightActiveStore();
6292
+ if (inFlight !== void 0) {
6293
+ advanceWhenInFlightSubmitLands(inFlight, activeKey.value);
6294
+ return;
6295
+ }
6054
6296
  await tryNext();
6055
6297
  return;
6056
6298
  }
@@ -6082,11 +6324,16 @@ function useWizard(options) {
6082
6324
  const form = activeForm.value;
6083
6325
  if (form === void 0) return false;
6084
6326
  const before = activeKey.value;
6327
+ const inFlight = inFlightActiveStore();
6328
+ if (inFlight !== void 0) {
6329
+ advanceWhenInFlightSubmitLands(inFlight, before);
6330
+ return false;
6331
+ }
6085
6332
  let ranClean = false;
6086
6333
  await asHandleSubmitSource(form).handleSubmit(() => {
6087
6334
  ranClean = true;
6088
6335
  })();
6089
- if (ranClean) advanceOne();
6336
+ if (ranClean && activeKey.value === before) advanceOne();
6090
6337
  return activeKey.value !== before;
6091
6338
  }
6092
6339
  function back() {
@@ -6366,6 +6613,7 @@ function useWizard(options) {
6366
6613
  onScopeDispose(() => {
6367
6614
  historyHandle.dispose();
6368
6615
  lazyNoopScope.stop();
6616
+ cancelDeferredAdvance?.();
6369
6617
  });
6370
6618
  }
6371
6619
  const explicitKey = options.key;
@@ -6558,4 +6806,4 @@ function escapeForInlineScript(json) {
6558
6806
  });
6559
6807
  }
6560
6808
 
6561
- 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 };
6809
+ export { AttaformErrorCode as A, DEFAULT_TIMINGS as D, defaultDisplayState as a, defineCoercion as b, injectWizard as c, defaultCoercionRules as d, escapeForInlineScript as e, isUnset as f, gate as g, useAbstractForm as h, injectForm as i, useRegister as j, useWizard as k, lazy as l, makeDefaultDisplayState as m, isPlainRecord as n, crossCopyState as o, getAtPath as p, humanize as q, slimKindOf as s, unset as u };