attaform 0.25.0 → 0.26.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 (70) hide show
  1. package/dist/chunks/devtools.cjs +1 -1
  2. package/dist/chunks/devtools.mjs +1 -1
  3. package/dist/chunks/fingerprint2.cjs +1 -1
  4. package/dist/chunks/fingerprint2.mjs +1 -1
  5. package/dist/index.cjs +3 -3
  6. package/dist/index.d.cts +5 -5
  7. package/dist/index.d.mts +5 -5
  8. package/dist/index.d.ts +5 -5
  9. package/dist/index.mjs +3 -3
  10. package/dist/nuxt.d.cts +1 -1
  11. package/dist/nuxt.d.mts +1 -1
  12. package/dist/nuxt.d.ts +1 -1
  13. package/dist/runtime/plugins/attaform.cjs +2 -2
  14. package/dist/runtime/plugins/attaform.mjs +2 -2
  15. package/dist/shared/{attaform.CO0e7YVY.d.cts → attaform.55hFR_cl.d.ts} +3 -0
  16. package/dist/shared/{attaform.BJt4ZCkM.d.mts → attaform.B71rfNL5.d.mts} +1 -1
  17. package/dist/shared/{attaform.DmKLa4tL.d.cts → attaform.BFfY7HRI.d.cts} +1 -1
  18. package/dist/shared/{attaform.3heDHayA.cjs → attaform.BPl-ECRT.cjs} +25 -1
  19. package/dist/shared/attaform.BPl-ECRT.cjs.map +1 -0
  20. package/dist/shared/{attaform.B5YcWrKi.cjs → attaform.BQflyVOL.cjs} +3 -3
  21. package/dist/shared/{attaform.B5YcWrKi.cjs.map → attaform.BQflyVOL.cjs.map} +1 -1
  22. package/dist/shared/{attaform.B3cgZE3c.d.ts → attaform.Be5otUVw.d.ts} +1 -1
  23. package/dist/shared/{attaform.DK3xUBkj.mjs → attaform.BoYqnIPI.mjs} +109 -45
  24. package/dist/shared/attaform.BoYqnIPI.mjs.map +1 -0
  25. package/dist/shared/{attaform.B5GFS3Su.d.cts → attaform.CEY_WLRJ.d.mts} +12 -1
  26. package/dist/shared/{attaform.DMNnfQq_.mjs → attaform.CSXDW2tO.mjs} +4 -4
  27. package/dist/shared/{attaform.DMNnfQq_.mjs.map → attaform.CSXDW2tO.mjs.map} +1 -1
  28. package/dist/shared/{attaform.CwXXbZIQ.mjs → attaform.CXVmZtFq.mjs} +3 -3
  29. package/dist/shared/{attaform.CwXXbZIQ.mjs.map → attaform.CXVmZtFq.mjs.map} +1 -1
  30. package/dist/shared/{attaform.sks1MFVO.cjs → attaform.Cs0UZ7q6.cjs} +4 -4
  31. package/dist/shared/{attaform.sks1MFVO.cjs.map → attaform.Cs0UZ7q6.cjs.map} +1 -1
  32. package/dist/shared/{attaform.xBDo0Ko0.cjs → attaform.D51IwDtP.cjs} +2 -2
  33. package/dist/shared/{attaform.xBDo0Ko0.cjs.map → attaform.D51IwDtP.cjs.map} +1 -1
  34. package/dist/shared/{attaform.i_LA3X9o.d.cts → attaform.DBNjHgNj.d.cts} +70 -15
  35. package/dist/shared/{attaform.i_LA3X9o.d.mts → attaform.DBNjHgNj.d.mts} +70 -15
  36. package/dist/shared/{attaform.i_LA3X9o.d.ts → attaform.DBNjHgNj.d.ts} +70 -15
  37. package/dist/shared/{attaform.CqwcTExO.mjs → attaform.DGhIix5D.mjs} +24 -2
  38. package/dist/shared/attaform.DGhIix5D.mjs.map +1 -0
  39. package/dist/shared/{attaform.CO0e7YVY.d.mts → attaform.DJRz_bzM.d.cts} +3 -0
  40. package/dist/shared/{attaform.CN4ZEGo6.mjs → attaform.DSOIz08n.mjs} +4 -4
  41. package/dist/shared/{attaform.CN4ZEGo6.mjs.map → attaform.DSOIz08n.mjs.map} +1 -1
  42. package/dist/shared/{attaform.BkUzunyB.cjs → attaform.Du9RZp8m.cjs} +109 -45
  43. package/dist/shared/attaform.Du9RZp8m.cjs.map +1 -0
  44. package/dist/shared/{attaform.CO0e7YVY.d.ts → attaform.JPsaqjLl.d.mts} +3 -0
  45. package/dist/shared/{attaform.8vmdOURQ.d.mts → attaform.MgaYKlPP.d.cts} +12 -1
  46. package/dist/shared/{attaform.OLtKd9gM.mjs → attaform.NqYEzRcM.mjs} +2 -2
  47. package/dist/shared/{attaform.OLtKd9gM.mjs.map → attaform.NqYEzRcM.mjs.map} +1 -1
  48. package/dist/shared/{attaform.DS_zBcdr.d.ts → attaform.ceYeVkjn.d.ts} +12 -1
  49. package/dist/shared/{attaform.Xe8dATED.cjs → attaform.tZ0YKisf.cjs} +4 -4
  50. package/dist/shared/{attaform.Xe8dATED.cjs.map → attaform.tZ0YKisf.cjs.map} +1 -1
  51. package/dist/zod-v3.cjs +2 -2
  52. package/dist/zod-v3.d.cts +3 -3
  53. package/dist/zod-v3.d.mts +3 -3
  54. package/dist/zod-v3.d.ts +3 -3
  55. package/dist/zod-v3.mjs +2 -2
  56. package/dist/zod-v4.cjs +2 -2
  57. package/dist/zod-v4.d.cts +6 -6
  58. package/dist/zod-v4.d.mts +6 -6
  59. package/dist/zod-v4.d.ts +6 -6
  60. package/dist/zod-v4.mjs +2 -2
  61. package/dist/zod.cjs +5 -5
  62. package/dist/zod.d.cts +5 -5
  63. package/dist/zod.d.mts +5 -5
  64. package/dist/zod.d.ts +5 -5
  65. package/dist/zod.mjs +5 -5
  66. package/package.json +1 -1
  67. package/dist/shared/attaform.3heDHayA.cjs.map +0 -1
  68. package/dist/shared/attaform.BkUzunyB.cjs.map +0 -1
  69. package/dist/shared/attaform.CqwcTExO.mjs.map +0 -1
  70. package/dist/shared/attaform.DK3xUBkj.mjs.map +0 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const paths = require('./attaform.3heDHayA.cjs');
