attaform 0.21.0 → 0.21.2

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 (108) hide show
  1. package/dist/chunks/dev-key-collision-warnings.cjs +1 -1
  2. package/dist/chunks/dev-key-collision-warnings.mjs +1 -1
  3. package/dist/chunks/devtools.cjs +1 -1
  4. package/dist/chunks/devtools.mjs +1 -1
  5. package/dist/chunks/fingerprint2.cjs +1 -1
  6. package/dist/chunks/fingerprint2.mjs +1 -1
  7. package/dist/chunks/indexeddb.cjs +1 -1
  8. package/dist/chunks/indexeddb.mjs +1 -1
  9. package/dist/chunks/local-storage.cjs +1 -1
  10. package/dist/chunks/local-storage.mjs +1 -1
  11. package/dist/chunks/multi-tab-sync.cjs +2 -2
  12. package/dist/chunks/multi-tab-sync.mjs +2 -2
  13. package/dist/chunks/session-storage.cjs +1 -1
  14. package/dist/chunks/session-storage.mjs +1 -1
  15. package/dist/chunks/wire-persistence.cjs +2 -2
  16. package/dist/chunks/wire-persistence.mjs +2 -2
  17. package/dist/index.cjs +37 -24
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +31 -28
  20. package/dist/index.d.mts +31 -28
  21. package/dist/index.d.ts +31 -28
  22. package/dist/index.mjs +38 -25
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/nuxt.d.cts +1 -1
  25. package/dist/nuxt.d.mts +1 -1
  26. package/dist/nuxt.d.ts +1 -1
  27. package/dist/runtime/components/AttaformDevtoolsPanel.vue +396 -216
  28. package/dist/runtime/components/DevtoolsValueTree.vue +176 -114
  29. package/dist/runtime/plugins/attaform.cjs +2 -2
  30. package/dist/runtime/plugins/attaform.mjs +2 -2
  31. package/dist/shared/{attaform.BA3vRDos.cjs → attaform.B5LNzqQh.cjs} +349 -277
  32. package/dist/shared/attaform.B5LNzqQh.cjs.map +1 -0
  33. package/dist/shared/{attaform.PnqML3xW.cjs → attaform.BBDIKtKY.cjs} +13 -16
  34. package/dist/shared/attaform.BBDIKtKY.cjs.map +1 -0
  35. package/dist/shared/{attaform.CRsXyy-Y.d.ts → attaform.BCcrLApm.d.mts} +131 -64
  36. package/dist/shared/{attaform.BupwXkj_.mjs → attaform.BFWb6hDk.mjs} +29 -23
  37. package/dist/shared/attaform.BFWb6hDk.mjs.map +1 -0
  38. package/dist/shared/{attaform.7lzO9pdM.d.mts → attaform.BGf_J22U.d.ts} +131 -64
  39. package/dist/shared/{attaform.BnK_bfcb.mjs → attaform.BVeLgfEh.mjs} +14 -17
  40. package/dist/shared/attaform.BVeLgfEh.mjs.map +1 -0
  41. package/dist/shared/{attaform.BK1RE2ha.d.ts → attaform.BYgioWLF.d.ts} +2 -2
  42. package/dist/shared/{attaform.F8LMHHWV.d.cts → attaform.BkjJfMvJ.d.cts} +131 -64
  43. package/dist/shared/{attaform.BDIEq9qP.d.cts → attaform.BoY6RZUl.d.cts} +2 -2
  44. package/dist/shared/{attaform.CEf6wYfD.cjs → attaform.BwLp9KM7.cjs} +2 -2
  45. package/dist/shared/{attaform.CEf6wYfD.cjs.map → attaform.BwLp9KM7.cjs.map} +1 -1
  46. package/dist/shared/{attaform._rsCZy2j.cjs → attaform.BwrowMp2.cjs} +25 -45
  47. package/dist/shared/attaform.BwrowMp2.cjs.map +1 -0
  48. package/dist/shared/{attaform.ezb5Nh2t.mjs → attaform.C41gjp-a.mjs} +2 -2
  49. package/dist/shared/{attaform.ezb5Nh2t.mjs.map → attaform.C41gjp-a.mjs.map} +1 -1
  50. package/dist/shared/{attaform.BM6YD9kZ.cjs → attaform.CR6wGvNu.cjs} +29 -23
  51. package/dist/shared/attaform.CR6wGvNu.cjs.map +1 -0
  52. package/dist/shared/{attaform.DSqO6Db7.mjs → attaform.CTheKoTc.mjs} +705 -282
  53. package/dist/shared/attaform.CTheKoTc.mjs.map +1 -0
  54. package/dist/shared/{attaform.BzvOdiSI.cjs → attaform.CcnF1AKJ.cjs} +4 -4
  55. package/dist/shared/attaform.CcnF1AKJ.cjs.map +1 -0
  56. package/dist/shared/{attaform.BQ6drorq.d.mts → attaform.CnEl--PF.d.mts} +2 -2
  57. package/dist/shared/{attaform.CkjTapyq.mjs → attaform.CrD73S4m.mjs} +4 -4
  58. package/dist/shared/attaform.CrD73S4m.mjs.map +1 -0
  59. package/dist/shared/{attaform.BUszFoKq.cjs → attaform.D2ZuIOCf.cjs} +711 -287
  60. package/dist/shared/attaform.D2ZuIOCf.cjs.map +1 -0
  61. package/dist/shared/{attaform.r3PePkDR.mjs → attaform.D6GYGshL.mjs} +25 -45
  62. package/dist/shared/attaform.D6GYGshL.mjs.map +1 -0
  63. package/dist/shared/{attaform.Y_Mgg0Yp.mjs → attaform.DP-u7_tk.mjs} +348 -277
  64. package/dist/shared/attaform.DP-u7_tk.mjs.map +1 -0
  65. package/dist/shared/{attaform.B1nyO4ec.d.cts → attaform.ory-3WhV.d.cts} +395 -176
  66. package/dist/shared/{attaform.B1nyO4ec.d.mts → attaform.ory-3WhV.d.mts} +395 -176
  67. package/dist/shared/{attaform.B1nyO4ec.d.ts → attaform.ory-3WhV.d.ts} +395 -176
  68. package/dist/transforms.cjs +1 -1
  69. package/dist/transforms.mjs +1 -1
  70. package/dist/vite.cjs +1 -1
  71. package/dist/vite.mjs +1 -1
  72. package/dist/zod-v3.cjs +3 -4
  73. package/dist/zod-v3.cjs.map +1 -1
  74. package/dist/zod-v3.d.cts +4 -4
  75. package/dist/zod-v3.d.mts +4 -4
  76. package/dist/zod-v3.d.ts +4 -4
  77. package/dist/zod-v3.mjs +2 -3
  78. package/dist/zod-v3.mjs.map +1 -1
  79. package/dist/zod-v4.cjs +3 -4
  80. package/dist/zod-v4.cjs.map +1 -1
  81. package/dist/zod-v4.d.cts +4 -4
  82. package/dist/zod-v4.d.mts +4 -4
  83. package/dist/zod-v4.d.ts +4 -4
  84. package/dist/zod-v4.mjs +2 -3
  85. package/dist/zod-v4.mjs.map +1 -1
  86. package/dist/zod.cjs +6 -6
  87. package/dist/zod.cjs.map +1 -1
  88. package/dist/zod.d.cts +77 -26
  89. package/dist/zod.d.mts +77 -26
  90. package/dist/zod.d.ts +77 -26
  91. package/dist/zod.mjs +5 -6
  92. package/dist/zod.mjs.map +1 -1
  93. package/package.json +3 -11
  94. package/dist/shared/attaform.BA3vRDos.cjs.map +0 -1
  95. package/dist/shared/attaform.BM6YD9kZ.cjs.map +0 -1
  96. package/dist/shared/attaform.BUszFoKq.cjs.map +0 -1
  97. package/dist/shared/attaform.BnK_bfcb.mjs.map +0 -1
  98. package/dist/shared/attaform.BupwXkj_.mjs.map +0 -1
  99. package/dist/shared/attaform.BzvOdiSI.cjs.map +0 -1
  100. package/dist/shared/attaform.CkjTapyq.mjs.map +0 -1
  101. package/dist/shared/attaform.DSqO6Db7.mjs.map +0 -1
  102. package/dist/shared/attaform.PnqML3xW.cjs.map +0 -1
  103. package/dist/shared/attaform.Y_Mgg0Yp.mjs.map +0 -1
  104. package/dist/shared/attaform._rsCZy2j.cjs.map +0 -1
  105. package/dist/shared/attaform.r3PePkDR.mjs.map +0 -1
  106. package/dist/shared/{attaform.DSD85fHb.d.cts → attaform.nf83TIR5.d.cts} +10 -10
  107. package/dist/shared/{attaform.DSD85fHb.d.mts → attaform.nf83TIR5.d.mts} +10 -10
  108. package/dist/shared/{attaform.DSD85fHb.d.ts → attaform.nf83TIR5.d.ts} +10 -10
@@ -1,5 +1,5 @@
1
- import { computed, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, readonly, reactive, toRaw, watch, markRaw, shallowRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, effectScope, nextTick } from 'vue';
2
- import { _ as __DEV__, j as canonicalizePath, G as segmentsForPathKey, t as isPathPrefix, b as FORM_ERRORS_PATH_KEY, S as SubmitErrorHandlerError, A as AnonPersistError, k as captureUserCallSite, I as INTERACTIVE_TAG_NAMES, r as getOrAssignElementId, e as ROOT_PATH_KEY, R as ROOT_PATH, h as allowSensitivePersist, F as FORM_ERRORS_PATH, l as coerceToPathKey, v as isSensitivePath, o as createPersistOptInRegistry, d as InvalidUseFormConfigError, q as ensureAttaformInstalled, J as useRegistry, z as kFormContext, B as kFormInstanceId, g as ReservedFormKeyError, n as createIsSensitivePath, y as kAttaformWizardActiveStepResolver, w as kAttaformAncestorWizard } from './attaform.Y_Mgg0Yp.mjs';
1
+ import { computed, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, readonly, toRaw, reactive, watch, markRaw, shallowRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, onBeforeMount, onBeforeUpdate, onMounted, effectScope, nextTick } from 'vue';
2
+ import { _ as __DEV__, a as canonicalizePath, s as segmentsForPathKey, l as isPathPrefix, F as FORM_ERRORS_PATH_KEY, S as SubmitErrorHandlerError, t as toError, A as AnonPersistError, q as INTERACTIVE_TAG_NAMES, r as getOrAssignElementId, e as ROOT_PATH_KEY, R as ROOT_PATH, w as allowSensitivePersist, x as FORM_ERRORS_PATH, y as coerceToPathKey, z as isSensitivePath, B as createPersistOptInRegistry, d as InvalidUseFormConfigError, C as ensureAttaformInstalled, u as useRegistry, E as kFormContext, G as kFormInstanceId, h as ReservedFormKeyError, H as createIsSensitivePath, J as REGISTER_OWNER_MARKER, V as V_REGISTER_MARKER, k as kAttaformWizardActiveStepResolver, K as kAttaformAncestorWizard } from './attaform.DP-u7_tk.mjs';
3
3
 
4
4
  function safeAssign(target, key, value) {
5
5
  if (key === "__proto__") {
@@ -13,10 +13,14 @@ function safeAssign(target, key, value) {
13
13
  }
14
14
  target[key] = value;
15
15
  }
16
+ function isShadowedKey(key) {
17
+ return key in Object.prototype;
18
+ }
16
19
  function safeOwnRead(target, key) {
17
- if (key === "__proto__") {
18
- const desc = Object.getOwnPropertyDescriptor(target, "__proto__");
19
- return desc?.value;
20
+ if (isShadowedKey(key)) {
21
+ const desc = Object.getOwnPropertyDescriptor(target, key);
22
+ if (desc === void 0) return void 0;
23
+ return "value" in desc ? desc.value : target[key];
20
24
  }
21
25
  return target[key];
22
26
  }
@@ -35,6 +39,10 @@ function descendStep(value, segment) {
35
39
  }
36
40
  const record = value;
37
41
  const key = typeof segment === "number" ? String(segment) : segment;
42
+ if (isShadowedKey(key)) {
43
+ if (!safeOwnHas(record, key)) return NOT_FOUND;
44
+ return safeOwnRead(record, key);
45
+ }
38
46
  if (!(key in record)) return NOT_FOUND;
39
47
  return record[key];
40
48
  }
@@ -64,6 +72,7 @@ function hasAtPath(root, path) {
64
72
  return typeof last === "number" && last >= 0 && last < current.length;
65
73
  }
66
74
  const key = typeof last === "number" ? String(last) : last;
75
+ if (isShadowedKey(key)) return safeOwnHas(current, key);
67
76
  return key in current;
68
77
  }
69
78
  function isPlainRecord(value) {
@@ -151,68 +160,80 @@ function mergeStructuralImpl(schema, scratch, consumer, defaultValue) {
151
160
  }
152
161
  if (consumer === null) return null;
153
162
  if (Array.isArray(consumer)) {
154
- const shape = resolveArrayShape(schema, scratch);
155
- const isTuple = typeof shape === "number";
156
- const targetLen = isTuple ? shape : consumer.length;
157
- let cachedElementDefault;
158
- let cachedElementDefaultRead = false;
159
- let mutated = targetLen > consumer.length;
160
- const out = consumer.slice();
161
- while (out.length < targetLen) out.push(void 0);
162
- for (let i = 0; i < targetLen; i++) {
163
- scratch.push(i);
164
- let elemDefault;
165
- if (isTuple) {
166
- elemDefault = schema.getDefaultAtPath(scratch);
167
- } else {
168
- if (!cachedElementDefaultRead) {
169
- cachedElementDefault = schema.getDefaultAtPath(scratch);
170
- cachedElementDefaultRead = true;
171
- }
172
- elemDefault = cachedElementDefault;
173
- }
174
- const consumerElem = i < consumer.length ? consumer[i] : void 0;
175
- const merged = mergeStructuralImpl(schema, scratch, consumerElem, elemDefault);
176
- scratch.pop();
177
- if (merged !== consumerElem) {
178
- out[i] = merged;
179
- mutated = true;
180
- }
181
- }
182
- return mutated ? out : consumer;
163
+ return mergeStructuralArray(schema, scratch, consumer);
183
164
  }
184
165
  if (isPlainRecord(consumer)) {
185
166
  if (!isPlainRecord(defaultValue)) {
186
167
  return consumer;
187
168
  }
188
- let mutated = false;
189
169
  const out = { ...consumer };
190
- for (const key of Object.keys(defaultValue)) {
191
- if (!safeOwnHas(consumer, key)) {
192
- const defAtKey = safeOwnRead(defaultValue, key);
193
- scratch.push(key);
194
- const filled = mergeStructuralImpl(schema, scratch, void 0, defAtKey);
195
- scratch.pop();
196
- if (filled !== void 0) {
197
- safeAssign(out, key, filled);
198
- mutated = true;
199
- }
170
+ const filledAny = fillMissingKeysFromDefault(schema, scratch, consumer, defaultValue, out);
171
+ const recursedAny = recurseIntoConsumerKeys(schema, scratch, consumer, defaultValue, out);
172
+ return filledAny || recursedAny ? out : consumer;
173
+ }
174
+ return consumer;
175
+ }
176
+ function mergeStructuralArray(schema, scratch, consumer) {
177
+ const shape = resolveArrayShape(schema, scratch);
178
+ const isTuple = typeof shape === "number";
179
+ const targetLen = isTuple ? shape : consumer.length;
180
+ let cachedElementDefault;
181
+ let cachedElementDefaultRead = false;
182
+ let mutated = targetLen > consumer.length;
183
+ const out = consumer.slice();
184
+ while (out.length < targetLen) out.push(void 0);
185
+ for (let i = 0; i < targetLen; i++) {
186
+ scratch.push(i);
187
+ let elemDefault;
188
+ if (isTuple) {
189
+ elemDefault = schema.getDefaultAtPath(scratch);
190
+ } else {
191
+ if (!cachedElementDefaultRead) {
192
+ cachedElementDefault = schema.getDefaultAtPath(scratch);
193
+ cachedElementDefaultRead = true;
200
194
  }
195
+ elemDefault = cachedElementDefault;
201
196
  }
202
- for (const key of Object.keys(consumer)) {
203
- const cVal = safeOwnRead(consumer, key);
204
- if (cVal === void 0) continue;
197
+ const consumerElem = i < consumer.length ? consumer[i] : void 0;
198
+ const merged = mergeStructuralImpl(schema, scratch, consumerElem, elemDefault);
199
+ scratch.pop();
200
+ if (merged !== consumerElem) {
201
+ out[i] = merged;
202
+ mutated = true;
203
+ }
204
+ }
205
+ return mutated ? out : consumer;
206
+ }
207
+ function fillMissingKeysFromDefault(schema, scratch, consumer, defaultValue, out) {
208
+ let mutated = false;
209
+ for (const key of Object.keys(defaultValue)) {
210
+ if (!safeOwnHas(consumer, key)) {
211
+ const defAtKey = safeOwnRead(defaultValue, key);
205
212
  scratch.push(key);
206
- const merged = mergeStructuralImpl(schema, scratch, cVal, safeOwnRead(defaultValue, key));
213
+ const filled = mergeStructuralImpl(schema, scratch, void 0, defAtKey);
207
214
  scratch.pop();
208
- if (merged !== cVal) {
209
- safeAssign(out, key, merged);
215
+ if (filled !== void 0) {
216
+ safeAssign(out, key, filled);
210
217
  mutated = true;
211
218
  }
212
219
  }
213
- return mutated ? out : consumer;
214
220
  }
215
- return consumer;
221
+ return mutated;
222
+ }
223
+ function recurseIntoConsumerKeys(schema, scratch, consumer, defaultValue, out) {
224
+ let mutated = false;
225
+ for (const key of Object.keys(consumer)) {
226
+ const cVal = safeOwnRead(consumer, key);
227
+ if (cVal === void 0) continue;
228
+ scratch.push(key);
229
+ const merged = mergeStructuralImpl(schema, scratch, cVal, safeOwnRead(defaultValue, key));
230
+ scratch.pop();
231
+ if (merged !== cVal) {
232
+ safeAssign(out, key, merged);
233
+ mutated = true;
234
+ }
235
+ }
236
+ return mutated;
216
237
  }
217
238
  function setAtPathWithSchemaFill(root, schema, fullPath, value) {
218
239
  if (fullPath.length === 0) return value;
@@ -295,55 +316,27 @@ function diffAndApply(oldValue, newValue, prefix, visit) {
295
316
  const oldIsDescendable = isDescendable(oldValue);
296
317
  const newIsDescendable = isDescendable(newValue);
297
318
  if (oldValue === void 0 && newIsDescendable) {
298
- if (Array.isArray(newValue)) {
299
- for (let i = 0; i < newValue.length; i++) {
300
- diffAndApply(void 0, newValue[i], appendSegment(prefix, i), visit);
301
- }
302
- } else {
303
- const rec = newValue;
304
- for (const k of Object.keys(rec)) {
305
- diffAndApply(void 0, rec[k], appendSegment(prefix, k), visit);
306
- }
307
- }
319
+ walkNewDescendable(newValue, prefix, visit);
308
320
  return;
309
321
  }
310
322
  if (oldIsDescendable && newValue === void 0) {
311
- if (Array.isArray(oldValue)) {
312
- for (let i = 0; i < oldValue.length; i++) {
313
- diffAndApply(oldValue[i], void 0, appendSegment(prefix, i), visit);
314
- }
315
- } else {
316
- const rec = oldValue;
317
- for (const k of Object.keys(rec)) {
318
- diffAndApply(rec[k], void 0, appendSegment(prefix, k), visit);
319
- }
320
- }
323
+ walkOldDescendable(oldValue, prefix, visit);
321
324
  return;
322
325
  }
323
326
  if (oldIsDescendable && newIsDescendable) {
324
327
  const oldIsArray = Array.isArray(oldValue);
325
328
  const newIsArray = Array.isArray(newValue);
326
329
  if (oldIsArray && newIsArray) {
327
- const oldArr = oldValue;
328
- const newArr = newValue;
329
- const max = Math.max(oldArr.length, newArr.length);
330
- for (let i = 0; i < max; i++) {
331
- diffAndApply(oldArr[i], newArr[i], appendSegment(prefix, i), visit);
332
- }
330
+ diffArraysLockstep(oldValue, newValue, prefix, visit);
333
331
  return;
334
332
  }
335
333
  if (!oldIsArray && !newIsArray) {
336
- const oldRec = oldValue;
337
- const newRec = newValue;
338
- const seen = /* @__PURE__ */ new Set();
339
- for (const k of Object.keys(oldRec)) {
340
- seen.add(k);
341
- diffAndApply(oldRec[k], newRec[k], appendSegment(prefix, k), visit);
342
- }
343
- for (const k of Object.keys(newRec)) {
344
- if (seen.has(k)) continue;
345
- diffAndApply(oldRec[k], newRec[k], appendSegment(prefix, k), visit);
346
- }
334
+ diffObjectsLockstep(
335
+ oldValue,
336
+ newValue,
337
+ prefix,
338
+ visit
339
+ );
347
340
  return;
348
341
  }
349
342
  visit({ kind: "changed", path: prefix, oldValue, newValue });
@@ -367,6 +360,47 @@ function diffAndApply(oldValue, newValue, prefix, visit) {
367
360
  }
368
361
  visit({ kind: "changed", path: prefix, oldValue, newValue });
369
362
  }
363
+ function walkNewDescendable(newValue, prefix, visit) {
364
+ if (Array.isArray(newValue)) {
365
+ for (let i = 0; i < newValue.length; i++) {
366
+ diffAndApply(void 0, newValue[i], appendSegment(prefix, i), visit);
367
+ }
368
+ } else {
369
+ const rec = newValue;
370
+ for (const k of Object.keys(rec)) {
371
+ diffAndApply(void 0, rec[k], appendSegment(prefix, k), visit);
372
+ }
373
+ }
374
+ }
375
+ function walkOldDescendable(oldValue, prefix, visit) {
376
+ if (Array.isArray(oldValue)) {
377
+ for (let i = 0; i < oldValue.length; i++) {
378
+ diffAndApply(oldValue[i], void 0, appendSegment(prefix, i), visit);
379
+ }
380
+ } else {
381
+ const rec = oldValue;
382
+ for (const k of Object.keys(rec)) {
383
+ diffAndApply(rec[k], void 0, appendSegment(prefix, k), visit);
384
+ }
385
+ }
386
+ }
387
+ function diffArraysLockstep(oldArr, newArr, prefix, visit) {
388
+ const max = Math.max(oldArr.length, newArr.length);
389
+ for (let i = 0; i < max; i++) {
390
+ diffAndApply(oldArr[i], newArr[i], appendSegment(prefix, i), visit);
391
+ }
392
+ }
393
+ function diffObjectsLockstep(oldRec, newRec, prefix, visit) {
394
+ const seen = /* @__PURE__ */ new Set();
395
+ for (const k of Object.keys(oldRec)) {
396
+ seen.add(k);
397
+ diffAndApply(oldRec[k], newRec[k], appendSegment(prefix, k), visit);
398
+ }
399
+ for (const k of Object.keys(newRec)) {
400
+ if (seen.has(k)) continue;
401
+ diffAndApply(oldRec[k], newRec[k], appendSegment(prefix, k), visit);
402
+ }
403
+ }
370
404
  function applyChangedKeys(target, source) {
371
405
  if (!isDescendable(target) || !isDescendable(source)) return false;
372
406
  const targetIsArray = Array.isArray(target);
@@ -470,7 +504,12 @@ function computeVerdict(field, formMeta) {
470
504
  if (field.valid === true && field.blank !== true && field.dirty === true) return "success";
471
505
  return "idle";
472
506
  }
473
- const DEFAULT_TIMINGS = { showDelay: 100, minVisible: 120 };
507
+ function earliestNonNull(a, b) {
508
+ if (a === null) return b;
509
+ if (b === null) return a;
510
+ return a < b ? a : b;
511
+ }
512
+ const DEFAULT_TIMINGS = { showDelay: 120, minVisible: 120 };
474
513
  const FOCUS_OUT_GRACE = 16;
475
514
  const defaultFamily = /* @__PURE__ */ new WeakSet();
476
515
  function isDefaultDisplayState(fn) {
@@ -480,10 +519,11 @@ function makeDefaultDisplayState({
480
519
  showDelay,
481
520
  minVisible
482
521
  }) {
483
- const reducer = (prev, { field, formMeta, validatingSince, now }) => {
522
+ const reducer = (prev, { field, formMeta, validatingSince, transformingSince, now }) => {
484
523
  const verdict = computeVerdict(field, formMeta);
485
524
  if (!isGateOpen(field, formMeta)) return { display: verdict };
486
- if (validatingSince === null) {
525
+ const inFlightSince = earliestNonNull(validatingSince, transformingSince);
526
+ if (inFlightSince === null) {
487
527
  if (prev.display === "pending") {
488
528
  const shownAt = prev.pendingShownAt ?? now;
489
529
  if (now < shownAt + minVisible)
@@ -494,8 +534,8 @@ function makeDefaultDisplayState({
494
534
  if (prev.display === "pending")
495
535
  return { display: "pending", pendingShownAt: prev.pendingShownAt ?? now };
496
536
  const window = field.focused === false ? Math.min(showDelay, FOCUS_OUT_GRACE) : showDelay;
497
- if (now - validatingSince < window) {
498
- return { display: prev.display, reviewAt: validatingSince + window };
537
+ if (now - inFlightSince < window) {
538
+ return { display: prev.display, reviewAt: inFlightSince + window };
499
539
  }
500
540
  return { display: "pending", pendingShownAt: now, reviewAt: now + minVisible };
501
541
  };
@@ -608,6 +648,12 @@ function buildFieldStateAccessor(state, formInstanceId, getFormMetaBase, options
608
648
  return c;
609
649
  };
610
650
  }
651
+ function resolveFieldMetaAndLabel(state, segments) {
652
+ const resolved = state.schema.getFieldMetaAtPath ? state.schema.getFieldMetaAtPath(segments) : EMPTY_RESOLVED_FIELD_META;
653
+ const lastSegment = segments.length === 0 ? "" : segments[segments.length - 1] ?? "";
654
+ const label = resolved.label || humanize(lastSegment);
655
+ return { resolved, label };
656
+ }
611
657
  function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
612
658
  const record = state.fields.get(key);
613
659
  const value = state.getValueAtPath(segments);
@@ -621,15 +667,15 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
621
667
  if (blankForKey !== void 0) errors.push(...blankForKey);
622
668
  if (userForKey !== void 0) errors.push(...userForKey);
623
669
  const validating = (state.fieldValidationCounts.get(key) ?? 0) > 0;
670
+ const transforming = (state.fieldTransformCounts.get(key) ?? 0) > 0;
671
+ const transformError = state.transformErrors.get(key) ?? null;
624
672
  const gated = state.pathHasAsyncValidation(segments) && !state.firstValidationDone.value;
625
673
  const isOrphan = segments.length > 0 && !hasAtPath(state.form.value, segments) && isUnderStubAncestor(state, segments);
626
674
  const valid = !gated && errors.length === 0 && !validating && !isOrphan;
627
675
  const elementRecord = state.elements.get(key);
628
676
  const elementsArr = elementRecord ? Object.freeze([...elementRecord.elements]) : EMPTY_ELEMENTS;
629
677
  const firstElement = elementsArr[0] ?? null;
630
- const resolved = state.schema.getFieldMetaAtPath ? state.schema.getFieldMetaAtPath(segments) : EMPTY_RESOLVED_FIELD_META;
631
- const lastSegment = segments.length === 0 ? "" : segments[segments.length - 1] ?? "";
632
- const label = resolved.label || humanize(lastSegment);
678
+ const { resolved, label } = resolveFieldMetaAndLabel(state, segments);
633
679
  return {
634
680
  value,
635
681
  original,
@@ -647,6 +693,9 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
647
693
  errors,
648
694
  validating,
649
695
  valid,
696
+ transforming,
697
+ busy: transforming || validating,
698
+ transformError,
650
699
  path: segments,
651
700
  ...computeFieldIdentity(formInstanceId, state.formKey, key),
652
701
  key: state.arrayElementKey(segments),
@@ -660,12 +709,14 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
660
709
  function buildLeafFieldState(state, segments, key, formInstanceId, getFormMetaBase, getDisplayState) {
661
710
  const base = buildLeafFieldStateBase(state, segments, key, formInstanceId);
662
711
  const validatingSince = state.fieldValidatingSince.get(key) ?? null;
712
+ const transformingSince = state.fieldTransformingSince.get(key) ?? null;
663
713
  return decorateWithDerivedProps(
664
714
  base,
665
715
  state,
666
716
  getFormMetaBase,
667
717
  key,
668
718
  validatingSince,
719
+ transformingSince,
669
720
  false,
670
721
  // revealedDescendantError: leaves have no descendants
671
722
  false,
@@ -688,6 +739,8 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
688
739
  let connected = false;
689
740
  let validating = false;
690
741
  let validatingSince = null;
742
+ let transforming = false;
743
+ let transformingSince = null;
691
744
  let updatedAt = null;
692
745
  let asyncPending = false;
693
746
  const submissionAttempts = state.submissionAttempts.value;
@@ -718,6 +771,13 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
718
771
  if (leafGateOpen && since !== void 0 && (validatingSince === null || since < validatingSince))
719
772
  validatingSince = since;
720
773
  }
774
+ if ((state.fieldTransformCounts.get(leafKey) ?? 0) > 0) {
775
+ transforming = true;
776
+ const leafGateOpen = submissionAttempts > 0 || leafRecord?.blurredAfterInteraction === true;
777
+ const since = state.fieldTransformingSince.get(leafKey);
778
+ if (leafGateOpen && since !== void 0 && (transformingSince === null || since < transformingSince))
779
+ transformingSince = since;
780
+ }
721
781
  if (state.pathHasAsyncValidationByKey(leafKey, entry.segments)) asyncPending = true;
722
782
  const ts = leafRecord?.updatedAt;
723
783
  if (ts !== void 0 && ts !== null) {
@@ -737,11 +797,22 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
737
797
  return blurredLeafSegments.some((s) => isPathPrefix(ePath, s));
738
798
  });
739
799
  if (!asyncPending && state.pathHasAsyncValidation(segments)) asyncPending = true;
800
+ if ((state.fieldValidationCounts.get(key) ?? 0) > 0) {
801
+ validating = true;
802
+ const since = state.fieldValidatingSince.get(key);
803
+ if (since !== void 0 && (validatingSince === null || since < validatingSince))
804
+ validatingSince = since;
805
+ }
806
+ if ((state.fieldTransformCounts.get(key) ?? 0) > 0) {
807
+ transforming = true;
808
+ const since = state.fieldTransformingSince.get(key);
809
+ if (since !== void 0 && (transformingSince === null || since < transformingSince))
810
+ transformingSince = since;
811
+ }
812
+ const ownTransformError = state.transformErrors.get(key) ?? null;
740
813
  const gated = asyncPending && !state.firstValidationDone.value;
741
814
  const valid = !gated && errors.length === 0 && !validating;
742
- const resolved = state.schema.getFieldMetaAtPath ? state.schema.getFieldMetaAtPath(segments) : EMPTY_RESOLVED_FIELD_META;
743
- const lastSegment = segments.length === 0 ? "" : segments[segments.length - 1] ?? "";
744
- const label = resolved.label || humanize(lastSegment);
815
+ const { resolved, label } = resolveFieldMetaAndLabel(state, segments);
745
816
  return {
746
817
  base: {
747
818
  value,
@@ -760,6 +831,12 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
760
831
  errors,
761
832
  validating,
762
833
  valid,
834
+ transforming,
835
+ busy: transforming || validating,
836
+ // A container surfaces its OWN transform failure (a transform registered
837
+ // on the container path, e.g. a file normalizer) but never rolls up a
838
+ // descendant leaf's failure — that stays a per-field channel.
839
+ transformError: ownTransformError,
763
840
  path: segments,
764
841
  ...computeFieldIdentity(formInstanceId, state.formKey, key),
765
842
  key: state.arrayElementKey(segments),
@@ -770,28 +847,25 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
770
847
  meta: resolved.meta
771
848
  },
772
849
  validatingSince,
850
+ transformingSince,
773
851
  revealedDescendantError
774
852
  };
775
853
  }
776
854
  function buildContainerFieldState(state, segments, key, formInstanceId, getFormMetaBase, getDisplayState) {
777
- const { base, validatingSince, revealedDescendantError } = buildContainerFieldStateBase(
778
- state,
779
- segments,
780
- key,
781
- formInstanceId
782
- );
855
+ const { base, validatingSince, transformingSince, revealedDescendantError } = buildContainerFieldStateBase(state, segments, key, formInstanceId);
783
856
  return decorateWithDerivedProps(
784
857
  base,
785
858
  state,
786
859
  getFormMetaBase,
787
860
  key,
788
861
  validatingSince,
862
+ transformingSince,
789
863
  revealedDescendantError,
790
864
  segments.length === 0,
791
865
  getDisplayState
792
866
  );
793
867
  }
794
- function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, revealedDescendantError, isRoot, getDisplayState) {
868
+ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, transformingSince, revealedDescendantError, isRoot, getDisplayState) {
795
869
  const firstError = base.errors[0];
796
870
  const predicate = getDisplayState ?? state.getDisplayState;
797
871
  const formMeta = getFormMetaBase();
@@ -799,6 +873,7 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
799
873
  field: base,
800
874
  formMeta,
801
875
  validatingSince,
876
+ transformingSince,
802
877
  // The engine's clock. Frozen to 0 under SSR (no clock, nothing in
803
878
  // flight) so the reducer returns the plain verdict and hydration matches.
804
879
  now: state.ssr ? 0 : Date.now()
@@ -865,6 +940,15 @@ function liveKeysAtPath(state, segments) {
865
940
  if (typeof value === "object") return Object.keys(value);
866
941
  return [];
867
942
  }
943
+ function liveContainerHasKey(state, segments, key) {
944
+ const value = getAtPath(state.form.value, segments);
945
+ if (value === null || value === void 0 || typeof value !== "object") return false;
946
+ if (Array.isArray(value)) {
947
+ const index = Number(key);
948
+ return Number.isInteger(index) && index >= 0 && index < value.length && String(index) === key;
949
+ }
950
+ return Object.hasOwn(value, key);
951
+ }
868
952
  function isArrayPath(state, segments) {
869
953
  if (segments.length === 0) return false;
870
954
  return Array.isArray(getAtPath(state.form.value, segments));
@@ -893,6 +977,21 @@ const INTEGER_SEGMENT = /^(?:0|[1-9]\d*)$/;
893
977
  function keyToSegment(key) {
894
978
  return INTEGER_SEGMENT.test(key) ? Number(key) : key;
895
979
  }
980
+ function callableInvokeShim(method, surface, getDescent) {
981
+ const fnMethod = Reflect.get(Function.prototype, method);
982
+ return new Proxy((() => {
983
+ }), {
984
+ apply: (_target, _thisArg, args) => Reflect.apply(fnMethod, surface, args),
985
+ get: (_target, key) => Reflect.get(getDescent(), key),
986
+ has: (_target, key) => Reflect.has(getDescent(), key),
987
+ ownKeys: () => Reflect.ownKeys(getDescent()),
988
+ getOwnPropertyDescriptor: (_target, key) => {
989
+ const descriptor = Reflect.getOwnPropertyDescriptor(getDescent(), key);
990
+ if (descriptor !== void 0) descriptor.configurable = true;
991
+ return descriptor;
992
+ }
993
+ });
994
+ }
896
995
  function buildSurfaceProxy(opts) {
897
996
  const containerCache = /* @__PURE__ */ new Map();
898
997
  const leafViewCache = /* @__PURE__ */ new Map();
@@ -919,6 +1018,8 @@ function buildSurfaceProxy(opts) {
919
1018
  const cacheKey = `${JSON.stringify(segments)}+${isArrayLike ? "A" : "O"}`;
920
1019
  const existing = containerCache.get(cacheKey);
921
1020
  if (existing !== void 0) return existing;
1021
+ const isFixedObject = opts.schema.isFixedObjectAtPath(segments);
1022
+ const containerHasKey = (k) => opts.containerHasOwnKey !== void 0 ? opts.containerHasOwnKey(segments, k) : opts.containerOwnKeys?.(segments).includes(k) === true;
922
1023
  const snapshotContainer = () => opts.materializeContainer === void 0 ? {} : opts.materializeContainer(segments);
923
1024
  const {
924
1025
  toString: containerToString,
@@ -926,8 +1027,9 @@ function buildSurfaceProxy(opts) {
926
1027
  toJSON: containerToJSON,
927
1028
  toPrimitive: containerToPrimitive
928
1029
  } = makeReadonlyCoercion(snapshotContainer);
929
- const target = isArrayLike ? [] : (() => {
930
- });
1030
+ const isRoot = segments.length === 0;
1031
+ const target = isRoot ? (() => {
1032
+ }) : isArrayLike ? [] : {};
931
1033
  const proxy = new Proxy(target, {
932
1034
  apply(_, __, args) {
933
1035
  const arg = args[0];
@@ -958,7 +1060,16 @@ function buildSurfaceProxy(opts) {
958
1060
  return key === "toString" ? containerToString : containerValueOf;
959
1061
  }
960
1062
  }
961
- return descendOrTerminate(childSegs);
1063
+ if (key === "hasOwnProperty" && !schemaHasPath(childSegs)) {
1064
+ return Object.prototype.hasOwnProperty;
1065
+ }
1066
+ if (isRoot && (key === "call" || key === "apply" || key === "bind")) {
1067
+ return callableInvokeShim(key, proxy, () => descendOrTerminate(childSegs));
1068
+ }
1069
+ if (opts.isTerminalAt?.(childSegs) === true || isFixedObject && schemaHasPath(childSegs) || containerHasKey(key)) {
1070
+ return descendOrTerminate(childSegs);
1071
+ }
1072
+ return void 0;
962
1073
  },
963
1074
  has(_, key) {
964
1075
  if (typeof key === "symbol") return Reflect.has(target, key);
@@ -1043,15 +1154,8 @@ function buildSurfaceProxy(opts) {
1043
1154
  toJSON: leafToJSONHandler,
1044
1155
  toPrimitive: leafToPrimitive
1045
1156
  } = makeReadonlyCoercion(snapshotLeaf);
1046
- const target = (() => {
1047
- });
1157
+ const target = {};
1048
1158
  const proxy = new Proxy(target, {
1049
- apply(_, __, args) {
1050
- const arg = args[0];
1051
- if (arg === void 0) return opts.resolveCallTarget(segments);
1052
- const { segments: argSegs } = canonicalizePath(arg);
1053
- return opts.resolveCallTarget(argSegs);
1054
- },
1055
1159
  get(_, key) {
1056
1160
  if (typeof key === "symbol") {
1057
1161
  if (key === Symbol.toPrimitive) return leafToPrimitive;
@@ -1061,6 +1165,9 @@ function buildSurfaceProxy(opts) {
1061
1165
  if (key === "toString") return leafToString;
1062
1166
  if (key === "valueOf") return leafValueOf;
1063
1167
  if (key === "toJSON") return leafToJSONHandler;
1168
+ if (key === "hasOwnProperty" && !schemaHasPath([...segments, keyToSegment(key)])) {
1169
+ return Object.prototype.hasOwnProperty;
1170
+ }
1064
1171
  if (leafKeys.has(key)) {
1065
1172
  const leaf = opts.resolveLeaf(segments);
1066
1173
  return readLeafKey(leaf, key);
@@ -1073,8 +1180,8 @@ function buildSurfaceProxy(opts) {
1073
1180
  return true;
1074
1181
  },
1075
1182
  // Iteration: leaf-views expose the leaf-key set so
1076
- // `JSON.stringify(form.fields.email)` produces a FieldState
1077
- // snapshot rather than the function-target placeholder.
1183
+ // `Object.keys(form.fields.email)` / spread enumerate the
1184
+ // FieldState props. (`JSON.stringify` routes through `toJSON` above.)
1078
1185
  ownKeys: () => Array.from(leafKeys),
1079
1186
  getOwnPropertyDescriptor(_, key) {
1080
1187
  if (typeof key !== "string") return void 0;
@@ -1183,6 +1290,12 @@ function buildErrorsProxy(state) {
1183
1290
  // library-produced verdicts (schema + derived-blank) at unreachable
1184
1291
  // paths stay hidden; user-supplied errors are unconditional.
1185
1292
  containerOwnKeys: (segments) => errorAwareContainerKeys(state, segments),
1293
+ // Fast path: a key the live form data holds short-circuits before the
1294
+ // O(n) error-store scan, so iterating `form.errors.<array>` over live
1295
+ // indices stays linear. The scan still runs for a key with no live
1296
+ // home — a server error at a non-schema key (`form.errors.ghost`) —
1297
+ // so it keeps surfacing while a genuinely-absent key reads undefined.
1298
+ containerHasOwnKey: (segments, key) => liveContainerHasKey(state, segments, key) || errorAwareContainerKeys(state, segments).includes(key),
1186
1299
  isArrayContainer: (segments) => isArrayPath(state, segments)
1187
1300
  });
1188
1301
  }
@@ -1356,6 +1469,9 @@ const FIELD_STATE_KEYS = /* @__PURE__ */ new Set([
1356
1469
  "errors",
1357
1470
  "validating",
1358
1471
  "valid",
1472
+ "transforming",
1473
+ "busy",
1474
+ "transformError",
1359
1475
  "displayState",
1360
1476
  "showErrors",
1361
1477
  "showPending",
@@ -1458,33 +1574,41 @@ function buildFieldStateProxy(state, formInstanceId, getFormMetaBase, options) {
1458
1574
  terminalCache.set(cacheKey, proxy);
1459
1575
  return proxy;
1460
1576
  }
1577
+ const surfaceSchema = state.schema;
1461
1578
  return buildSurfaceProxy({
1462
- schema: state.schema,
1579
+ schema: surfaceSchema,
1463
1580
  resolveLeaf: (path) => getFieldStateAt(path),
1464
1581
  leafKeys: FIELD_STATE_KEYS,
1465
1582
  readLeafKey: (computed, key) => computed.value[key],
1466
1583
  materializeContainer: (segments) => materializeFields(state, segments, snapshotFieldStateAt),
1467
- resolveCallTarget: (path) => fieldStateTerminalAt(path),
1584
+ // `form.fields(path)` resolves a FieldState for any path the SCHEMA
1585
+ // declares — a leaf, a container, an inactive discriminated-union
1586
+ // variant key, or an out-of-bounds array index (the element schema
1587
+ // admits any index). A path the schema doesn't have is a typo, not a
1588
+ // field, so it reads `undefined` rather than a phantom stub. The
1589
+ // empty path (`form.fields()`) is the root object, always valid.
1590
+ resolveCallTarget: (path) => surfaceSchema.getSlimPrimitiveTypesAtPath(path).size > 0 ? fieldStateTerminalAt(path) : void 0,
1468
1591
  containerOwnKeys: (segments) => liveKeysAtPath(state, segments),
1592
+ containerHasOwnKey: (segments, key) => liveContainerHasKey(state, segments, key),
1469
1593
  isArrayContainer: (segments) => isArrayPath(state, segments)
1470
1594
  });
1471
1595
  }
1472
1596
  function materializeFields(state, containerSegments, snapshotFieldStateAt) {
1473
1597
  const liveValue = getAtPath(state.form.value, containerSegments);
1474
- return walk$2(liveValue, containerSegments, state.schema, snapshotFieldStateAt);
1598
+ return walk$1(liveValue, containerSegments, state.schema, snapshotFieldStateAt);
1475
1599
  }
1476
- function walk$2(value, basePath, schema, snapshotFieldStateAt) {
1600
+ function walk$1(value, basePath, schema, snapshotFieldStateAt) {
1477
1601
  if (schema.isLeafAtPath(basePath)) return snapshotFieldStateAt(basePath);
1478
1602
  if (value === null || value === void 0) return value;
1479
1603
  if (typeof value !== "object") {
1480
1604
  return value;
1481
1605
  }
1482
1606
  if (Array.isArray(value)) {
1483
- return value.map((_, i) => walk$2(value[i], [...basePath, i], schema, snapshotFieldStateAt));
1607
+ return value.map((_, i) => walk$1(value[i], [...basePath, i], schema, snapshotFieldStateAt));
1484
1608
  }
1485
1609
  const result = {};
1486
1610
  for (const key of Object.keys(value)) {
1487
- result[key] = walk$2(
1611
+ result[key] = walk$1(
1488
1612
  value[key],
1489
1613
  [...basePath, key],
1490
1614
  schema,
@@ -1568,47 +1692,42 @@ function mergeDeep(target, source, path, schema) {
1568
1692
  if (!isPlainRecord(source)) return source;
1569
1693
  if (schema !== void 0) {
1570
1694
  const du = schema.getUnionDiscriminatorAtPath(path);
1571
- if (du !== void 0) {
1572
- const sourceRecord = source;
1573
- const sourceDisc = sourceRecord[du.discriminatorKey];
1574
- if (sourceDisc !== void 0 && !du.isVariantSelected(sourceDisc)) {
1575
- return { [du.discriminatorKey]: sourceDisc };
1576
- }
1577
- if (sourceDisc !== void 0) {
1578
- const variantDefault = du.getVariantDefault(sourceDisc);
1579
- if (isPlainRecord(variantDefault)) {
1580
- const out2 = { ...variantDefault };
1581
- for (const key of Object.keys(sourceRecord)) {
1582
- if (!safeOwnHas(variantDefault, key) && key !== du.discriminatorKey) continue;
1583
- safeAssign(
1584
- out2,
1585
- key,
1586
- mergeDeep(
1587
- safeOwnRead(out2, key),
1588
- safeOwnRead(sourceRecord, key),
1589
- [...path, key],
1590
- schema
1591
- )
1592
- );
1593
- }
1594
- return out2;
1595
- }
1596
- }
1597
- return {};
1695
+ if (du !== void 0) return mergeDuAwareKeys(source, path, schema, du);
1696
+ }
1697
+ return mergeObjectKeys(target, source, path, schema);
1698
+ }
1699
+ function mergeDuAwareKeys(source, path, schema, du) {
1700
+ const sourceDisc = source[du.discriminatorKey];
1701
+ if (sourceDisc !== void 0 && !du.isVariantSelected(sourceDisc)) {
1702
+ return { [du.discriminatorKey]: sourceDisc };
1703
+ }
1704
+ if (sourceDisc !== void 0) {
1705
+ const variantDefault = du.getVariantDefault(sourceDisc);
1706
+ if (isPlainRecord(variantDefault)) {
1707
+ return mergeVariantKeys(source, variantDefault, path, schema, du);
1598
1708
  }
1599
1709
  }
1600
- const mergeTarget = target;
1601
- const out = isPlainRecord(mergeTarget) ? { ...mergeTarget } : {};
1710
+ return {};
1711
+ }
1712
+ function mergeVariantKeys(source, variantDefault, path, schema, du) {
1713
+ const out = { ...variantDefault };
1602
1714
  for (const key of Object.keys(source)) {
1715
+ if (!safeOwnHas(variantDefault, key) && key !== du.discriminatorKey) continue;
1603
1716
  safeAssign(
1604
1717
  out,
1605
1718
  key,
1606
- mergeDeep(
1607
- safeOwnRead(out, key),
1608
- safeOwnRead(source, key),
1609
- [...path, key],
1610
- schema
1611
- )
1719
+ mergeDeep(safeOwnRead(out, key), safeOwnRead(source, key), [...path, key], schema)
1720
+ );
1721
+ }
1722
+ return out;
1723
+ }
1724
+ function mergeObjectKeys(target, source, path, schema) {
1725
+ const out = isPlainRecord(target) ? { ...target } : {};
1726
+ for (const key of Object.keys(source)) {
1727
+ safeAssign(
1728
+ out,
1729
+ key,
1730
+ mergeDeep(safeOwnRead(out, key), safeOwnRead(source, key), [...path, key], schema)
1612
1731
  );
1613
1732
  }
1614
1733
  return out;
@@ -1741,7 +1860,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
1741
1860
  if (!result.ok) return result.error;
1742
1861
  return stripData(composeWithDerivedBlank(result.refinement, result.segments));
1743
1862
  }
1744
- async function process(pathInput) {
1863
+ async function parse(pathInput) {
1745
1864
  const result = await runImperativeValidation(pathInput, {
1746
1865
  cancelInFlight: false,
1747
1866
  commitToSchemaErrors: false
@@ -1794,6 +1913,8 @@ function buildProcessForm(state, formInstanceId, options = {}) {
1794
1913
  state.activeSubmissions.value += 1;
1795
1914
  state.submitting.value = true;
1796
1915
  state.submitError.value = null;
1916
+ state.clearUserErrors();
1917
+ while (state.activeTransforms.value > 0) await state.settleTransforms();
1797
1918
  state.cancelFieldValidation();
1798
1919
  state.displayEngine.clear();
1799
1920
  state.activeValidations.value += 1;
@@ -1832,9 +1953,8 @@ function buildProcessForm(state, formInstanceId, options = {}) {
1832
1953
  state.emitSubmitSuccess();
1833
1954
  } catch (err) {
1834
1955
  if (state.submissionGeneration.value === genAtEntry) {
1835
- state.submitError.value = err;
1956
+ state.submitError.value = toError(err);
1836
1957
  }
1837
- throw err;
1838
1958
  } finally {
1839
1959
  if (!validationSettled) {
1840
1960
  state.activeValidations.value = Math.max(0, state.activeValidations.value - 1);
@@ -1848,7 +1968,7 @@ function buildProcessForm(state, formInstanceId, options = {}) {
1848
1968
  };
1849
1969
  return submitHandler;
1850
1970
  };
1851
- return { validate, validateAsync, process, handleSubmit };
1971
+ return { validate, validateAsync, parse, handleSubmit };
1852
1972
  }
1853
1973
  function toSegments(pathInput) {
1854
1974
  return canonicalizePath(pathInput).segments;
@@ -1906,6 +2026,33 @@ function applyInvalidSubmitPolicy(state, formInstanceId, policy) {
1906
2026
  target.element.focus({ preventScroll: true });
1907
2027
  }
1908
2028
 
2029
+ function captureUserCallSite() {
2030
+ const raw = new Error().stack;
2031
+ if (typeof raw !== "string") return void 0;
2032
+ const lines = raw.split("\n");
2033
+ for (let i = 1; i < lines.length; i++) {
2034
+ const frame = lines[i];
2035
+ if (frame === void 0) continue;
2036
+ if (/attaform[/-]forms?/i.test(frame)) continue;
2037
+ if (/\bforms\.[A-Za-z0-9_-]+\.m?js\b/.test(frame)) continue;
2038
+ const trimmed = frame.trim();
2039
+ if (trimmed.length === 0) continue;
2040
+ return shortenSourceFrame(trimmed);
2041
+ }
2042
+ return void 0;
2043
+ }
2044
+ function shortenSourceFrame(frame) {
2045
+ const match = /(?:^|\s|\()([^\s()]+):(\d+):\d+\)?$/.exec(frame);
2046
+ if (match === null) return frame;
2047
+ const [, urlOrPath, line] = match;
2048
+ if (urlOrPath === void 0 || line === void 0) return frame;
2049
+ let path = urlOrPath;
2050
+ path = path.replace(/^[a-z]+:\/\/[^/]+\//i, "");
2051
+ path = path.replace(/^_nuxt\//, "");
2052
+ path = path.replace(/^\//, "");
2053
+ return `(${path}:${line})`;
2054
+ }
2055
+
1909
2056
  function extractSchemaFields(schema) {
1910
2057
  try {
1911
2058
  const root = schema.getDefaultAtPath([]);
@@ -1964,9 +2111,9 @@ function isLeafValue(value) {
1964
2111
  return true;
1965
2112
  }
1966
2113
  function isSlimPrimitiveValid(schema, store, path, value) {
1967
- return walk$1(schema, store, path, value);
2114
+ return walk(schema, store, path, value);
1968
2115
  }
1969
- function walk$1(schema, store, path, value) {
2116
+ function walk(schema, store, path, value) {
1970
2117
  if (schema.isPreprocessOrCoerceLeaf(path)) return true;
1971
2118
  const accepted = schema.getSlimPrimitiveTypesAtPath(path);
1972
2119
  const kind = isLeafValue(value) ? slimKindOf(value) : Array.isArray(value) ? "array" : "object";
@@ -1976,13 +2123,13 @@ function walk$1(schema, store, path, value) {
1976
2123
  }
1977
2124
  if (Array.isArray(value)) {
1978
2125
  for (let i = 0; i < value.length; i++) {
1979
- if (!walk$1(schema, store, [...path, i], value[i])) return false;
2126
+ if (!walk(schema, store, [...path, i], value[i])) return false;
1980
2127
  }
1981
2128
  return true;
1982
2129
  }
1983
2130
  if (isPlainRecord(value)) {
1984
2131
  for (const key of Object.keys(value)) {
1985
- if (!walk$1(schema, store, [...path, key], value[key])) {
2132
+ if (!walk(schema, store, [...path, key], value[key])) {
1986
2133
  return false;
1987
2134
  }
1988
2135
  }
@@ -2321,6 +2468,23 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2321
2468
  markConnectedOptimistically: () => {
2322
2469
  state.markConnectedOptimistically(segments);
2323
2470
  },
2471
+ // --- Async transform lifecycle (internal; the directive's
2472
+ // deferred orchestrator is the only legitimate consumer). Thin
2473
+ // path-bound delegates to the store's per-path token / counter
2474
+ // machinery — same pattern as `markBlank` / `setValueWithInternalPath`,
2475
+ // so the directive (which holds only this RegisterValue, never the
2476
+ // store) can drive the busy/discard/error bookkeeping. ---
2477
+ beginTransform: (holder) => state.beginTransform(pathKey, holder),
2478
+ isCurrentTransform: (token) => state.isCurrentTransform(pathKey, token),
2479
+ endTransform: (token) => state.endTransform(pathKey, token),
2480
+ setTransformError: (err) => state.setTransformError(pathKey, err),
2481
+ // Synchronous read of "is a transform in flight at this path". The
2482
+ // orchestrator's `beginTransform` bumps the count before the
2483
+ // listener's force-sync block runs, so the directive reads this to
2484
+ // skip reverting the DOM to stale storage mid-flight.
2485
+ get transforming() {
2486
+ return (state.fieldTransformCounts.get(pathKey) ?? 0) > 0;
2487
+ },
2324
2488
  path: pathKey,
2325
2489
  // Frozen so a wrapper component can pass `rv.segments` directly
2326
2490
  // to `form.fields(...)` without defensive copying — and so test
@@ -2365,49 +2529,60 @@ function walkUnsetSentinels(values, schema) {
2365
2529
  walkUnspecified(rootSlim, [], paths);
2366
2530
  return { cleanedValues: void 0, paths };
2367
2531
  }
2368
- const cleaned = walk(values, [], schema, paths);
2532
+ const cleaned = walkCore(values, [], schema, paths, true);
2369
2533
  return { cleanedValues: cleaned, paths };
2370
2534
  }
2371
- function walk(input, segments, schema, paths) {
2535
+ function isOpaqueLeaf(value) {
2536
+ return value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || typeof value === "function";
2537
+ }
2538
+ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2372
2539
  if (isUnset(input)) {
2373
2540
  return expandUnsetAt(segments, schema, paths);
2374
2541
  }
2375
2542
  if (input === void 0) {
2376
- const slim = schema.getDefaultAtPath(segments);
2377
- return walkUnspecified(slim, segments, paths);
2378
- }
2379
- if (input === null) return null;
2380
- if (input instanceof Date || input instanceof RegExp || input instanceof Map || input instanceof Set || typeof input === "function") {
2543
+ if (synthesizeSchemaKeys) {
2544
+ const slim = schema.getDefaultAtPath(segments);
2545
+ return walkUnspecified(slim, segments, paths);
2546
+ }
2381
2547
  return input;
2382
2548
  }
2549
+ if (input === null) return null;
2550
+ if (isOpaqueLeaf(input)) return input;
2383
2551
  if (Array.isArray(input)) {
2384
2552
  const out = new Array(input.length);
2385
2553
  let mutated = false;
2386
2554
  for (let i = 0; i < input.length; i++) {
2387
- const walked = walk(input[i], [...segments, i], schema, paths);
2555
+ const walked = walkCore(input[i], [...segments, i], schema, paths, synthesizeSchemaKeys);
2388
2556
  out[i] = walked;
2389
2557
  if (walked !== input[i]) mutated = true;
2390
2558
  }
2391
2559
  return mutated ? out : input;
2392
2560
  }
2393
2561
  if (typeof input === "object") {
2394
- const slim = schema.getDefaultAtPath(segments);
2395
- const inputKeys = Object.keys(input);
2396
- const inputKeysSet = new Set(inputKeys);
2397
- const allKeys = new Set(inputKeys);
2398
- if (slim !== null && slim !== void 0 && typeof slim === "object" && !Array.isArray(slim) && !(slim instanceof Date) && !(slim instanceof RegExp) && !(slim instanceof Map) && !(slim instanceof Set)) {
2399
- for (const k of Object.keys(slim)) allKeys.add(k);
2562
+ const obj = input;
2563
+ const inputKeys = Object.keys(obj);
2564
+ let keys = inputKeys;
2565
+ let mutated = false;
2566
+ let inputKeysSet = null;
2567
+ if (synthesizeSchemaKeys) {
2568
+ inputKeysSet = new Set(inputKeys);
2569
+ const allKeys = new Set(inputKeys);
2570
+ const slim = schema.getDefaultAtPath(segments);
2571
+ if (slim !== null && slim !== void 0 && typeof slim === "object" && !Array.isArray(slim) && !isOpaqueLeaf(slim)) {
2572
+ for (const k of Object.keys(slim)) allKeys.add(k);
2573
+ }
2574
+ keys = allKeys;
2575
+ mutated = allKeys.size !== inputKeys.length;
2400
2576
  }
2401
2577
  const out = {};
2402
- let mutated = allKeys.size !== inputKeys.length;
2403
- for (const key of allKeys) {
2404
- const orig = input[key];
2405
- if (orig === void 0 && inputKeysSet.has(key)) {
2578
+ for (const key of keys) {
2579
+ const orig = obj[key];
2580
+ if (synthesizeSchemaKeys && orig === void 0 && inputKeysSet?.has(key) === true) {
2406
2581
  safeAssign(out, key, void 0);
2407
2582
  mutated = true;
2408
2583
  continue;
2409
2584
  }
2410
- const walked = walk(orig, [...segments, key], schema, paths);
2585
+ const walked = walkCore(orig, [...segments, key], schema, paths, synthesizeSchemaKeys);
2411
2586
  safeAssign(out, key, walked);
2412
2587
  if (walked !== orig) mutated = true;
2413
2588
  }
@@ -2422,7 +2597,7 @@ function walkUnspecified(slim, segments, paths) {
2422
2597
  }
2423
2598
  return slim;
2424
2599
  }
2425
- if (slim instanceof Date || slim instanceof RegExp || slim instanceof Map || slim instanceof Set || typeof slim === "function") {
2600
+ if (isOpaqueLeaf(slim)) {
2426
2601
  return slim;
2427
2602
  }
2428
2603
  if (Array.isArray(slim)) return slim;
@@ -2441,40 +2616,9 @@ function walkUnspecified(slim, segments, paths) {
2441
2616
  }
2442
2617
  function substituteUnsetSentinels(value, prefix, schema) {
2443
2618
  const paths = [];
2444
- const cleaned = substitute(value, [...prefix], schema, paths);
2619
+ const cleaned = walkCore(value, [...prefix], schema, paths, false);
2445
2620
  return { cleanedValues: cleaned, paths };
2446
2621
  }
2447
- function substitute(input, segments, schema, paths) {
2448
- if (isUnset(input)) {
2449
- return expandUnsetAt(segments, schema, paths);
2450
- }
2451
- if (input === void 0 || input === null) return input;
2452
- if (input instanceof Date || input instanceof RegExp || input instanceof Map || input instanceof Set || typeof input === "function") {
2453
- return input;
2454
- }
2455
- if (Array.isArray(input)) {
2456
- let mutated = false;
2457
- const out = new Array(input.length);
2458
- for (let i = 0; i < input.length; i++) {
2459
- const walked = substitute(input[i], [...segments, i], schema, paths);
2460
- out[i] = walked;
2461
- if (walked !== input[i]) mutated = true;
2462
- }
2463
- return mutated ? out : input;
2464
- }
2465
- if (typeof input === "object") {
2466
- let mutated = false;
2467
- const out = {};
2468
- for (const key of Object.keys(input)) {
2469
- const orig = input[key];
2470
- const walked = substitute(orig, [...segments, key], schema, paths);
2471
- safeAssign(out, key, walked);
2472
- if (walked !== orig) mutated = true;
2473
- }
2474
- return mutated ? out : input;
2475
- }
2476
- return input;
2477
- }
2478
2622
  function isPrimitiveOrEmpty(value) {
2479
2623
  if (value === null || value === void 0) return true;
2480
2624
  const t = typeof value;
@@ -2504,7 +2648,7 @@ function expandUnsetAt(segments, schema, paths) {
2504
2648
  paths.push(canonicalizePath(segments).key);
2505
2649
  return slim;
2506
2650
  }
2507
- if (slim instanceof Date || slim instanceof RegExp || slim instanceof Map || slim instanceof Set || typeof slim === "function") {
2651
+ if (isOpaqueLeaf(slim)) {
2508
2652
  paths.push(canonicalizePath(segments).key);
2509
2653
  return slim;
2510
2654
  }
@@ -2519,7 +2663,9 @@ function expandUnsetAt(segments, schema, paths) {
2519
2663
  function buildCallableReadonlySnapshotProxy(opts) {
2520
2664
  const target = (() => {
2521
2665
  });
2522
- const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(opts.snapshot);
2666
+ const { toString, valueOf, toJSON, toPrimitive } = makeReadonlyCoercion(
2667
+ opts.coercionSnapshot ?? opts.snapshot
2668
+ );
2523
2669
  const callResolve = opts.resolveCall ?? ((arg) => opts.resolveKey(String(arg)));
2524
2670
  return new Proxy(target, {
2525
2671
  apply(_, __, args) {
@@ -2568,27 +2714,52 @@ function buildCallableReadonlySnapshotProxy(opts) {
2568
2714
  });
2569
2715
  }
2570
2716
 
2717
+ function materializeFormValue(node) {
2718
+ if (node === null || typeof node !== "object") return node;
2719
+ if (Array.isArray(node)) {
2720
+ const out2 = new Array(node.length);
2721
+ for (let i = 0; i < node.length; i++) out2[i] = materializeFormValue(node[i]);
2722
+ return out2;
2723
+ }
2724
+ if (!isPlainRecord(node)) return toRaw(node);
2725
+ const rec = node;
2726
+ const out = {};
2727
+ for (const key of Object.keys(rec)) {
2728
+ safeAssign(out, key, materializeFormValue(safeOwnRead(rec, key)));
2729
+ }
2730
+ return out;
2731
+ }
2571
2732
  function buildValuesProxy(form) {
2572
2733
  const inner = computed(() => readonly(form.value));
2573
2734
  return buildCallableReadonlySnapshotProxy({
2574
2735
  surface: "form.values",
2575
2736
  snapshot: () => inner.value,
2737
+ // Faithful, reactivity-preserving serialisation: walk the reactive
2738
+ // proxy with own-safe reads so `JSON.stringify(form.values)` /
2739
+ // `String(form.values)` reflect the stored data — including a field
2740
+ // literally named `hasOwnProperty` that Vue would otherwise shim —
2741
+ // while still tracking the per-key reads that drive re-render.
2742
+ coercionSnapshot: () => materializeFormValue(inner.value),
2576
2743
  // Read through the readonly proxy at access time so Vue's
2577
2744
  // dependency tracking lands inside the consumer's active effect
2578
2745
  // — `inner.value[key]` is what triggers per-key tracking.
2579
- resolveKey: (key) => inner.value[key],
2580
- // Dynamic path: walk segments through the readonly proxy. Each
2581
- // step reads through the proxy's own get traps so dependency
2582
- // tracking propagates at every level.
2583
- resolveCall: (arg) => {
2584
- const { segments } = canonicalizePath(arg);
2585
- let cursor = inner.value;
2586
- for (const seg of segments) {
2587
- if (cursor === null || cursor === void 0) return void 0;
2588
- cursor = cursor[seg];
2589
- }
2590
- return cursor;
2591
- },
2746
+ //
2747
+ // Prototype-shadowed names (`hasOwnProperty`, `constructor`, …) read
2748
+ // off the RAW target instead: own-shadows-inherited semantics still
2749
+ // hold (a data field by that name returns its stored value), but
2750
+ // when there's no such field the inherited member resolves — so
2751
+ // `form.values.hasOwnProperty('x')` keeps working as the real
2752
+ // method. The raw read dodges Vue's `hasOwnProperty` proxy shim,
2753
+ // which would otherwise mask a data field of that name. (`toString`
2754
+ // / `valueOf` / `toJSON` never reach here the base get trap
2755
+ // intercepts them as coercion handlers first.)
2756
+ resolveKey: (key) => isShadowedKey(key) ? toRaw(inner.value)[key] : inner.value[key],
2757
+ // Dynamic path: walk segments through the readonly proxy with the
2758
+ // same own-property-safe descent the rest of the runtime uses
2759
+ // (`getAtPath`), so `form.values('a.hasOwnProperty')` resolves the
2760
+ // stored value. Per-level reads still propagate Vue's tracking for
2761
+ // ordinary keys.
2762
+ resolveCall: (arg) => getAtPath(inner.value, canonicalizePath(arg).segments),
2592
2763
  ownKeys: () => Reflect.ownKeys(inner.value),
2593
2764
  hasKey: (key) => Reflect.has(inner.value, key),
2594
2765
  describeKey: (key) => {
@@ -2611,6 +2782,17 @@ function buildFormApi(state, formInstanceId, options = {}) {
2611
2782
  if (instanceMeta === void 0) return meta;
2612
2783
  return meta === void 0 ? { instance: instanceMeta } : { ...meta, instance: instanceMeta };
2613
2784
  };
2785
+ const reMarkBlanksAfterSubstitution = (paths) => {
2786
+ for (const pathKey of paths) {
2787
+ const blankSegments = segmentsForPathKey(pathKey);
2788
+ if (blankSegments === null) continue;
2789
+ state.setValueAtPath(
2790
+ blankSegments,
2791
+ state.getValueAtPath(blankSegments),
2792
+ withInstanceMeta({ blank: true })
2793
+ );
2794
+ }
2795
+ };
2614
2796
  const getFormMetaBase = () => {
2615
2797
  const { base: rootBase } = buildContainerFieldStateBase(
2616
2798
  state,
@@ -2649,12 +2831,12 @@ function buildFormApi(state, formInstanceId, options = {}) {
2649
2831
  const {
2650
2832
  validate: validateBuilt,
2651
2833
  validateAsync: validateAsyncBuilt,
2652
- process: processBuilt,
2834
+ parse: parseBuilt,
2653
2835
  handleSubmit
2654
2836
  } = buildProcessForm(state, formInstanceId, processOptions);
2655
2837
  const validate = (pathInput) => validateBuilt(pathInput);
2656
2838
  const validateAsync = (pathInput) => validateAsyncBuilt(pathInput);
2657
- const process = (pathInput) => processBuilt(pathInput);
2839
+ const parse = (pathInput) => parseBuilt(pathInput);
2658
2840
  function pathToRef(pathInput) {
2659
2841
  const segments = canonicalizePath(pathInput).segments;
2660
2842
  return computed(() => getAtPath(state.form.value, segments));
@@ -2668,15 +2850,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2668
2850
  );
2669
2851
  const ok2 = state.setValueAtPath([], walked2.cleanedValues, withInstanceMeta());
2670
2852
  if (!ok2) return false;
2671
- for (const pathKey of walked2.paths) {
2672
- const blankSegments = segmentsForPathKey(pathKey);
2673
- if (blankSegments === null) continue;
2674
- state.setValueAtPath(
2675
- blankSegments,
2676
- state.getValueAtPath(blankSegments),
2677
- withInstanceMeta({ blank: true })
2678
- );
2679
- }
2853
+ reMarkBlanksAfterSubstitution(walked2.paths);
2680
2854
  return true;
2681
2855
  }
2682
2856
  const segments = canonicalizePath(pathOrValue).segments;
@@ -2731,15 +2905,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2731
2905
  );
2732
2906
  const ok = state.setValueAtPath(segments, walked.cleanedValues, withInstanceMeta());
2733
2907
  if (!ok) return false;
2734
- for (const pathKey of walked.paths) {
2735
- const blankSegments = segmentsForPathKey(pathKey);
2736
- if (blankSegments === null) continue;
2737
- state.setValueAtPath(
2738
- blankSegments,
2739
- state.getValueAtPath(blankSegments),
2740
- withInstanceMeta({ blank: true })
2741
- );
2742
- }
2908
+ reMarkBlanksAfterSubstitution(walked.paths);
2743
2909
  return true;
2744
2910
  }
2745
2911
  const errorsProxy = buildErrorsProxy(state);
@@ -2882,6 +3048,21 @@ function buildFormApi(state, formInstanceId, options = {}) {
2882
3048
  // keep the explicit form-level computation for the gate.
2883
3049
  valid,
2884
3050
  errors: metaErrors,
3051
+ // Whole-form transforming mirrors the global `activeTransforms`
3052
+ // counter ORed with any per-leaf transform in flight (the root
3053
+ // rollup), exactly as `validating` composes its lifecycle and
3054
+ // per-field sources. `busy` is the union of both work signals at
3055
+ // the form level. `transformError` is leaf-only, so the root
3056
+ // rollup reads it as `null` (kept for FieldState-shape parity).
3057
+ transforming: computed(
3058
+ () => state.activeTransforms.value > 0 || rootFieldState.value.transforming
3059
+ ),
3060
+ busy: computed(
3061
+ () => state.activeValidations.value > 0 || state.activeTransforms.value > 0 || rootFieldState.value.validating || rootFieldState.value.transforming
3062
+ ),
3063
+ get transformError() {
3064
+ return rootFieldState.value.transformError;
3065
+ },
2885
3066
  // `displayState` / the `show*` booleans / `firstError` flow
2886
3067
  // through the same root field-state computed as the rest of the
2887
3068
  // FieldState surface, so `form.meta.displayState` matches
@@ -3110,7 +3291,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
3110
3291
  setValue: gated(setValueImpl),
3111
3292
  validate: gated(validate),
3112
3293
  validateAsync: gated(validateAsync),
3113
- process: gated(process),
3294
+ parse: gated(parse),
3295
+ settleTransforms: gated(state.settleTransforms),
3114
3296
  register: gated(register),
3115
3297
  key: state.formKey,
3116
3298
  // Auto-unwrapping views over the per-store async-defaults lifecycle
@@ -3977,6 +4159,106 @@ function createFormStore(options) {
3977
4159
  fieldValidationCounts.set(key, next);
3978
4160
  }
3979
4161
  }
4162
+ const fieldTransformCounts = reactive(/* @__PURE__ */ new Map());
4163
+ const fieldTransformingSince = reactive(/* @__PURE__ */ new Map());
4164
+ const transformErrors = reactive(/* @__PURE__ */ new Map());
4165
+ const activeTransforms = ref(0);
4166
+ const transformRuns = /* @__PURE__ */ new Map();
4167
+ let transformTokenSeq = 0;
4168
+ const transformWaiters = [];
4169
+ function incFieldTransform(key) {
4170
+ fieldTransformingSince.set(key, ssr ? 0 : Date.now());
4171
+ fieldTransformCounts.set(key, (fieldTransformCounts.get(key) ?? 0) + 1);
4172
+ }
4173
+ function decFieldTransform(key) {
4174
+ const next = (fieldTransformCounts.get(key) ?? 0) - 1;
4175
+ if (next <= 0) {
4176
+ fieldTransformCounts.delete(key);
4177
+ fieldTransformingSince.delete(key);
4178
+ } else {
4179
+ fieldTransformCounts.set(key, next);
4180
+ }
4181
+ }
4182
+ function flushSettledTransformWaiters() {
4183
+ if (transformWaiters.length === 0) return;
4184
+ const globalIdle = activeTransforms.value === 0;
4185
+ for (let i = transformWaiters.length - 1; i >= 0; i--) {
4186
+ const w = transformWaiters[i];
4187
+ if (w === void 0) continue;
4188
+ const idle = w.key === null ? globalIdle : (fieldTransformCounts.get(w.key) ?? 0) === 0;
4189
+ if (idle) {
4190
+ transformWaiters.splice(i, 1);
4191
+ w.resolve();
4192
+ }
4193
+ }
4194
+ }
4195
+ function releaseTransformRun(key, run) {
4196
+ if (run.released) return;
4197
+ run.released = true;
4198
+ run.holder.aborted = true;
4199
+ run.holder.controller?.abort();
4200
+ activeTransforms.value = Math.max(0, activeTransforms.value - 1);
4201
+ decFieldTransform(key);
4202
+ }
4203
+ function beginTransform(key, holder) {
4204
+ const prior = transformRuns.get(key);
4205
+ if (prior !== void 0) releaseTransformRun(key, prior);
4206
+ const token = ++transformTokenSeq;
4207
+ transformRuns.set(key, { token, holder, released: false });
4208
+ incFieldTransform(key);
4209
+ activeTransforms.value += 1;
4210
+ if (transformErrors.has(key)) transformErrors.delete(key);
4211
+ return token;
4212
+ }
4213
+ function isCurrentTransform(key, token) {
4214
+ return transformRuns.get(key)?.token === token;
4215
+ }
4216
+ function endTransform(key, token) {
4217
+ const run = transformRuns.get(key);
4218
+ if (run?.token === token) {
4219
+ if (!run.released) {
4220
+ activeTransforms.value = Math.max(0, activeTransforms.value - 1);
4221
+ decFieldTransform(key);
4222
+ }
4223
+ transformRuns.delete(key);
4224
+ }
4225
+ flushSettledTransformWaiters();
4226
+ }
4227
+ function setTransformError(key, err) {
4228
+ transformErrors.set(key, err);
4229
+ }
4230
+ function cancelTransforms() {
4231
+ for (const [key, run] of [...transformRuns]) {
4232
+ releaseTransformRun(key, run);
4233
+ transformRuns.delete(key);
4234
+ }
4235
+ if (transformErrors.size > 0) transformErrors.clear();
4236
+ flushSettledTransformWaiters();
4237
+ }
4238
+ function cancelTransformsUnder(prefix) {
4239
+ for (const [key, run] of [...transformRuns]) {
4240
+ const segs = segmentsForPathKey(key);
4241
+ if (segs === null) continue;
4242
+ if (!isPathPrefix(prefix, segs)) continue;
4243
+ releaseTransformRun(key, run);
4244
+ transformRuns.delete(key);
4245
+ transformErrors.delete(key);
4246
+ }
4247
+ flushSettledTransformWaiters();
4248
+ }
4249
+ function settleTransforms(path) {
4250
+ if (path === void 0) {
4251
+ if (activeTransforms.value === 0) return Promise.resolve();
4252
+ return new Promise((resolve) => {
4253
+ transformWaiters.push({ key: null, resolve });
4254
+ });
4255
+ }
4256
+ const { key } = canonicalizePath(path);
4257
+ if ((fieldTransformCounts.get(key) ?? 0) === 0) return Promise.resolve();
4258
+ return new Promise((resolve) => {
4259
+ transformWaiters.push({ key, resolve });
4260
+ });
4261
+ }
3980
4262
  const initStamp = (/* @__PURE__ */ new Date()).toISOString();
3981
4263
  diffAndApply({}, schemaInitialData, [], (patch) => {
3982
4264
  if (patch.kind !== "added") return;
@@ -4126,6 +4408,7 @@ function createFormStore(options) {
4126
4408
  }
4127
4409
  }
4128
4410
  }
4411
+ if (transformRuns.size !== 0) cancelTransformsUnder(path);
4129
4412
  if (meta?.skipDiscriminatorReshape !== true) {
4130
4413
  if (path.length > 0) {
4131
4414
  const last = path[path.length - 1];
@@ -4460,6 +4743,7 @@ function createFormStore(options) {
4460
4743
  drainHooks.length = 0;
4461
4744
  modules.clear();
4462
4745
  cancelFieldValidation();
4746
+ cancelTransforms();
4463
4747
  fieldValidatingSince.clear();
4464
4748
  formChangeListeners.clear();
4465
4749
  submitSuccessListeners.clear();
@@ -4596,6 +4880,7 @@ function createFormStore(options) {
4596
4880
  if (remaining === 0) {
4597
4881
  elements.delete(key);
4598
4882
  touchFieldRecord(key, path, { connected: false, focused: null, blurred: null });
4883
+ if (transformRuns.size !== 0) cancelTransformsUnder(path);
4599
4884
  }
4600
4885
  return remaining;
4601
4886
  }
@@ -4817,6 +5102,7 @@ function createFormStore(options) {
4817
5102
  submitError.value = null;
4818
5103
  departAttempts.value = 0;
4819
5104
  cancelFieldValidation();
5105
+ cancelTransforms();
4820
5106
  displayEngine.clear();
4821
5107
  fieldValidatingSince.clear();
4822
5108
  pathSnapshots.clear();
@@ -4835,6 +5121,7 @@ function createFormStore(options) {
4835
5121
  const { key: targetKey, segments: targetSegments } = canonicalizePath(path);
4836
5122
  variantMemory.clearUnderPath(targetSegments);
4837
5123
  cancelFieldValidationUnder(targetSegments);
5124
+ cancelTransformsUnder(targetSegments);
4838
5125
  for (const [snapKey] of [...pathSnapshots]) {
4839
5126
  const segs = segmentsForPathKey(snapKey);
4840
5127
  if (segs === null) continue;
@@ -4970,6 +5257,10 @@ function createFormStore(options) {
4970
5257
  pathHasAsyncValidationByKey,
4971
5258
  fieldValidationCounts,
4972
5259
  fieldValidatingSince,
5260
+ fieldTransformCounts,
5261
+ fieldTransformingSince,
5262
+ transformErrors,
5263
+ activeTransforms,
4973
5264
  displayEngine,
4974
5265
  applyFormReplacement,
4975
5266
  setValueAtPath,
@@ -4999,6 +5290,13 @@ function createFormStore(options) {
4999
5290
  getOriginalAtPath,
5000
5291
  getFirstErrorElement,
5001
5292
  cancelFieldValidation,
5293
+ beginTransform,
5294
+ isCurrentTransform,
5295
+ endTransform,
5296
+ setTransformError,
5297
+ cancelTransforms,
5298
+ cancelTransformsUnder,
5299
+ settleTransforms,
5002
5300
  scheduleFieldValidation,
5003
5301
  onFormChange,
5004
5302
  onSubmitSuccess,
@@ -5030,6 +5328,20 @@ function captureErrorEntries(map) {
5030
5328
  for (const [k, v] of map) out.push([k, [...v]]);
5031
5329
  return out;
5032
5330
  }
5331
+ function pathsEqual(a, b) {
5332
+ if (a.length !== b.length) return false;
5333
+ for (let j = 0; j < a.length; j++) {
5334
+ if (a[j] !== b[j]) return false;
5335
+ }
5336
+ return true;
5337
+ }
5338
+ function errorFieldsEqual(av, bvi) {
5339
+ if (av === bvi) return true;
5340
+ if (av.message !== bvi.message) return false;
5341
+ if (av.code !== bvi.code) return false;
5342
+ if (av.formKey !== bvi.formKey) return false;
5343
+ return av.path === bvi.path || pathsEqual(av.path, bvi.path);
5344
+ }
5033
5345
  function errorsEqual(a, b) {
5034
5346
  if (a.length !== b.length) return false;
5035
5347
  const bMap = /* @__PURE__ */ new Map();
@@ -5039,18 +5351,7 @@ function errorsEqual(a, b) {
5039
5351
  if (bv === void 0) return false;
5040
5352
  if (v.length !== bv.length) return false;
5041
5353
  for (let i = 0; i < v.length; i++) {
5042
- const av = v[i];
5043
- const bvi = bv[i];
5044
- if (av === bvi) continue;
5045
- if (av.message !== bvi.message) return false;
5046
- if (av.code !== bvi.code) return false;
5047
- if (av.formKey !== bvi.formKey) return false;
5048
- if (av.path !== bvi.path) {
5049
- if (av.path.length !== bvi.path.length) return false;
5050
- for (let j = 0; j < av.path.length; j++) {
5051
- if (av.path[j] !== bvi.path[j]) return false;
5052
- }
5053
- }
5354
+ if (!errorFieldsEqual(v[i], bv[i])) return false;
5054
5355
  }
5055
5356
  }
5056
5357
  return true;
@@ -5632,6 +5933,99 @@ function warnIfAmbientProviderHadDuplicates() {
5632
5933
  }
5633
5934
  }
5634
5935
 
5936
+ const warnedNoParentRV = __DEV__ ? /* @__PURE__ */ new WeakSet() : null;
5937
+ let warnedOutsideSetup = false;
5938
+ function makeRegisterValueProxy(capturedRegisterValue) {
5939
+ return new Proxy({}, {
5940
+ get(_target, prop) {
5941
+ if (prop === "__v_isRef") return true;
5942
+ if (prop === "value") return capturedRegisterValue.value;
5943
+ const v = capturedRegisterValue.value;
5944
+ if (v === void 0) return void 0;
5945
+ return Reflect.get(v, prop);
5946
+ },
5947
+ has(_target, prop) {
5948
+ if (prop === "__v_isRef" || prop === "value") return true;
5949
+ const v = capturedRegisterValue.value;
5950
+ if (v === void 0) return false;
5951
+ return Reflect.has(v, prop);
5952
+ },
5953
+ ownKeys(_target) {
5954
+ const v = capturedRegisterValue.value;
5955
+ if (v === void 0) return [];
5956
+ return Reflect.ownKeys(v);
5957
+ },
5958
+ getOwnPropertyDescriptor(_target, prop) {
5959
+ const v = capturedRegisterValue.value;
5960
+ if (v === void 0) return void 0;
5961
+ const desc = Reflect.getOwnPropertyDescriptor(v, prop);
5962
+ if (desc !== void 0) {
5963
+ desc.configurable = true;
5964
+ }
5965
+ return desc;
5966
+ }
5967
+ });
5968
+ }
5969
+ function useRegister() {
5970
+ const instance = getCurrentInstance();
5971
+ if (instance === null) {
5972
+ warnOutsideSetup();
5973
+ return makeRegisterValueProxy(shallowRef(void 0));
5974
+ }
5975
+ ensureAttaformInstalled(instance.appContext.app);
5976
+ const capturedRegisterValue = shallowRef(void 0);
5977
+ const refreshAndStripBridgeAttrs = () => {
5978
+ const rawAttrs = instance.attrs;
5979
+ if ("registerValue" in rawAttrs) {
5980
+ capturedRegisterValue.value = rawAttrs["registerValue"];
5981
+ delete rawAttrs["registerValue"];
5982
+ } else {
5983
+ const dirs = instance.vnode.dirs;
5984
+ if (dirs !== null && dirs !== void 0) {
5985
+ for (const dir of dirs) {
5986
+ const marked = dir.dir?.[V_REGISTER_MARKER];
5987
+ if (marked === true) {
5988
+ capturedRegisterValue.value = dir.value;
5989
+ break;
5990
+ }
5991
+ }
5992
+ }
5993
+ }
5994
+ if ("value" in rawAttrs) delete rawAttrs["value"];
5995
+ };
5996
+ refreshAndStripBridgeAttrs();
5997
+ onBeforeMount(refreshAndStripBridgeAttrs);
5998
+ onBeforeUpdate(refreshAndStripBridgeAttrs);
5999
+ onMounted(() => {
6000
+ const el = instance.vnode.el;
6001
+ if (el !== null && el !== void 0 && typeof el === "object") {
6002
+ el[REGISTER_OWNER_MARKER] = true;
6003
+ }
6004
+ if (capturedRegisterValue.value === void 0) {
6005
+ warnNoParentRV(instance);
6006
+ }
6007
+ });
6008
+ return makeRegisterValueProxy(capturedRegisterValue);
6009
+ }
6010
+ function warnOutsideSetup() {
6011
+ if (!__DEV__) return;
6012
+ if (warnedOutsideSetup) return;
6013
+ warnedOutsideSetup = true;
6014
+ const frame = captureUserCallSite();
6015
+ console.warn(
6016
+ `[attaform] useRegister() called outside a component setup; returning an unbound RegisterValue proxy. Fix: call it inside <script setup> or a setup() function \u2014 not from an event handler or async callback.` + (frame !== void 0 ? ` ${frame}` : "")
6017
+ );
6018
+ }
6019
+ function warnNoParentRV(instance) {
6020
+ if (!__DEV__ || warnedNoParentRV === null) return;
6021
+ if (warnedNoParentRV.has(instance)) return;
6022
+ warnedNoParentRV.add(instance);
6023
+ const frame = captureUserCallSite();
6024
+ console.warn(
6025
+ `[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}` : "")
6026
+ );
6027
+ }
6028
+
5635
6029
  const LAZY_BRAND = Symbol.for("attaform/wizard-lazy");
5636
6030
  function lazy(resolve) {
5637
6031
  return { [LAZY_BRAND]: true, resolve };
@@ -5641,6 +6035,8 @@ function isLazyMarker(value) {
5641
6035
  }
5642
6036
 
5643
6037
  const NOOP_WIZARD_HISTORY = {
6038
+ push() {
6039
+ },
5644
6040
  replace() {
5645
6041
  },
5646
6042
  read() {
@@ -5655,6 +6051,9 @@ function createWizardHistory(param) {
5655
6051
  if (typeof window === "undefined") return NOOP_WIZARD_HISTORY;
5656
6052
  const subscribers = [];
5657
6053
  let disposed = false;
6054
+ function currentKey() {
6055
+ return new URL(window.location.href).searchParams.get(param) ?? void 0;
6056
+ }
5658
6057
  function buildUrl(key) {
5659
6058
  const url = new URL(window.location.href);
5660
6059
  url.searchParams.set(param, key);
@@ -5662,25 +6061,29 @@ function createWizardHistory(param) {
5662
6061
  }
5663
6062
  function handlePopstate() {
5664
6063
  if (disposed) return;
5665
- const url = new URL(window.location.href);
5666
- const value = url.searchParams.get(param) ?? void 0;
6064
+ const value = currentKey();
5667
6065
  for (const subscriber of subscribers) subscriber(value);
5668
6066
  }
5669
6067
  window.addEventListener("popstate", handlePopstate);
5670
- function safeReplaceState(key) {
6068
+ function safeWrite(key, mode) {
5671
6069
  try {
5672
- window.history.replaceState({}, "", buildUrl(key));
6070
+ if (mode === "push") window.history.pushState({}, "", buildUrl(key));
6071
+ else window.history.replaceState({}, "", buildUrl(key));
5673
6072
  } catch {
5674
6073
  }
5675
6074
  }
5676
6075
  return {
6076
+ push(key) {
6077
+ if (disposed) return;
6078
+ if (currentKey() === key) return;
6079
+ safeWrite(key, "push");
6080
+ },
5677
6081
  replace(key) {
5678
6082
  if (disposed) return;
5679
- safeReplaceState(key);
6083
+ safeWrite(key, "replace");
5680
6084
  },
5681
6085
  read() {
5682
- const url = new URL(window.location.href);
5683
- return url.searchParams.get(param) ?? void 0;
6086
+ return currentKey();
5684
6087
  },
5685
6088
  subscribe(callback) {
5686
6089
  if (disposed) return;
@@ -5718,6 +6121,7 @@ function buildNoopWizardSchema(formKey) {
5718
6121
  getEmptyValueAtPath: () => void 0,
5719
6122
  isPreprocessOrCoerceLeaf: () => false,
5720
6123
  arrayShapeAtPath: () => void 0,
6124
+ isFixedObjectAtPath: (path) => path.length === 0,
5721
6125
  getSchemasAtPath: () => [],
5722
6126
  validateAtPath: () => success,
5723
6127
  getSlimPrimitiveTypesAtPath: () => new Set(EMPTY_SLIM_KINDS),
@@ -6171,7 +6575,10 @@ function useWizard(options) {
6171
6575
  };
6172
6576
  const persistCallback = options.persist === false ? void 0 : options.persist !== void 0 ? options.persist : (state) => {
6173
6577
  if (state.step === void 0) return;
6174
- historyHandle.replace(state.step);
6578
+ const current = historyHandle.read();
6579
+ const effectiveCurrent = current !== void 0 && isCompiledKey(current) ? current : firstKey();
6580
+ if (state.step === effectiveCurrent) historyHandle.replace(state.step);
6581
+ else historyHandle.push(state.step);
6175
6582
  };
6176
6583
  function isCompiledKey(key) {
6177
6584
  const list = compiledSteps.value;
@@ -6252,6 +6659,7 @@ function useWizard(options) {
6252
6659
  }
6253
6660
  const submitting = ref(false);
6254
6661
  const submissionAttempts = ref(0);
6662
+ const submitError = ref(null);
6255
6663
  const done = ref(false);
6256
6664
  function activateForm(form) {
6257
6665
  const source = asSubmissionSource(form);
@@ -6379,7 +6787,7 @@ function useWizard(options) {
6379
6787
  formKey: form.key
6380
6788
  };
6381
6789
  }
6382
- return full.process();
6790
+ return full.parse();
6383
6791
  }
6384
6792
  function collectErrors(results) {
6385
6793
  const out = [];
@@ -6410,6 +6818,7 @@ function useWizard(options) {
6410
6818
  return;
6411
6819
  }
6412
6820
  submitting.value = true;
6821
+ submitError.value = null;
6413
6822
  try {
6414
6823
  const currentKey = activeKey.value;
6415
6824
  const final = isFinalStep.value;
@@ -6418,12 +6827,14 @@ function useWizard(options) {
6418
6827
  if (final) {
6419
6828
  await Promise.all(
6420
6829
  list.map(async (step) => {
6830
+ registry.forms.get(step.key)?.clearUserErrors();
6421
6831
  const result = await processOne(step.form);
6422
6832
  results.set(step.key, result);
6423
6833
  })
6424
6834
  );
6425
6835
  } else {
6426
6836
  const active = activeForm.value;
6837
+ registry.forms.get(active.key)?.clearUserErrors();
6427
6838
  const result = await processOne(active);
6428
6839
  results.set(active.key, result);
6429
6840
  }
@@ -6458,7 +6869,6 @@ function useWizard(options) {
6458
6869
  if (target !== void 0) moveTo(target.key);
6459
6870
  }
6460
6871
  } else {
6461
- if (onError !== void 0) await onError(errors);
6462
6872
  if (options.focusFirstError !== false) {
6463
6873
  const firstFailedKey = errors[0]?.formKey;
6464
6874
  if (firstFailedKey !== void 0 && isCompiledKey(firstFailedKey)) {
@@ -6473,7 +6883,16 @@ function useWizard(options) {
6473
6883
  }
6474
6884
  }
6475
6885
  }
6886
+ if (onError !== void 0) {
6887
+ try {
6888
+ await onError(errors);
6889
+ } catch (cause) {
6890
+ throw new SubmitErrorHandlerError("User-provided onError threw", { cause });
6891
+ }
6892
+ }
6476
6893
  }
6894
+ } catch (err) {
6895
+ submitError.value = toError(err);
6477
6896
  } finally {
6478
6897
  submitting.value = false;
6479
6898
  }
@@ -6482,6 +6901,7 @@ function useWizard(options) {
6482
6901
  function reset() {
6483
6902
  submissionAttempts.value = 0;
6484
6903
  done.value = false;
6904
+ submitError.value = null;
6485
6905
  lazyEpoch.value += 1;
6486
6906
  for (const step of compiledSteps.value) {
6487
6907
  const full = asSubmissionSource(step.form);
@@ -6557,6 +6977,9 @@ function useWizard(options) {
6557
6977
  get submissionAttempts() {
6558
6978
  return submissionAttempts.value;
6559
6979
  },
6980
+ get submitError() {
6981
+ return submitError.value;
6982
+ },
6560
6983
  get visited() {
6561
6984
  return visited.value;
6562
6985
  }
@@ -6666,5 +7089,5 @@ function warnIfAmbientWizardProviderHadDuplicates() {
6666
7089
  }
6667
7090
  }
6668
7091
 
6669
- export { AttaformErrorCode as A, useAbstractForm as B, useWizard as C, DEFAULT_PERSISTENCE_DEBOUNCE_MS as D, PERSISTENCE_MODULE_KEY as P, DEFAULT_TIMINGS as a, applyPatchesForward as b, cleanupOrphanKeys as c, defaultCoercionRules as d, defaultDisplayState as e, defineCoercion as f, deleteAtPath as g, diffAndApply as h, getAtPath as i, humanize as j, injectForm as k, injectWizard as l, isPlainRecord as m, isUnset as n, lazy as o, makeDefaultDisplayState as p, mergeSparseHydration as q, normalizeNumericOption as r, normalizePersistConfig as s, resolveStorageKeyBase as t, safeAssign as u, safeOwnRead as v, setAtPath as w, slimKindOf as x, structuralSnapshot as y, unset as z };
6670
- //# sourceMappingURL=attaform.DSqO6Db7.mjs.map
7092
+ export { AttaformErrorCode as A, deleteAtPath as B, safeOwnRead as C, DEFAULT_TIMINGS as D, humanize as E, PERSISTENCE_MODULE_KEY as P, injectWizard as a, isUnset as b, useRegister as c, useWizard as d, isPlainRecord as e, safeAssign as f, diffAndApply as g, slimKindOf as h, injectForm as i, applyPatchesForward as j, normalizeNumericOption as k, lazy as l, defaultCoercionRules as m, normalizePersistConfig as n, defaultDisplayState as o, defineCoercion as p, makeDefaultDisplayState as q, useAbstractForm as r, structuralSnapshot as s, getAtPath as t, unset as u, setAtPath as v, resolveStorageKeyBase as w, DEFAULT_PERSISTENCE_DEBOUNCE_MS as x, cleanupOrphanKeys as y, mergeSparseHydration as z };
7093
+ //# sourceMappingURL=attaform.CTheKoTc.mjs.map