3
+ const paths = require('./attaform.BPl-ECRT.cjs');
4
4
 
5
5
  function renderAttaformState(app) {
6
6
  const registry = paths.getRegistryFromApp(app);
@@ -36,4 +36,4 @@ const DEVTOOLS_WINDOW_KEY = "__attaform_devtools__";
36
36
  exports.DEVTOOLS_WINDOW_KEY = DEVTOOLS_WINDOW_KEY;
37
37
  exports.hydrateAttaformState = hydrateAttaformState;
38
38
  exports.renderAttaformState = renderAttaformState;
39
- //# sourceMappingURL=attaform.xBDo0Ko0.cjs.map
39
+ //# sourceMappingURL=attaform.D51IwDtP.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"attaform.xBDo0Ko0.cjs","sources":["../../src/runtime/core/serialize.ts","../../src/runtime/core/devtools-shared.ts"],"sourcesContent":["import type { App } from 'vue'\nimport type { FormKey } from '../types/types-api'\nimport { pathKeyToDotted, type PathKey } from './paths'\nimport { getRegistryFromApp, type SerializedFormData } from './registry'\n\n/**\n * Serialised snapshot of every form in a Vue app, produced by\n * `renderAttaformState` and consumed by `hydrateAttaformState`.\n *\n * JSON-safe — pass to `JSON.stringify`, `devalue`, or any other\n * serialiser before embedding in your SSR payload.\n */\nexport type SerializedAttaformState = {\n /** Tuples of `[formKey, snapshot]` for every form in the app. */\n readonly forms: ReadonlyArray<readonly [FormKey, SerializedFormData]>\n}\n\n/**\n * Snapshot every form on a Vue app for SSR. Call from your server\n * entry after rendering the app:\n *\n * ```ts\n * import { renderToString } from '@vue/server-renderer'\n * import { renderAttaformState, escapeForInlineScript } from 'attaform'\n *\n * const html = await renderToString(app)\n * const state = renderAttaformState(app)\n * const payload = escapeForInlineScript(JSON.stringify(state))\n *\n * return `\n * ${html}\n * <script>window.__ATTAFORM_STATE__ = ${payload}</script>\n * `\n * ```\n *\n * Pair with `hydrateAttaformState` on the client to restore the\n * forms in their server-rendered state. Nuxt users don't need this —\n * `attaform/nuxt` wires SSR automatically.\n */\nexport function renderAttaformState(app: App): SerializedAttaformState {\n const registry = getRegistryFromApp(app)\n const forms: Array<readonly [FormKey, SerializedFormData]> = []\n for (const [key, state] of registry.forms) {\n // Skip the blank field when the set is empty so the\n // wire payload stays minimal for forms that don't use it. The\n // optional shape on the consuming side handles the absence\n // cleanly (defaults to \"no blank paths\"). PathKey → dotted at\n // the boundary so the wire shape matches the rest of the\n // public path notation.\n const transientList: string[] = []\n for (const pk of state.blankPaths) {\n const d = pathKeyToDotted(pk as PathKey)\n if (d !== null) transientList.push(d)\n }\n forms.push([\n key,\n {\n form: state.form.value,\n schemaErrors: Array.from(state.schemaErrors.entries()),\n userErrors: Array.from(state.userErrors.entries()),\n fields: Array.from(state.fields.entries()),\n ...(transientList.length > 0 ? { blankPaths: transientList } : {}),\n },\n ])\n }\n return { forms }\n}\n\n/**\n * Restore forms from a server-rendered snapshot on the client. Call\n * from your client entry before mounting:\n *\n * ```ts\n * import { createApp } from 'vue'\n * import { createAttaform, hydrateAttaformState } from 'attaform'\n *\n * const app = createApp(App).use(createAttaform())\n * hydrateAttaformState(app, window.__ATTAFORM_STATE__)\n * app.mount('#app')\n * ```\n *\n * The next `useForm({ key })` call for each serialised form picks up\n * the snapshot transparently — no further action is required.\n */\nexport function hydrateAttaformState(app: App, payload: SerializedAttaformState): void {\n const registry = getRegistryFromApp(app)\n for (const [key, data] of payload.forms) {\n registry.pendingHydration.set(key, data)\n }\n}\n","/**\n * Shared building blocks for Attaform's two devtools surfaces — the Vue\n * DevTools (Chrome-extension) inspector wired up in `./devtools.ts`, and\n * the Nuxt DevTools (overlay) panel wired up via `../../nuxt.ts` +\n * `../pages/_attaform_devtools.vue`.\n *\n * Houses the window-bridge contract both surfaces consume so a new\n * bridge field lands in one file. Both surfaces render RAW form values\n * by design — DevTools is a dev-only surface, and redaction across every\n * place a value surfaces is impractical security theater rather than a\n * real safeguard.\n */\nimport type { AttaformRegistry } from './registry'\n\n/**\n * Property key on `window` that the Nuxt-side dev plugin attaches the\n * bridge object to. The iframe-mounted overlay panel reads\n * `window.parent[DEVTOOLS_WINDOW_KEY]` to reach the host app's registry.\n *\n * Underscored + namespaced to make accidental collision with consumer\n * globals vanishingly unlikely. Stable across versions — bumping it\n * would silently disconnect older library builds from newer overlay\n * panels in the same browser tab during a library upgrade.\n */\nexport const DEVTOOLS_WINDOW_KEY = '__attaform_devtools__'\n\n/**\n * Shape of the object the host plugin attaches to `window` in dev mode.\n * The iframe overlay panel reads this to discover the live registry and\n * render its forms.\n *\n * Single-registry assumption: the latest `createAttaform()` install\n * wins. Multi-app pages (rare; typically only seen in micro-frontend\n * setups) will only see one app's forms in the panel. Documented but\n * not actively supported — the alternative (a Set of registries with\n * union-rendering) is a future call if a real consumer hits it.\n */\nexport interface AttaformDevtoolsBridge {\n registry: AttaformRegistry\n /**\n * The library version, surfaced in the panel's footer for support /\n * bug-report context. Read from `package.json` at host-plugin init.\n */\n version: string\n}\n\ndeclare global {\n interface Window {\n [DEVTOOLS_WINDOW_KEY]?: AttaformDevtoolsBridge\n }\n}\n"],"names":["getRegistryFromApp","pathKeyToDotted"],"mappings":";;;;AAuCO,SAAS,oBAAoB,GAAA,EAAmC;AACrE,EAAA,MAAM,QAAA,GAAWA,yBAAmB,GAAG,CAAA;AACvC,EAAA,MAAM,QAAuD,EAAC;AAC9D,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,SAAS,KAAA,EAAO;AAOzC,IAAA,MAAM,gBAA0B,EAAC;AACjC,IAAA,KAAA,MAAW,EAAA,IAAM,MAAM,UAAA,EAAY;AACjC,MAAA,MAAM,CAAA,GAAIC,sBAAgB,EAAa,CAAA;AACvC,MAAA,IAAI,CAAA,KAAM,IAAA,EAAM,aAAA,CAAc,IAAA,CAAK,CAAC,CAAA;AAAA,IACtC;AACA,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,GAAA;AAAA,MACA;AAAA,QACE,IAAA,EAAM,MAAM,IAAA,CAAK,KAAA;AAAA,QACjB,cAAc,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,YAAA,CAAa,SAAS,CAAA;AAAA,QACrD,YAAY,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,UAAA,CAAW,SAAS,CAAA;AAAA,QACjD,QAAQ,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,SAAS,CAAA;AAAA,QACzC,GAAI,cAAc,MAAA,GAAS,CAAA,GAAI,EAAE,UAAA,EAAY,aAAA,KAAkB;AAAC;AAClE,KACD,CAAA;AAAA,EACH;AACA,EAAA,OAAO,EAAE,KAAA,EAAM;AACjB;AAkBO,SAAS,oBAAA,CAAqB,KAAU,OAAA,EAAwC;AACrF,EAAA,MAAM,QAAA,GAAWD,yBAAmB,GAAG,CAAA;AACvC,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,IAAI,CAAA,IAAK,QAAQ,KAAA,EAAO;AACvC,IAAA,QAAA,CAAS,gBAAA,CAAiB,GAAA,CAAI,GAAA,EAAK,IAAI,CAAA;AAAA,EACzC;AACF;;ACjEO,MAAM,mBAAA,GAAsB;;;;;;"}
1
+ {"version":3,"file":"attaform.D51IwDtP.cjs","sources":["../../src/runtime/core/serialize.ts","../../src/runtime/core/devtools-shared.ts"],"sourcesContent":["import type { App } from 'vue'\nimport type { FormKey } from '../types/types-api'\nimport { pathKeyToDotted, type PathKey } from './paths'\nimport { getRegistryFromApp, type SerializedFormData } from './registry'\n\n/**\n * Serialised snapshot of every form in a Vue app, produced by\n * `renderAttaformState` and consumed by `hydrateAttaformState`.\n *\n * JSON-safe — pass to `JSON.stringify`, `devalue`, or any other\n * serialiser before embedding in your SSR payload.\n */\nexport type SerializedAttaformState = {\n /** Tuples of `[formKey, snapshot]` for every form in the app. */\n readonly forms: ReadonlyArray<readonly [FormKey, SerializedFormData]>\n}\n\n/**\n * Snapshot every form on a Vue app for SSR. Call from your server\n * entry after rendering the app:\n *\n * ```ts\n * import { renderToString } from '@vue/server-renderer'\n * import { renderAttaformState, escapeForInlineScript } from 'attaform'\n *\n * const html = await renderToString(app)\n * const state = renderAttaformState(app)\n * const payload = escapeForInlineScript(JSON.stringify(state))\n *\n * return `\n * ${html}\n * <script>window.__ATTAFORM_STATE__ = ${payload}</script>\n * `\n * ```\n *\n * Pair with `hydrateAttaformState` on the client to restore the\n * forms in their server-rendered state. Nuxt users don't need this —\n * `attaform/nuxt` wires SSR automatically.\n */\nexport function renderAttaformState(app: App): SerializedAttaformState {\n const registry = getRegistryFromApp(app)\n const forms: Array<readonly [FormKey, SerializedFormData]> = []\n for (const [key, state] of registry.forms) {\n // Skip the blank field when the set is empty so the\n // wire payload stays minimal for forms that don't use it. The\n // optional shape on the consuming side handles the absence\n // cleanly (defaults to \"no blank paths\"). PathKey → dotted at\n // the boundary so the wire shape matches the rest of the\n // public path notation.\n const transientList: string[] = []\n for (const pk of state.blankPaths) {\n const d = pathKeyToDotted(pk as PathKey)\n if (d !== null) transientList.push(d)\n }\n forms.push([\n key,\n {\n form: state.form.value,\n schemaErrors: Array.from(state.schemaErrors.entries()),\n userErrors: Array.from(state.userErrors.entries()),\n fields: Array.from(state.fields.entries()),\n ...(transientList.length > 0 ? { blankPaths: transientList } : {}),\n },\n ])\n }\n return { forms }\n}\n\n/**\n * Restore forms from a server-rendered snapshot on the client. Call\n * from your client entry before mounting:\n *\n * ```ts\n * import { createApp } from 'vue'\n * import { createAttaform, hydrateAttaformState } from 'attaform'\n *\n * const app = createApp(App).use(createAttaform())\n * hydrateAttaformState(app, window.__ATTAFORM_STATE__)\n * app.mount('#app')\n * ```\n *\n * The next `useForm({ key })` call for each serialised form picks up\n * the snapshot transparently — no further action is required.\n */\nexport function hydrateAttaformState(app: App, payload: SerializedAttaformState): void {\n const registry = getRegistryFromApp(app)\n for (const [key, data] of payload.forms) {\n registry.pendingHydration.set(key, data)\n }\n}\n","/**\n * Shared building blocks for Attaform's two devtools surfaces — the Vue\n * DevTools (Chrome-extension) inspector wired up in `./devtools.ts`, and\n * the Nuxt DevTools (overlay) panel wired up via `../../nuxt.ts` +\n * `../pages/_attaform_devtools.vue`.\n *\n * Houses the window-bridge contract both surfaces consume so a new\n * bridge field lands in one file. Both surfaces render RAW form values\n * by design — DevTools is a dev-only surface, and redaction across every\n * place a value surfaces is impractical security theater rather than a\n * real safeguard.\n */\nimport type { AttaformRegistry } from './registry'\n\n/**\n * Property key on `window` that the Nuxt-side dev plugin attaches the\n * bridge object to. The iframe-mounted overlay panel reads\n * `window.parent[DEVTOOLS_WINDOW_KEY]` to reach the host app's registry.\n *\n * Underscored + namespaced to make accidental collision with consumer\n * globals vanishingly unlikely. Stable across versions — bumping it\n * would silently disconnect older library builds from newer overlay\n * panels in the same browser tab during a library upgrade.\n */\nexport const DEVTOOLS_WINDOW_KEY = '__attaform_devtools__'\n\n/**\n * Shape of the object the host plugin attaches to `window` in dev mode.\n * The iframe overlay panel reads this to discover the live registry and\n * render its forms.\n *\n * Single-registry assumption: the latest `createAttaform()` install\n * wins. Multi-app pages (rare; typically only seen in micro-frontend\n * setups) will only see one app's forms in the panel. Documented but\n * not actively supported — the alternative (a Set of registries with\n * union-rendering) is a future call if a real consumer hits it.\n */\nexport interface AttaformDevtoolsBridge {\n registry: AttaformRegistry\n /**\n * The library version, surfaced in the panel's footer for support /\n * bug-report context. Read from `package.json` at host-plugin init.\n */\n version: string\n}\n\ndeclare global {\n interface Window {\n [DEVTOOLS_WINDOW_KEY]?: AttaformDevtoolsBridge\n }\n}\n"],"names":["getRegistryFromApp","pathKeyToDotted"],"mappings":";;;;AAuCO,SAAS,oBAAoB,GAAA,EAAmC;AACrE,EAAA,MAAM,QAAA,GAAWA,yBAAmB,GAAG,CAAA;AACvC,EAAA,MAAM,QAAuD,EAAC;AAC9D,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,SAAS,KAAA,EAAO;AAOzC,IAAA,MAAM,gBAA0B,EAAC;AACjC,IAAA,KAAA,MAAW,EAAA,IAAM,MAAM,UAAA,EAAY;AACjC,MAAA,MAAM,CAAA,GAAIC,sBAAgB,EAAa,CAAA;AACvC,MAAA,IAAI,CAAA,KAAM,IAAA,EAAM,aAAA,CAAc,IAAA,CAAK,CAAC,CAAA;AAAA,IACtC;AACA,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,GAAA;AAAA,MACA;AAAA,QACE,IAAA,EAAM,MAAM,IAAA,CAAK,KAAA;AAAA,QACjB,cAAc,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,YAAA,CAAa,SAAS,CAAA;AAAA,QACrD,YAAY,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,UAAA,CAAW,SAAS,CAAA;AAAA,QACjD,QAAQ,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,SAAS,CAAA;AAAA,QACzC,GAAI,cAAc,MAAA,GAAS,CAAA,GAAI,EAAE,UAAA,EAAY,aAAA,KAAkB;AAAC;AAClE,KACD,CAAA;AAAA,EACH;AACA,EAAA,OAAO,EAAE,KAAA,EAAM;AACjB;AAkBO,SAAS,oBAAA,CAAqB,KAAU,OAAA,EAAwC;AACrF,EAAA,MAAM,QAAA,GAAWD,yBAAmB,GAAG,CAAA;AACvC,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,IAAI,CAAA,IAAK,QAAQ,KAAA,EAAO;AACvC,IAAA,QAAA,CAAS,gBAAA,CAAiB,GAAA,CAAI,GAAA,EAAK,IAAI,CAAA;AAAA,EACzC;AACF;;ACjEO,MAAM,mBAAA,GAAsB;;;;;;"}
@@ -137,8 +137,8 @@ declare function canonicalizePath(input: string | Path): {
137
137
  * `Path` to address the form value as a whole, and the home for
138
138
  * form-level (global) errors: root `.refine()` messages, hydration
139
139
  * failures, and `setErrors` entries with no path all live at `[]`. Aggregate
140
- * reads (`errors()`, `meta.errors`) surface them alongside field
141
- * errors; `errors([])` returns the global bucket alone.
140
+ * reads (`errors()`, `errors([])`, `meta.errors`) surface them alongside
141
+ * field errors; `meta.ownErrors` returns the root bucket alone.
142
142
  *
143
143
  * The empty SEGMENT tuple `[]` is structurally unconstructible as a
144
144
  * field path, so it can never collide with a schema key, unlike the
@@ -2074,14 +2074,15 @@ type OnError = (error: ValidationError[]) => void | Promise<void>;
2074
2074
  type DisplayState = 'idle' | 'pending' | 'error' | 'success';
2075
2075
  /**
2076
2076
  * Keys on `FieldState` layered on FROM the display-state predicate
2077
- * (plus `firstError`, computed alongside them). `Omit`'d from the
2078
- * predicate's arguments so a predicate cannot read its own output and
2079
- * form a cycle — enforced at the type level AND at runtime: the base
2080
- * objects passed in literally lack these keys, so an `as` cast in TS
2081
- * or a vanilla-JS caller still can't reach them. `FieldStateBase` /
2082
- * `FormMetaBase` (field-state-api.ts) omit the same set in lockstep.
2077
+ * (plus `firstError` / `firstOwnError`, computed alongside them).
2078
+ * `Omit`'d from the predicate's arguments so a predicate cannot read
2079
+ * its own output and form a cycle — enforced at the type level AND at
2080
+ * runtime: the base objects passed in literally lack these keys, so an
2081
+ * `as` cast in TS or a vanilla-JS caller still can't reach them.
2082
+ * `FieldStateBase` / `FormMetaBase` (field-state-api.ts) omit the same
2083
+ * set in lockstep.
2083
2084
  */
2084
- type FieldStateDerivedKey = 'displayState' | 'showErrors' | 'showPending' | 'showSuccess' | 'showIdle' | 'firstError';
2085
+ type FieldStateDerivedKey = 'displayState' | 'showErrors' | 'showPending' | 'showSuccess' | 'showIdle' | 'firstError' | 'firstOwnError';
2085
2086
  /**
2086
2087
  * One step of the display state machine: the verdict the field should
2087
2088
  * render right now (`display`, projected to `displayState` and the
@@ -3114,7 +3115,40 @@ type FieldState<Value = unknown> = {
3114
3115
  */
3115
3116
  readonly elements: readonly HTMLElement[];
3116
3117
  readonly updatedAt: string | null;
3118
+ /**
3119
+ * Every `ValidationError` in this path's SUBTREE: the node's own
3120
+ * bucket plus every descendant's, sorted by schema-declaration order.
3121
+ * On a leaf (no descendants) this equals `ownErrors`. On a container
3122
+ * it rolls up the whole fieldset, so a parent's `errors` is non-empty
3123
+ * whenever any child is invalid.
3124
+ *
3125
+ * For the errors pinned at THIS path alone (a container's own
3126
+ * cross-field `.refine()`, or `setErrors` at this path), read
3127
+ * `ownErrors`.
3128
+ */
3117
3129
  readonly errors: readonly ValidationError[];
3130
+ /**
3131
+ * Every `ValidationError` at THIS exact path's own bucket, excluding
3132
+ * descendants: schema errors, blank-required errors, and `setErrors`
3133
+ * pinned here, in `schema`, `blank`, `user` order. The exact-path
3134
+ * counterpart to the subtree-scoped `errors`.
3135
+ *
3136
+ * On a leaf this is the same array as `errors` (a leaf has no
3137
+ * descendants). On a container it holds only the container's OWN
3138
+ * errors, a cross-field `.refine()` on the fieldset or a path-less
3139
+ * `setErrors` at this node, without dragging in any child error:
3140
+ *
3141
+ * ```vue
3142
+ * <p v-if="form.fields.address.firstOwnError">
3143
+ * {{ form.fields.address.firstOwnError.message }}
3144
+ * </p>
3145
+ * ```
3146
+ *
3147
+ * On `form.meta` this is the root `[]` bucket: form-level errors from
3148
+ * a root `.refine()` or a path-less `setErrors`. `form.meta.ownErrors`
3149
+ * (with `firstOwnError`) is the banner accessor for those.
3150
+ */
3151
+ readonly ownErrors: readonly ValidationError[];
3118
3152
  /**
3119
3153
  * `true` while a per-field validation run is in flight at this path.
3120
3154
  * Reflects field-level debounced runs (`validate-on-change`) and
@@ -3235,9 +3269,28 @@ type FieldState<Value = unknown> = {
3235
3269
  * decides when to render it.
3236
3270
  *
3237
3271
  * On container paths, the first error in the aggregated subtree
3238
- * (descendants sorted by `pathOrdinal`).
3272
+ * (descendants sorted by `pathOrdinal`). For the container's OWN
3273
+ * first error only, read `firstOwnError`.
3239
3274
  */
3240
3275
  readonly firstError: ValidationError | undefined;
3276
+ /**
3277
+ * The first `ValidationError` in `ownErrors` (this exact path's own
3278
+ * bucket), or `undefined` when that bucket is empty. Equivalent to
3279
+ * `ownErrors[0]`, the exact-path counterpart to `firstError`.
3280
+ *
3281
+ * On a leaf this equals `firstError`. On a container it is the
3282
+ * container's own cross-field error (a fieldset `.refine()`), never a
3283
+ * child's. `form.meta.firstOwnError` is the form-level banner: the
3284
+ * first root `[]` error from a root `.refine()` or a path-less
3285
+ * `setErrors`:
3286
+ *
3287
+ * ```vue
3288
+ * <p v-if="form.meta.firstOwnError" role="alert">
3289
+ * {{ form.meta.firstOwnError.message }}
3290
+ * </p>
3291
+ * ```
3292
+ */
3293
+ readonly firstOwnError: ValidationError | undefined;
3241
3294
  readonly path: ReadonlyArray<string | number>;
3242
3295
  /**
3243
3296
  * Stable, SSR-safe DOM id for this field, unique across every mount
@@ -3601,11 +3654,13 @@ type FormErrorsSurface<Form> = ErrorsProxyShape<Form> & {
3601
3654
  <const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form>] ? unknown : never)): readonly ValidationError[];
3602
3655
  (segments: ReadonlyArray<string | number>): readonly ValidationError[];
3603
3656
  /**
3604
- * No-arg call returns the whole-form error aggregate same as
3605
- * `form.meta.errors`: every field error plus the global bucket.
3606
- * Distinct from `form.errors([])`, which returns ONLY the global
3607
- * (root) bucket. Always a readonly array; empty when the form has no
3608
- * errors.
3657
+ * No-arg call returns the whole-form error aggregate, the same as
3658
+ * `form.meta.errors` and `form.errors([])`: every field error plus
3659
+ * the root bucket. `form.errors(path)` is uniform at every depth,
3660
+ * including `[]`, so the root is no exception. For the root bucket
3661
+ * alone (a root `.refine()`, a path-less `setErrors`), read
3662
+ * `form.meta.ownErrors`. Always a readonly array; empty when the form
3663
+ * has no errors.
3609
3664
  */
3610
3665
  (): readonly ValidationError[];
3611
3666
  };
@@ -137,8 +137,8 @@ declare function canonicalizePath(input: string | Path): {
137
137
  * `Path` to address the form value as a whole, and the home for
138
138
  * form-level (global) errors: root `.refine()` messages, hydration
139
139
  * failures, and `setErrors` entries with no path all live at `[]`. Aggregate
140
- * reads (`errors()`, `meta.errors`) surface them alongside field
141
- * errors; `errors([])` returns the global bucket alone.
140
+ * reads (`errors()`, `errors([])`, `meta.errors`) surface them alongside
141
+ * field errors; `meta.ownErrors` returns the root bucket alone.
142
142
  *
143
143
  * The empty SEGMENT tuple `[]` is structurally unconstructible as a
144
144
  * field path, so it can never collide with a schema key, unlike the
@@ -2074,14 +2074,15 @@ type OnError = (error: ValidationError[]) => void | Promise<void>;
2074
2074
  type DisplayState = 'idle' | 'pending' | 'error' | 'success';
2075
2075
  /**
2076
2076
  * Keys on `FieldState` layered on FROM the display-state predicate
2077
- * (plus `firstError`, computed alongside them). `Omit`'d from the
2078
- * predicate's arguments so a predicate cannot read its own output and
2079
- * form a cycle — enforced at the type level AND at runtime: the base
2080
- * objects passed in literally lack these keys, so an `as` cast in TS
2081
- * or a vanilla-JS caller still can't reach them. `FieldStateBase` /
2082
- * `FormMetaBase` (field-state-api.ts) omit the same set in lockstep.
2077
+ * (plus `firstError` / `firstOwnError`, computed alongside them).
2078
+ * `Omit`'d from the predicate's arguments so a predicate cannot read
2079
+ * its own output and form a cycle — enforced at the type level AND at
2080
+ * runtime: the base objects passed in literally lack these keys, so an
2081
+ * `as` cast in TS or a vanilla-JS caller still can't reach them.
2082
+ * `FieldStateBase` / `FormMetaBase` (field-state-api.ts) omit the same
2083
+ * set in lockstep.
2083
2084
  */
2084
- type FieldStateDerivedKey = 'displayState' | 'showErrors' | 'showPending' | 'showSuccess' | 'showIdle' | 'firstError';
2085
+ type FieldStateDerivedKey = 'displayState' | 'showErrors' | 'showPending' | 'showSuccess' | 'showIdle' | 'firstError' | 'firstOwnError';
2085
2086
  /**
2086
2087
  * One step of the display state machine: the verdict the field should
2087
2088
  * render right now (`display`, projected to `displayState` and the
@@ -3114,7 +3115,40 @@ type FieldState<Value = unknown> = {
3114
3115
  */
3115
3116
  readonly elements: readonly HTMLElement[];
3116
3117
  readonly updatedAt: string | null;
3118
+ /**
3119
+ * Every `ValidationError` in this path's SUBTREE: the node's own
3120
+ * bucket plus every descendant's, sorted by schema-declaration order.
3121
+ * On a leaf (no descendants) this equals `ownErrors`. On a container
3122
+ * it rolls up the whole fieldset, so a parent's `errors` is non-empty
3123
+ * whenever any child is invalid.
3124
+ *
3125
+ * For the errors pinned at THIS path alone (a container's own
3126
+ * cross-field `.refine()`, or `setErrors` at this path), read
3127
+ * `ownErrors`.
3128
+ */
3117
3129
  readonly errors: readonly ValidationError[];
3130
+ /**
3131
+ * Every `ValidationError` at THIS exact path's own bucket, excluding
3132
+ * descendants: schema errors, blank-required errors, and `setErrors`
3133
+ * pinned here, in `schema`, `blank`, `user` order. The exact-path
3134
+ * counterpart to the subtree-scoped `errors`.
3135
+ *
3136
+ * On a leaf this is the same array as `errors` (a leaf has no
3137
+ * descendants). On a container it holds only the container's OWN
3138
+ * errors, a cross-field `.refine()` on the fieldset or a path-less
3139
+ * `setErrors` at this node, without dragging in any child error:
3140
+ *
3141
+ * ```vue
3142
+ * <p v-if="form.fields.address.firstOwnError">
3143
+ * {{ form.fields.address.firstOwnError.message }}
3144
+ * </p>
3145
+ * ```
3146
+ *
3147
+ * On `form.meta` this is the root `[]` bucket: form-level errors from
3148
+ * a root `.refine()` or a path-less `setErrors`. `form.meta.ownErrors`
3149
+ * (with `firstOwnError`) is the banner accessor for those.
3150
+ */
3151
+ readonly ownErrors: readonly ValidationError[];
3118
3152
  /**
3119
3153
  * `true` while a per-field validation run is in flight at this path.
3120
3154
  * Reflects field-level debounced runs (`validate-on-change`) and
@@ -3235,9 +3269,28 @@ type FieldState<Value = unknown> = {
3235
3269
  * decides when to render it.
3236
3270
  *
3237
3271
  * On container paths, the first error in the aggregated subtree
3238
- * (descendants sorted by `pathOrdinal`).
3272
+ * (descendants sorted by `pathOrdinal`). For the container's OWN
3273
+ * first error only, read `firstOwnError`.
3239
3274
  */
3240
3275
  readonly firstError: ValidationError | undefined;
3276
+ /**
3277
+ * The first `ValidationError` in `ownErrors` (this exact path's own
3278
+ * bucket), or `undefined` when that bucket is empty. Equivalent to
3279
+ * `ownErrors[0]`, the exact-path counterpart to `firstError`.
3280
+ *
3281
+ * On a leaf this equals `firstError`. On a container it is the
3282
+ * container's own cross-field error (a fieldset `.refine()`), never a
3283
+ * child's. `form.meta.firstOwnError` is the form-level banner: the
3284
+ * first root `[]` error from a root `.refine()` or a path-less
3285
+ * `setErrors`:
3286
+ *
3287
+ * ```vue
3288
+ * <p v-if="form.meta.firstOwnError" role="alert">
3289
+ * {{ form.meta.firstOwnError.message }}
3290
+ * </p>
3291
+ * ```
3292
+ */
3293
+ readonly firstOwnError: ValidationError | undefined;
3241
3294
  readonly path: ReadonlyArray<string | number>;
3242
3295
  /**
3243
3296
  * Stable, SSR-safe DOM id for this field, unique across every mount
@@ -3601,11 +3654,13 @@ type FormErrorsSurface<Form> = ErrorsProxyShape<Form> & {
3601
3654
  <const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form>] ? unknown : never)): readonly ValidationError[];
3602
3655
  (segments: ReadonlyArray<string | number>): readonly ValidationError[];
3603
3656
  /**
3604
- * No-arg call returns the whole-form error aggregate same as
3605
- * `form.meta.errors`: every field error plus the global bucket.
3606
- * Distinct from `form.errors([])`, which returns ONLY the global
3607
- * (root) bucket. Always a readonly array; empty when the form has no
3608
- * errors.
3657
+ * No-arg call returns the whole-form error aggregate, the same as
3658
+ * `form.meta.errors` and `form.errors([])`: every field error plus
3659
+ * the root bucket. `form.errors(path)` is uniform at every depth,
3660
+ * including `[]`, so the root is no exception. For the root bucket
3661
+ * alone (a root `.refine()`, a path-less `setErrors`), read
3662
+ * `form.meta.ownErrors`. Always a readonly array; empty when the form
3663
+ * has no errors.
3609
3664
  */
3610
3665
  (): readonly ValidationError[];
3611
3666
  };
@@ -137,8 +137,8 @@ declare function canonicalizePath(input: string | Path): {
137
137
  * `Path` to address the form value as a whole, and the home for
138
138
  * form-level (global) errors: root `.refine()` messages, hydration
139
139
  * failures, and `setErrors` entries with no path all live at `[]`. Aggregate
140
- * reads (`errors()`, `meta.errors`) surface them alongside field
141
- * errors; `errors([])` returns the global bucket alone.
140
+ * reads (`errors()`, `errors([])`, `meta.errors`) surface them alongside
141
+ * field errors; `meta.ownErrors` returns the root bucket alone.
142
142
  *
143
143
  * The empty SEGMENT tuple `[]` is structurally unconstructible as a
144
144
  * field path, so it can never collide with a schema key, unlike the
@@ -2074,14 +2074,15 @@ type OnError = (error: ValidationError[]) => void | Promise<void>;
2074
2074
  type DisplayState = 'idle' | 'pending' | 'error' | 'success';
2075
2075
  /**
2076
2076
  * Keys on `FieldState` layered on FROM the display-state predicate
2077
- * (plus `firstError`, computed alongside them). `Omit`'d from the
2078
- * predicate's arguments so a predicate cannot read its own output and
2079
- * form a cycle — enforced at the type level AND at runtime: the base
2080
- * objects passed in literally lack these keys, so an `as` cast in TS
2081
- * or a vanilla-JS caller still can't reach them. `FieldStateBase` /
2082
- * `FormMetaBase` (field-state-api.ts) omit the same set in lockstep.
2077
+ * (plus `firstError` / `firstOwnError`, computed alongside them).
2078
+ * `Omit`'d from the predicate's arguments so a predicate cannot read
2079
+ * its own output and form a cycle — enforced at the type level AND at
2080
+ * runtime: the base objects passed in literally lack these keys, so an
2081
+ * `as` cast in TS or a vanilla-JS caller still can't reach them.
2082
+ * `FieldStateBase` / `FormMetaBase` (field-state-api.ts) omit the same
2083
+ * set in lockstep.
2083
2084
  */
2084
- type FieldStateDerivedKey = 'displayState' | 'showErrors' | 'showPending' | 'showSuccess' | 'showIdle' | 'firstError';
2085
+ type FieldStateDerivedKey = 'displayState' | 'showErrors' | 'showPending' | 'showSuccess' | 'showIdle' | 'firstError' | 'firstOwnError';
2085
2086
  /**
2086
2087
  * One step of the display state machine: the verdict the field should
2087
2088
  * render right now (`display`, projected to `displayState` and the
@@ -3114,7 +3115,40 @@ type FieldState<Value = unknown> = {
3114
3115
  */
3115
3116
  readonly elements: readonly HTMLElement[];
3116
3117
  readonly updatedAt: string | null;
3118
+ /**
3119
+ * Every `ValidationError` in this path's SUBTREE: the node's own
3120
+ * bucket plus every descendant's, sorted by schema-declaration order.
3121
+ * On a leaf (no descendants) this equals `ownErrors`. On a container
3122
+ * it rolls up the whole fieldset, so a parent's `errors` is non-empty
3123
+ * whenever any child is invalid.
3124
+ *
3125
+ * For the errors pinned at THIS path alone (a container's own
3126
+ * cross-field `.refine()`, or `setErrors` at this path), read
3127
+ * `ownErrors`.
3128
+ */
3117
3129
  readonly errors: readonly ValidationError[];
3130
+ /**
3131
+ * Every `ValidationError` at THIS exact path's own bucket, excluding
3132
+ * descendants: schema errors, blank-required errors, and `setErrors`
3133
+ * pinned here, in `schema`, `blank`, `user` order. The exact-path
3134
+ * counterpart to the subtree-scoped `errors`.
3135
+ *
3136
+ * On a leaf this is the same array as `errors` (a leaf has no
3137
+ * descendants). On a container it holds only the container's OWN
3138
+ * errors, a cross-field `.refine()` on the fieldset or a path-less
3139
+ * `setErrors` at this node, without dragging in any child error:
3140
+ *
3141
+ * ```vue
3142
+ * <p v-if="form.fields.address.firstOwnError">
3143
+ * {{ form.fields.address.firstOwnError.message }}
3144
+ * </p>
3145
+ * ```
3146
+ *
3147
+ * On `form.meta` this is the root `[]` bucket: form-level errors from
3148
+ * a root `.refine()` or a path-less `setErrors`. `form.meta.ownErrors`
3149
+ * (with `firstOwnError`) is the banner accessor for those.
3150
+ */
3151
+ readonly ownErrors: readonly ValidationError[];
3118
3152
  /**
3119
3153
  * `true` while a per-field validation run is in flight at this path.
3120
3154
  * Reflects field-level debounced runs (`validate-on-change`) and
@@ -3235,9 +3269,28 @@ type FieldState<Value = unknown> = {
3235
3269
  * decides when to render it.
3236
3270
  *
3237
3271
  * On container paths, the first error in the aggregated subtree
3238
- * (descendants sorted by `pathOrdinal`).
3272
+ * (descendants sorted by `pathOrdinal`). For the container's OWN
3273
+ * first error only, read `firstOwnError`.
3239
3274
  */
3240
3275
  readonly firstError: ValidationError | undefined;
3276
+ /**
3277
+ * The first `ValidationError` in `ownErrors` (this exact path's own
3278
+ * bucket), or `undefined` when that bucket is empty. Equivalent to
3279
+ * `ownErrors[0]`, the exact-path counterpart to `firstError`.
3280
+ *
3281
+ * On a leaf this equals `firstError`. On a container it is the
3282
+ * container's own cross-field error (a fieldset `.refine()`), never a
3283
+ * child's. `form.meta.firstOwnError` is the form-level banner: the
3284
+ * first root `[]` error from a root `.refine()` or a path-less
3285
+ * `setErrors`:
3286
+ *
3287
+ * ```vue
3288
+ * <p v-if="form.meta.firstOwnError" role="alert">
3289
+ * {{ form.meta.firstOwnError.message }}
3290
+ * </p>
3291
+ * ```
3292
+ */
3293
+ readonly firstOwnError: ValidationError | undefined;
3241
3294
  readonly path: ReadonlyArray<string | number>;
3242
3295
  /**
3243
3296
  * Stable, SSR-safe DOM id for this field, unique across every mount
@@ -3601,11 +3654,13 @@ type FormErrorsSurface<Form> = ErrorsProxyShape<Form> & {
3601
3654
  <const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form>] ? unknown : never)): readonly ValidationError[];
3602
3655
  (segments: ReadonlyArray<string | number>): readonly ValidationError[];
3603
3656
  /**
3604
- * No-arg call returns the whole-form error aggregate same as
3605
- * `form.meta.errors`: every field error plus the global bucket.
3606
- * Distinct from `form.errors([])`, which returns ONLY the global
3607
- * (root) bucket. Always a readonly array; empty when the form has no
3608
- * errors.
3657
+ * No-arg call returns the whole-form error aggregate, the same as
3658
+ * `form.meta.errors` and `form.errors([])`: every field error plus
3659
+ * the root bucket. `form.errors(path)` is uniform at every depth,
3660
+ * including `[]`, so the root is no exception. For the root bucket
3661
+ * alone (a root `.refine()`, a path-less `setErrors`), read
3662
+ * `form.meta.ownErrors`. Always a readonly array; empty when the form
3663
+ * has no errors.
3609
3664
  */
3610
3665
  (): readonly ValidationError[];
3611
3666
  };
@@ -25,6 +25,28 @@ function toError(value) {
25
25
  const message = typeof value === "string" && value.length > 0 ? value : `Submit callback threw a non-Error value (${typeof value})`;
26
26
  return new Error(message, { cause: value });
27
27
  }
28
+ function normalizeErrorInput(item, scope, formKey, defaultCode) {
29
+ if (item instanceof Error) {
30
+ return {
31
+ message: item.message.length > 0 ? item.message : "Unknown error",
32
+ path: scope !== void 0 ? [...scope] : [],
33
+ formKey,
34
+ code: defaultCode
35
+ };
36
+ }
37
+ const entry = {
38
+ message: typeof item.message === "string" && item.message.length > 0 ? item.message : "Unknown error",
39
+ path: scope !== void 0 ? [...scope] : Array.isArray(item.path) ? [...item.path] : [],
40
+ formKey,
41
+ code: typeof item.code === "string" && item.code.length > 0 ? item.code : defaultCode
42
+ };
43
+ if (item.data !== void 0) entry.data = item.data;
44
+ return entry;
45
+ }
46
+ function normalizeErrorInputs(input, scope, formKey, defaultCode) {
47
+ const items = Array.isArray(input) ? input : [input];
48
+ return items.map((item) => normalizeErrorInput(item, scope, formKey, defaultCode));
49
+ }
28
50
  class RegistryNotInstalledError extends AttaformError {
29
51
  constructor() {
30
52
  super(
@@ -1592,5 +1614,5 @@ function pathsEqual(a, b) {
1592
1614
  return true;
1593
1615
  }
1594
1616
 
1595
- export { AttaformError as A, InvalidPathError as I, OutsideSetupError as O, ROOT_PATH as R, SubmitErrorHandlerError as S, __DEV__ as _, InvalidUseFormConfigError as a, ROOT_PATH_KEY as b, RegistryNotInstalledError as c, ReservedFormKeyError as d, assignKey as e, canonicalizePath as f, createAttaform as g, createRegistry as h, getRegistryFromApp as i, isPathPrefix as j, kAttaformRegistry as k, kAttaformWizardActiveStepResolver as l, pathKeyToDotted as m, pathsEqual as n, keyForSegments as o, parseDottedPath as p, INTERACTIVE_TAG_NAMES as q, coerceToPathKey as r, segmentsForPathKey as s, toError as t, useRegistry as u, vRegister as v, ensureAttaformInstalled as w, kFormContext as x, kFormInstanceId as y, kAttaformAncestorWizard as z };
1596
- //# sourceMappingURL=attaform.CqwcTExO.mjs.map
1617
+ export { AttaformError as A, kFormInstanceId as B, kAttaformAncestorWizard as C, InvalidPathError as I, OutsideSetupError as O, ROOT_PATH as R, SubmitErrorHandlerError as S, __DEV__ as _, InvalidUseFormConfigError as a, ROOT_PATH_KEY as b, RegistryNotInstalledError as c, ReservedFormKeyError as d, assignKey as e, canonicalizePath as f, createAttaform as g, createRegistry as h, getRegistryFromApp as i, isPathPrefix as j, kAttaformRegistry as k, kAttaformWizardActiveStepResolver as l, pathKeyToDotted as m, pathsEqual as n, keyForSegments as o, parseDottedPath as p, normalizeErrorInput as q, INTERACTIVE_TAG_NAMES as r, segmentsForPathKey as s, toError as t, useRegistry as u, vRegister as v, normalizeErrorInputs as w, coerceToPathKey as x, ensureAttaformInstalled as y, kFormContext as z };
1618
+ //# sourceMappingURL=attaform.DGhIix5D.mjs.map