attaform 0.17.2 → 0.18.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 (115) hide show
  1. package/README.md +77 -36
  2. package/dist/chunks/devtools.cjs +10 -37
  3. package/dist/chunks/devtools.cjs.map +1 -1
  4. package/dist/chunks/devtools.mjs +10 -37
  5. package/dist/chunks/devtools.mjs.map +1 -1
  6. package/dist/chunks/indexeddb.cjs +4 -4
  7. package/dist/chunks/indexeddb.cjs.map +1 -1
  8. package/dist/chunks/indexeddb.mjs +1 -1
  9. package/dist/chunks/local-storage.cjs +2 -2
  10. package/dist/chunks/local-storage.cjs.map +1 -1
  11. package/dist/chunks/local-storage.mjs +1 -1
  12. package/dist/chunks/session-storage.cjs +2 -2
  13. package/dist/chunks/session-storage.cjs.map +1 -1
  14. package/dist/chunks/session-storage.mjs +1 -1
  15. package/dist/index.cjs +42 -37
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +159 -196
  18. package/dist/index.d.mts +159 -196
  19. package/dist/index.d.ts +159 -196
  20. package/dist/index.mjs +5 -7
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/nuxt.cjs +31 -40
  23. package/dist/nuxt.cjs.map +1 -1
  24. package/dist/nuxt.d.cts +8 -1
  25. package/dist/nuxt.d.mts +8 -1
  26. package/dist/nuxt.d.ts +8 -1
  27. package/dist/nuxt.mjs +32 -41
  28. package/dist/nuxt.mjs.map +1 -1
  29. package/dist/runtime/components/AttaformDevtoolsPanel.d.vue.ts +7 -0
  30. package/dist/runtime/components/AttaformDevtoolsPanel.vue +453 -0
  31. package/dist/runtime/components/AttaformDevtoolsPanel.vue.d.ts +7 -0
  32. package/dist/runtime/components/DevtoolsValueTree.d.vue.ts +37 -0
  33. package/dist/runtime/components/DevtoolsValueTree.vue +192 -0
  34. package/dist/runtime/components/DevtoolsValueTree.vue.d.ts +37 -0
  35. package/dist/runtime/plugins/attaform.cjs +17 -6
  36. package/dist/runtime/plugins/attaform.cjs.map +1 -1
  37. package/dist/runtime/plugins/attaform.mjs +15 -4
  38. package/dist/runtime/plugins/attaform.mjs.map +1 -1
  39. package/dist/shared/attaform.5UhpSVFI.cjs +63 -0
  40. package/dist/shared/attaform.5UhpSVFI.cjs.map +1 -0
  41. package/dist/shared/attaform.BDdFdjeX.mjs +57 -0
  42. package/dist/shared/attaform.BDdFdjeX.mjs.map +1 -0
  43. package/dist/shared/attaform.Bgu9l6OG.d.cts +1651 -0
  44. package/dist/shared/attaform.BmDBu4ql.d.ts +1651 -0
  45. package/dist/shared/{attaform.Dee2rU1P.cjs → attaform.BqK_L4gK.cjs} +310 -24
  46. package/dist/shared/attaform.BqK_L4gK.cjs.map +1 -0
  47. package/dist/shared/{attaform.C_5aB6EQ.d.ts → attaform.BsMdl-35.d.cts} +754 -146
  48. package/dist/shared/{attaform.C_5aB6EQ.d.mts → attaform.BsMdl-35.d.mts} +754 -146
  49. package/dist/shared/{attaform.C_5aB6EQ.d.cts → attaform.BsMdl-35.d.ts} +754 -146
  50. package/dist/shared/attaform.Bubm_slq.cjs.map +1 -1
  51. package/dist/shared/{attaform.C6lbmMUe.d.ts → attaform.C3x1hKJC.d.mts} +4 -4
  52. package/dist/shared/{attaform.CuE-bS1C.d.mts → attaform.CWs1Z3p7.d.ts} +57 -23
  53. package/dist/shared/attaform.CXpzmj38.mjs.map +1 -1
  54. package/dist/shared/{attaform.C5MH4lNh.d.mts → attaform.CjmJpfLH.d.ts} +4 -4
  55. package/dist/shared/{attaform.Drt6fivF.mjs → attaform.CtNUB9nf.mjs} +74 -76
  56. package/dist/shared/attaform.CtNUB9nf.mjs.map +1 -0
  57. package/dist/shared/{attaform.C0iFnTN0.d.ts → attaform.D-hDvb98.d.cts} +57 -23
  58. package/dist/shared/attaform.DAH3kvav.d.mts +1651 -0
  59. package/dist/shared/{attaform.BPRHR3Zs.cjs → attaform.DUHru0OF.cjs} +83 -85
  60. package/dist/shared/attaform.DUHru0OF.cjs.map +1 -0
  61. package/dist/shared/{attaform.BV40t5y2.cjs → attaform.Dlk1jMuv.cjs} +245 -108
  62. package/dist/shared/attaform.Dlk1jMuv.cjs.map +1 -0
  63. package/dist/shared/{attaform.B3ZaPIzS.mjs → attaform.DsC3rZHG.mjs} +1804 -219
  64. package/dist/shared/attaform.DsC3rZHG.mjs.map +1 -0
  65. package/dist/shared/{attaform.DtMN-MAm.d.cts → attaform.Dzi89x8N.d.cts} +4 -4
  66. package/dist/shared/{attaform.Cer8JO_P.cjs → attaform.II89Pcf4.cjs} +1860 -272
  67. package/dist/shared/attaform.II89Pcf4.cjs.map +1 -0
  68. package/dist/shared/{attaform.CIEQgJnM.mjs → attaform.Xhg0AYNa.mjs} +300 -26
  69. package/dist/shared/attaform.Xhg0AYNa.mjs.map +1 -0
  70. package/dist/shared/{attaform.CpERWz3u.mjs → attaform.Xt0A3QUd.mjs} +232 -95
  71. package/dist/shared/attaform.Xt0A3QUd.mjs.map +1 -0
  72. package/dist/shared/{attaform.CHorcsIU.d.cts → attaform.bH7WvNad.d.mts} +57 -23
  73. package/dist/vite.cjs +270 -2
  74. package/dist/vite.cjs.map +1 -1
  75. package/dist/vite.mjs +266 -2
  76. package/dist/vite.mjs.map +1 -1
  77. package/dist/zod-v3.cjs +11 -8
  78. package/dist/zod-v3.cjs.map +1 -1
  79. package/dist/zod-v3.d.cts +6 -6
  80. package/dist/zod-v3.d.mts +6 -6
  81. package/dist/zod-v3.d.ts +6 -6
  82. package/dist/zod-v3.mjs +3 -3
  83. package/dist/zod-v4.cjs +11 -8
  84. package/dist/zod-v4.cjs.map +1 -1
  85. package/dist/zod-v4.d.cts +5 -5
  86. package/dist/zod-v4.d.mts +5 -5
  87. package/dist/zod-v4.d.ts +5 -5
  88. package/dist/zod-v4.mjs +3 -3
  89. package/dist/zod.cjs +15 -16
  90. package/dist/zod.cjs.map +1 -1
  91. package/dist/zod.d.cts +127 -40
  92. package/dist/zod.d.mts +127 -40
  93. package/dist/zod.d.ts +127 -40
  94. package/dist/zod.mjs +7 -11
  95. package/dist/zod.mjs.map +1 -1
  96. package/package.json +19 -5
  97. package/dist/shared/attaform.B1jvxsOF.d.mts +0 -156
  98. package/dist/shared/attaform.B3ZaPIzS.mjs.map +0 -1
  99. package/dist/shared/attaform.BBM2muQ9.cjs +0 -101
  100. package/dist/shared/attaform.BBM2muQ9.cjs.map +0 -1
  101. package/dist/shared/attaform.BPRHR3Zs.cjs.map +0 -1
  102. package/dist/shared/attaform.BV40t5y2.cjs.map +0 -1
  103. package/dist/shared/attaform.C6qzEdIM.d.cts +0 -156
  104. package/dist/shared/attaform.C8LVFVVe.cjs +0 -32
  105. package/dist/shared/attaform.C8LVFVVe.cjs.map +0 -1
  106. package/dist/shared/attaform.CIEQgJnM.mjs.map +0 -1
  107. package/dist/shared/attaform.CTwNcpLE.d.ts +0 -156
  108. package/dist/shared/attaform.Cer8JO_P.cjs.map +0 -1
  109. package/dist/shared/attaform.CpERWz3u.mjs.map +0 -1
  110. package/dist/shared/attaform.Dee2rU1P.cjs.map +0 -1
  111. package/dist/shared/attaform.Drt6fivF.mjs.map +0 -1
  112. package/dist/shared/attaform.Vo-Kft0t.mjs +0 -29
  113. package/dist/shared/attaform.Vo-Kft0t.mjs.map +0 -1
  114. package/dist/shared/attaform.h1sq3BFu.mjs +0 -92
  115. package/dist/shared/attaform.h1sq3BFu.mjs.map +0 -1
package/dist/zod.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { z } from 'zod';
2
- import { S as StorageShape } from './shared/attaform.C0iFnTN0.js';
3
- export { P as PathInput, a as PathOutput } from './shared/attaform.C0iFnTN0.js';
4
- import { U as UnwrapZodObject, S as StorageShape$1 } from './shared/attaform.C6lbmMUe.js';
5
- import { U as UseFormConfiguration, G as GenericForm, b as AbstractSchema, D as DeepPartial, c as DefaultValuesShape, ag as ValidateOnConfig, d as UseFormReturnType, o as FieldMetaPayload } from './shared/attaform.C_5aB6EQ.js';
6
- export { ae as Unset, ao as isUnset, aq as unset } from './shared/attaform.C_5aB6EQ.js';
7
- export { A as AttaformErrorCode, i as injectForm, u as useRegister } from './shared/attaform.CTwNcpLE.js';
2
+ import { S as StorageShape } from './shared/attaform.CWs1Z3p7.js';
3
+ export { P as PathInput, a as PathOutput } from './shared/attaform.CWs1Z3p7.js';
4
+ import { U as UnwrapZodObject, S as StorageShape$1 } from './shared/attaform.CjmJpfLH.js';
5
+ import { F as FormKey, U as UseFormConfiguration, G as GenericForm, a as AbstractSchema, D as DefaultValuesInput, ak as ValidateOnConfig, b as UseFormReturnType, p as FieldMetaPayload } from './shared/attaform.BsMdl-35.js';
6
+ export { ai as Unset, as as isUnset, au as unset } from './shared/attaform.BsMdl-35.js';
7
+ export { b as AggregateError, c as AnyForm, d as AttaformErrorCode, C as CompiledStep, F as FormStatus, I as InjectWizardInput, L as LazyMarker, e as StepSlot, U as UseRegisterReturn, f as UseWizardReturnType, W as WizardCtx, g as WizardCtxForm, h as WizardOnError, i as WizardOnSubmit, j as WizardOptions, k as WizardPersistFn, l as WizardRestoreFn, m as WizardRestoreState, n as WizardStatusesProxy, o as WizardSubmitContext, t as injectForm, u as injectWizard, w as lazy, x as useRegister, z as useWizard } from './shared/attaform.BmDBu4ql.js';
8
8
  import 'vue';
9
9
 
10
10
  /**
@@ -14,21 +14,18 @@ import 'vue';
14
14
  * to the v3 wrapper, which already accepts both Zod v3 input and
15
15
  * `AbstractSchema` directly via its built-in shape branch.
16
16
  *
17
- * Type-level dispatch happens through a single signature with a
18
- * union constraint `Schema extends z.ZodObject |
19
- * zV3.ZodObject<zV3.ZodRawShape>`. The configuration parameter and
20
- * return type both dispatch conditionally on whether `Schema` is a
21
- * v4 or v3 object. The two majors don't structurally satisfy each
22
- * other's `ZodObject` constraints (v4 has `loose` / `safeExtend` /
23
- * `def` / `type` members v3 lacks), so neither alone is enough — the
24
- * union accepts both, and the conditional return type routes through
25
- * the matching adapter's `StorageShape` / `z.input` / `z.output`.
26
- *
27
- * A single signature (rather than overloads) keeps `typeof
28
- * useForm<X>` instantiation expressions in test code unambiguous:
29
- * TypeScript's overload-resolution rules for these expressions are
30
- * brittle when multiple overloads partially match, so we collapse to
31
- * one signature.
17
+ * Type-level dispatch happens via TWO typed overloads v4 first, v3
18
+ * secondplus an untyped impl. Each overload mirrors the matching
19
+ * direct adapter's signature exactly, so a v4-schema call site pays
20
+ * the same per-call depth cost as importing from `attaform/zod-v4`
21
+ * directly. Overload resolution at concrete call sites commits to one
22
+ * overload immediately on argument shape no type-level dispatch tax.
23
+ *
24
+ * Tests and other call sites that need the equivalent of
25
+ * `typeof useForm<X>` should reach for the `UseFormReturn<X>` /
26
+ * `UseFormConfig<X>` helpers in `types-api.ts` — instantiation
27
+ * expressions on overloaded functions follow brittle resolution rules,
28
+ * and the helper types give a deterministic projection.
32
29
  *
33
30
  * This module is the FALLBACK path. Vite consumers see the
34
31
  * `attaform/vite` plugin's `resolveId` hook rewrite `attaform/zod`
@@ -44,25 +41,14 @@ import 'vue';
44
41
  * adapter.
45
42
  */
46
43
 
47
- type FormInput<Schema> = Schema extends z.ZodObject ? z.input<Schema> extends GenericForm ? z.input<Schema> : never : Schema extends z.ZodObject<z.ZodRawShape> ? z.input<UnwrapZodObject<Schema>> extends GenericForm ? z.input<UnwrapZodObject<Schema>> : never : never;
48
- type FormOutput<Schema> = Schema extends z.ZodObject ? z.output<Schema> extends GenericForm ? z.output<Schema> : never : Schema extends z.ZodObject<z.ZodRawShape> ? z.output<UnwrapZodObject<Schema>> extends GenericForm ? z.output<UnwrapZodObject<Schema>> : never : never;
49
- type FormStorageShape<Schema> = Schema extends z.ZodObject ? StorageShape<Schema> extends GenericForm ? StorageShape<Schema> : never : Schema extends z.ZodObject<z.ZodRawShape> ? StorageShape$1<UnwrapZodObject<Schema>> extends GenericForm ? StorageShape$1<UnwrapZodObject<Schema>> : never : never;
50
- type UnifiedConfiguration<Schema> = Omit<UseFormConfiguration<FormInput<Schema>, FormOutput<Schema>, AbstractSchema<FormInput<Schema>, FormOutput<Schema>>, DeepPartial<DefaultValuesShape<FormInput<Schema>>>>, 'schema' | 'validateOn' | 'debounceMs'> & {
51
- schema: Schema;
52
- } & ValidateOnConfig;
44
+ type V4FormOf$1<S extends z.ZodObject> = z.input<S> extends GenericForm ? z.input<S> : never;
45
+ type V4OutOf$1<S extends z.ZodObject> = z.output<S> extends GenericForm ? z.output<S> : never;
46
+ type V4ReadOf$1<S extends z.ZodObject> = StorageShape<S> extends GenericForm ? StorageShape<S> : never;
47
+ type V3FormOf$1<S extends z.ZodObject<z.ZodRawShape>> = z.input<UnwrapZodObject<S>> extends GenericForm ? z.input<UnwrapZodObject<S>> : never;
48
+ type V3OutOf$1<S extends z.ZodObject<z.ZodRawShape>> = z.output<UnwrapZodObject<S>> extends GenericForm ? z.output<UnwrapZodObject<S>> : never;
49
+ type V3ReadOf$1<S extends z.ZodObject<z.ZodRawShape>> = StorageShape$1<UnwrapZodObject<S>> extends GenericForm ? StorageShape$1<UnwrapZodObject<S>> : never;
53
50
  /**
54
- * Create a form bound to a Zod schema. Accepts both Zod v3 and Zod v4
55
- * schemas; the runtime picks the right adapter from the schema's
56
- * shape.
57
- *
58
- * Type inference works transparently for both Zod v3 and Zod v4
59
- * schemas — the adapter is selected from the schema's shape at both
60
- * runtime and type-check time. `form.values`, `form.fields`,
61
- * `register`, and the `handleSubmit` callback data type all resolve
62
- * against the matching adapter's storage shape; consumers don't need
63
- * to reach for `attaform/zod-v3` or `attaform/zod-v4` to get full
64
- * inference. Those subpath entries remain as lean-bundle escape
65
- * hatches for non-Vite tooling, not correctness escape hatches.
51
+ * Create a form bound to a Zod v4 schema.
66
52
  *
67
53
  * ```ts
68
54
  * import { useForm } from 'attaform/zod'
@@ -75,8 +61,108 @@ type UnifiedConfiguration<Schema> = Omit<UseFormConfiguration<FormInput<Schema>,
75
61
  * }),
76
62
  * })
77
63
  * ```
64
+ *
65
+ * v4 schemas match this overload first via their structural `def`
66
+ * field. v3 schemas fall through to the v3 overload below.
78
67
  */
79
- declare function useForm<Schema extends z.ZodObject | z.ZodObject<z.ZodRawShape>>(configuration: UnifiedConfiguration<Schema>): UseFormReturnType<FormInput<Schema>, FormOutput<Schema>, FormStorageShape<Schema>>;
68
+ declare function useForm<Schema extends z.ZodObject, K extends FormKey = FormKey>(configuration: Omit<UseFormConfiguration<V4FormOf$1<Schema>, V4OutOf$1<Schema>, AbstractSchema<V4FormOf$1<Schema>, V4OutOf$1<Schema>>, DefaultValuesInput<V4FormOf$1<Schema>>, K>, 'schema' | 'validateOn' | 'debounceMs'> & {
69
+ schema: Schema;
70
+ } & ValidateOnConfig): UseFormReturnType<V4FormOf$1<Schema>, V4OutOf$1<Schema>, V4ReadOf$1<Schema>, K>;
71
+ /**
72
+ * Create a form bound to a Zod v3 schema.
73
+ *
74
+ * ```ts
75
+ * import { useForm } from 'attaform/zod'
76
+ * import { z } from 'zod-v3'
77
+ *
78
+ * const form = useForm({
79
+ * schema: z.object({
80
+ * username: z.string().min(2, 'At least 2 characters'),
81
+ * password: z.string().min(8, 'At least 8 characters'),
82
+ * }),
83
+ * })
84
+ * ```
85
+ *
86
+ * v3 schemas match this overload; v4 schemas hit the v4 overload
87
+ * above first and never reach here.
88
+ */
89
+ declare function useForm<Schema extends z.ZodObject<z.ZodRawShape>, K extends FormKey = FormKey>(configuration: Omit<UseFormConfiguration<V3FormOf$1<Schema>, V3OutOf$1<Schema>, AbstractSchema<V3FormOf$1<Schema>, V3OutOf$1<Schema>>, DefaultValuesInput<V3FormOf$1<Schema>>, K>, 'schema' | 'validateOn' | 'debounceMs'> & {
90
+ schema: Schema;
91
+ } & ValidateOnConfig): UseFormReturnType<V3FormOf$1<Schema>, V3OutOf$1<Schema>, V3ReadOf$1<Schema>, K>;
92
+
93
+ /**
94
+ * Type-level helpers for the unified `attaform/zod` entry. These give
95
+ * tests and other type-query call sites a deterministic projection
96
+ * over an arbitrary v4 OR v3 schema, sidestepping the brittle
97
+ * instantiation-expression resolution rules TypeScript applies to
98
+ * overloaded functions (`typeof useForm<X>` can pick the wrong
99
+ * overload or the impl signature, depending on whether the type
100
+ * argument is a concrete schema, a generic, or a constraint).
101
+ *
102
+ * The helpers dispatch ONCE per use site via a binary conditional —
103
+ * no stacking, no amplification across the return type. Equivalent
104
+ * to writing `ReturnType<typeof useForm<S>>` but cache-stable across
105
+ * call patterns.
106
+ *
107
+ * Per `inference-first DX`, these helpers are test- and
108
+ * internal-facing. Consumer code shouldn't reach for them — the
109
+ * overloaded `useForm` already gives full inference at call sites.
110
+ */
111
+
112
+ type V4FormOf<S extends z.ZodObject> = z.input<S> extends GenericForm ? z.input<S> : never;
113
+ type V4OutOf<S extends z.ZodObject> = z.output<S> extends GenericForm ? z.output<S> : never;
114
+ type V4ReadOf<S extends z.ZodObject> = StorageShape<S> extends GenericForm ? StorageShape<S> : never;
115
+ type V3FormOf<S extends z.ZodObject<z.ZodRawShape>> = z.input<UnwrapZodObject<S>> extends GenericForm ? z.input<UnwrapZodObject<S>> : never;
116
+ type V3OutOf<S extends z.ZodObject<z.ZodRawShape>> = z.output<UnwrapZodObject<S>> extends GenericForm ? z.output<UnwrapZodObject<S>> : never;
117
+ type V3ReadOf<S extends z.ZodObject<z.ZodRawShape>> = StorageShape$1<UnwrapZodObject<S>> extends GenericForm ? StorageShape$1<UnwrapZodObject<S>> : never;
118
+ /**
119
+ * Direct V4 projection — no major-dispatch. Use when the schema's
120
+ * Zod major is known statically (typical for V4 generic helpers like
121
+ * `function setup<S extends z.ZodObject>(s: S)`). TS simplifies the
122
+ * helper cleanly under generic constraints because no conditional
123
+ * is present.
124
+ */
125
+ type UseFormReturnV4<Schema extends z.ZodObject, K extends FormKey = FormKey> = UseFormReturnType<V4FormOf<Schema>, V4OutOf<Schema>, V4ReadOf<Schema>, K>;
126
+ /**
127
+ * Direct V4 configuration projection. Mirrors `UseFormReturnV4`.
128
+ */
129
+ type UseFormConfigV4<Schema extends z.ZodObject, K extends FormKey = FormKey> = Omit<UseFormConfiguration<V4FormOf<Schema>, V4OutOf<Schema>, AbstractSchema<V4FormOf<Schema>, V4OutOf<Schema>>, DefaultValuesInput<V4FormOf<Schema>>, K>, 'schema' | 'validateOn' | 'debounceMs'> & {
130
+ schema: Schema;
131
+ } & ValidateOnConfig;
132
+ /**
133
+ * Direct V3 projection — no major-dispatch. Use when the schema's
134
+ * Zod major is known statically.
135
+ */
136
+ type UseFormReturnV3<Schema extends z.ZodObject<z.ZodRawShape>, K extends FormKey = FormKey> = UseFormReturnType<V3FormOf<Schema>, V3OutOf<Schema>, V3ReadOf<Schema>, K>;
137
+ /**
138
+ * Direct V3 configuration projection. Mirrors `UseFormReturnV3`.
139
+ */
140
+ type UseFormConfigV3<Schema extends z.ZodObject<z.ZodRawShape>, K extends FormKey = FormKey> = Omit<UseFormConfiguration<V3FormOf<Schema>, V3OutOf<Schema>, AbstractSchema<V3FormOf<Schema>, V3OutOf<Schema>>, DefaultValuesInput<V3FormOf<Schema>>, K>, 'schema' | 'validateOn' | 'debounceMs'> & {
141
+ schema: Schema;
142
+ } & ValidateOnConfig;
143
+ /**
144
+ * The return shape of `useForm` for a given Zod schema. Dispatches
145
+ * once on the schema's major version and projects to the matching
146
+ * adapter's `Form` / `Out` / `Read` slots.
147
+ *
148
+ * Replaces `ReturnType<typeof useForm<Schema, K>>` in test code with
149
+ * concrete schemas. For generic helpers (`<S extends z.ZodObject>`),
150
+ * use `UseFormReturnV4<S>` directly — TS doesn't simplify
151
+ * conditional types under generic constraints, so the dispatch in
152
+ * this helper stays deferred and TS can't prove return-type
153
+ * compatibility.
154
+ */
155
+ type UseFormReturn<Schema, K extends FormKey = FormKey> = Schema extends z.ZodObject ? UseFormReturnType<V4FormOf<Schema>, V4OutOf<Schema>, V4ReadOf<Schema>, K> : Schema extends z.ZodObject<z.ZodRawShape> ? UseFormReturnType<V3FormOf<Schema>, V3OutOf<Schema>, V3ReadOf<Schema>, K> : never;
156
+ /**
157
+ * The configuration parameter shape of `useForm` for a given Zod
158
+ * schema. Mirrors `UseFormReturn`'s dispatch — replaces
159
+ * `Parameters<typeof useForm<Schema, K>>[0]` in test code.
160
+ */
161
+ type UseFormConfig<Schema, K extends FormKey = FormKey> = Schema extends z.ZodObject ? Omit<UseFormConfiguration<V4FormOf<Schema>, V4OutOf<Schema>, AbstractSchema<V4FormOf<Schema>, V4OutOf<Schema>>, DefaultValuesInput<V4FormOf<Schema>>, K>, 'schema' | 'validateOn' | 'debounceMs'> & {
162
+ schema: Schema;
163
+ } & ValidateOnConfig : Schema extends z.ZodObject<z.ZodRawShape> ? Omit<UseFormConfiguration<V3FormOf<Schema>, V3OutOf<Schema>, AbstractSchema<V3FormOf<Schema>, V3OutOf<Schema>>, DefaultValuesInput<V3FormOf<Schema>>, K>, 'schema' | 'validateOn' | 'debounceMs'> & {
164
+ schema: Schema;
165
+ } & ValidateOnConfig : never;
80
166
 
81
167
  /**
82
168
  * Field-metadata write/read API for the unified `attaform/zod` entry.
@@ -124,3 +210,4 @@ declare const fieldMeta: ZodFieldMetaRegistry;
124
210
  declare function withMeta<S>(schema: S, payload: FieldMetaPayload): S;
125
211
 
126
212
  export { FieldMetaPayload, fieldMeta, useForm, withMeta };
213
+ export type { UseFormConfig, UseFormConfigV3, UseFormConfigV4, UseFormReturn, UseFormReturnV3, UseFormReturnV4 };
package/dist/zod.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import { b as InvalidUseFormConfigError } from './shared/attaform.CIEQgJnM.mjs';
2
- export { u as useRegister } from './shared/attaform.CIEQgJnM.mjs';
3
- import { u as useForm$2 } from './shared/attaform.Drt6fivF.mjs';
4
- import { u as useForm$1 } from './shared/attaform.CpERWz3u.mjs';
5
- export { A as AttaformErrorCode, i as injectForm, a as isUnset, u as unset } from './shared/attaform.B3ZaPIzS.mjs';
1
+ import { d as InvalidUseFormConfigError } from './shared/attaform.Xhg0AYNa.mjs';
2
+ export { u as useRegister } from './shared/attaform.Xhg0AYNa.mjs';
3
+ import { u as useForm$2 } from './shared/attaform.CtNUB9nf.mjs';
4
+ import { u as useForm$1 } from './shared/attaform.Xt0A3QUd.mjs';
5
+ export { A as AttaformErrorCode, i as injectForm, a as injectWizard, b as isUnset, l as lazy, u as unset, c as useWizard } from './shared/attaform.DsC3rZHG.mjs';
6
6
  import { f as fieldMetaStore, g as getFieldMetaForSchema } from './shared/attaform.D13GMFgK.mjs';
7
7
 
8
8
  function isZodV4SchemaShape(value) {
@@ -18,13 +18,9 @@ function useForm(configuration) {
18
18
  }
19
19
  const { schema } = configuration;
20
20
  if (isZodV4SchemaShape(schema)) {
21
- return useForm$1(
22
- configuration
23
- );
21
+ return useForm$1(configuration);
24
22
  }
25
- return useForm$2(
26
- configuration
27
- );
23
+ return useForm$2(configuration);
28
24
  }
29
25
 
30
26
  const fieldMeta = fieldMetaStore;
package/dist/zod.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"zod.mjs","sources":["../src/runtime/core/zod-shape.ts","../src/runtime/adapters/unified/use-form.ts","../src/runtime/adapters/unified/field-meta.ts"],"sourcesContent":["/**\n * Shape detectors for Zod schemas. Used by the unified `attaform/zod`\n * entry's runtime dispatch (`runtime/adapters/unified/use-form.ts`)\n * to route to the v3 or v4 adapter based on the schema's runtime\n * shape. Mirrors the discrimination already used by the v4\n * introspection helper (`adapters/zod-v4/introspect.ts`'s\n * `assertZodVersion`, which reads `def.type`) and the v3 wrapper's\n * legitimate-input branch (`composables/use-form.ts`'s `isZodType`,\n * which reads `_def`).\n *\n * Why this discriminator and not `_zod` / `_def`:\n * - Zod v4 retained `_def` for backward compat — reading `_def` alone\n * misclassifies v4 schemas as v3.\n * - Zod v4's stable shape is `def.type: string` (lowercase tag like\n * `'object'`); Zod v3's is `_def.typeName: string` (capitalised tag\n * like `'ZodObject'`). Both are checked structurally so consumers\n * who alias one Zod major to a non-standard import path still work.\n */\n\ninterface ZodV4Shape {\n def: { type: unknown }\n}\n\ninterface ZodV3Shape {\n _def: { typeName: unknown }\n}\n\n/**\n * Returns true when `value` looks like a Zod schema of either major\n * version. Convenience wrapper around the v3 / v4 detectors.\n */\nexport function isZodSchemaShape(value: unknown): boolean {\n return isZodV4SchemaShape(value) || isZodV3SchemaShape(value)\n}\n\n/**\n * Returns true when `value` looks like a Zod v4 schema (has\n * `def.type: string`). Used by the unified entry's runtime-dispatch\n * to route to the v4 adapter.\n */\nexport function isZodV4SchemaShape(value: unknown): value is ZodV4Shape {\n if (typeof value !== 'object' || value === null) return false\n const def = (value as { def?: unknown }).def\n if (typeof def !== 'object' || def === null) return false\n return typeof (def as { type?: unknown }).type === 'string'\n}\n\n/**\n * Returns true when `value` looks like a Zod v3 schema (has\n * `_def.typeName: string`). Kept distinct from `isZodV4SchemaShape`\n * because some v4 schemas also expose `_def` for backward compat —\n * the v4 detector wins first in `isZodSchemaShape`.\n */\nexport function isZodV3SchemaShape(value: unknown): value is ZodV3Shape {\n if (typeof value !== 'object' || value === null) return false\n const def = (value as { _def?: unknown })._def\n if (typeof def !== 'object' || def === null) return false\n return typeof (def as { typeName?: unknown }).typeName === 'string'\n}\n","/**\n * Unified `useForm` for the `attaform/zod` entry. Runtime-dispatches\n * on schema shape: a Zod v4 schema (`def.type` truthy) routes to the\n * v4 adapter; a Zod v3 schema (or any other `AbstractSchema`) routes\n * to the v3 wrapper, which already accepts both Zod v3 input and\n * `AbstractSchema` directly via its built-in shape branch.\n *\n * Type-level dispatch happens through a single signature with a\n * union constraint — `Schema extends z.ZodObject |\n * zV3.ZodObject<zV3.ZodRawShape>`. The configuration parameter and\n * return type both dispatch conditionally on whether `Schema` is a\n * v4 or v3 object. The two majors don't structurally satisfy each\n * other's `ZodObject` constraints (v4 has `loose` / `safeExtend` /\n * `def` / `type` members v3 lacks), so neither alone is enough — the\n * union accepts both, and the conditional return type routes through\n * the matching adapter's `StorageShape` / `z.input` / `z.output`.\n *\n * A single signature (rather than overloads) keeps `typeof\n * useForm<X>` instantiation expressions in test code unambiguous:\n * TypeScript's overload-resolution rules for these expressions are\n * brittle when multiple overloads partially match, so we collapse to\n * one signature.\n *\n * This module is the FALLBACK path. Vite consumers see the\n * `attaform/vite` plugin's `resolveId` hook rewrite `attaform/zod`\n * imports to either `attaform/zod-v3` or `attaform/zod-v4` at build\n * time — in that case this dispatch never runs and the consumer\n * bundle ships only the matching adapter. Other bundlers (and\n * non-bundled ESM consumption) hit this dispatch instead, paying a\n * modest size cost for the convenience of a single hello-world import.\n *\n * Power users who want a guaranteed lean bundle on non-Vite tooling\n * can import directly from `attaform/zod-v3` or `attaform/zod-v4` —\n * those subpaths are never rewritten and never load the other\n * adapter.\n */\nimport type { z } from 'zod'\nimport type { z as zV3 } from 'zod-v3'\nimport { InvalidUseFormConfigError } from '../../core/errors'\nimport { isZodV4SchemaShape } from '../../core/zod-shape'\nimport { useForm as useFormV3 } from '../../composables/use-form'\nimport { useForm as useFormV4 } from '../zod-v4'\nimport type { StorageShape as StorageShapeV4 } from '../zod-v4/types-storage-shape'\nimport type { StorageShape as StorageShapeV3 } from '../zod-v3/types-storage-shape'\nimport type { UnwrapZodObject } from '../zod-v3/types-zod-adapter'\nimport type {\n AbstractSchema,\n ValidateOnConfig,\n UseFormReturnType,\n UseFormConfiguration,\n} from '../../types/types-api'\nimport type { DeepPartial, DefaultValuesShape, GenericForm } from '../../types/types-core'\n\n// ───────────────────────────────────────────────────────────────────\n// Per-major projections. Each dispatches a single Schema to the\n// matching adapter's input / output / storage-shape slot. The\n// trailing `never` arms catch the \"other major\" case so an isolated\n// instantiation stays well-formed; the union constraint on the\n// public signature guarantees one arm always fires.\n// ───────────────────────────────────────────────────────────────────\n\ntype FormInput<Schema> = Schema extends z.ZodObject\n ? z.input<Schema> extends GenericForm\n ? z.input<Schema>\n : never\n : Schema extends zV3.ZodObject<zV3.ZodRawShape>\n ? zV3.input<UnwrapZodObject<Schema>> extends GenericForm\n ? zV3.input<UnwrapZodObject<Schema>>\n : never\n : never\n\ntype FormOutput<Schema> = Schema extends z.ZodObject\n ? z.output<Schema> extends GenericForm\n ? z.output<Schema>\n : never\n : Schema extends zV3.ZodObject<zV3.ZodRawShape>\n ? zV3.output<UnwrapZodObject<Schema>> extends GenericForm\n ? zV3.output<UnwrapZodObject<Schema>>\n : never\n : never\n\ntype FormStorageShape<Schema> = Schema extends z.ZodObject\n ? StorageShapeV4<Schema> extends GenericForm\n ? StorageShapeV4<Schema>\n : never\n : Schema extends zV3.ZodObject<zV3.ZodRawShape>\n ? StorageShapeV3<UnwrapZodObject<Schema>> extends GenericForm\n ? StorageShapeV3<UnwrapZodObject<Schema>>\n : never\n : never\n\n// Single unified configuration shape. The outer structure is\n// non-conditional (so TS can resolve it for any Schema satisfying\n// the union constraint, including generic `F extends z.ZodObject`\n// helpers in test code); only the field-level types dispatch on\n// Schema kind via `FormInput` / `FormOutput`. The runtime cast\n// passes the configuration through unchanged — each adapter's own\n// signature absorbs the residual structural drift.\ntype UnifiedConfiguration<Schema> = Omit<\n UseFormConfiguration<\n FormInput<Schema>,\n FormOutput<Schema>,\n AbstractSchema<FormInput<Schema>, FormOutput<Schema>>,\n DeepPartial<DefaultValuesShape<FormInput<Schema>>>\n >,\n 'schema' | 'validateOn' | 'debounceMs'\n> & { schema: Schema } & ValidateOnConfig\n\n/**\n * Create a form bound to a Zod schema. Accepts both Zod v3 and Zod v4\n * schemas; the runtime picks the right adapter from the schema's\n * shape.\n *\n * Type inference works transparently for both Zod v3 and Zod v4\n * schemas — the adapter is selected from the schema's shape at both\n * runtime and type-check time. `form.values`, `form.fields`,\n * `register`, and the `handleSubmit` callback data type all resolve\n * against the matching adapter's storage shape; consumers don't need\n * to reach for `attaform/zod-v3` or `attaform/zod-v4` to get full\n * inference. Those subpath entries remain as lean-bundle escape\n * hatches for non-Vite tooling, not correctness escape hatches.\n *\n * ```ts\n * import { useForm } from 'attaform/zod'\n * import { z } from 'zod'\n *\n * const form = useForm({\n * schema: z.object({\n * username: z.string().min(2, 'At least 2 characters'),\n * password: z.string().min(8, 'At least 8 characters'),\n * }),\n * })\n * ```\n */\nexport function useForm<Schema extends z.ZodObject | zV3.ZodObject<zV3.ZodRawShape>>(\n configuration: UnifiedConfiguration<Schema>\n): UseFormReturnType<FormInput<Schema>, FormOutput<Schema>, FormStorageShape<Schema>> {\n // Foot-gun guard mirrors the typed wrappers'.\n if (\n configuration === undefined ||\n configuration === null ||\n (configuration as { schema?: unknown }).schema === undefined\n ) {\n throw new InvalidUseFormConfigError()\n }\n\n const { schema } = configuration as { schema: unknown }\n if (isZodV4SchemaShape(schema)) {\n return useFormV4(\n configuration as Parameters<typeof useFormV4>[0]\n ) as unknown as UseFormReturnType<\n FormInput<Schema>,\n FormOutput<Schema>,\n FormStorageShape<Schema>\n >\n }\n // Anything else (Zod v3 schema, custom AbstractSchema, schema\n // factory) goes through the v3 wrapper, which already accepts both\n // Zod v3 input and AbstractSchema directly via its existing shape\n // branch.\n return useFormV3(\n configuration as Parameters<typeof useFormV3>[0]\n ) as unknown as UseFormReturnType<FormInput<Schema>, FormOutput<Schema>, FormStorageShape<Schema>>\n}\n","/**\n * Field-metadata write/read API for the unified `attaform/zod` entry.\n *\n * Storage is shared with both adapters via `field-meta-store` — a\n * payload written here is visible to whichever adapter the unified\n * `useForm` dispatches to at runtime, regardless of Zod major. No\n * `zod` runtime import; the type-only `import type` is erased at\n * build, so `attaform/zod` carries no `z.registry` reference even\n * when consumed by a Zod 3 project without the Vite plugin alias.\n *\n * The native v4 chain `schema.register(fieldMeta, payload)` continues\n * to work — Zod 4's `.register()` only calls `.add(this, payload)`\n * structurally, satisfied by the shared store.\n */\nimport type { z } from 'zod'\nimport type { FieldMetaPayload } from '../../core/field-meta'\nimport { fieldMetaStore, getFieldMetaForSchema } from '../../core/field-meta-store'\n\n// Zod v4's `$ZodRegistry` class isn't surfaced under the `z` namespace\n// of the classic external entry, but `z.registry()` returns one — so\n// `ReturnType<typeof z.registry<T>>` resolves to the registry type\n// without needing a direct import. The `import type` keeps the\n// reference type-only; nothing about `z.registry` lands in the bundle.\ntype ZodFieldMetaRegistry = ReturnType<typeof z.registry<FieldMetaPayload>>\n\n/**\n * The shared registry every Attaform-aware Zod schema can register\n * field metadata against, regardless of major. Same instance the v3\n * and v4 adapter entries expose — write in one place, read from\n * any.\n *\n * Cast to Zod 4's `$ZodRegistry<FieldMetaPayload>` so the native\n * `schema.register(fieldMeta, payload)` chain type-checks for v4\n * users; the runtime call only needs `.add` structurally, which the\n * shared store provides.\n */\nexport const fieldMeta = fieldMetaStore as unknown as ZodFieldMetaRegistry\n\n/**\n * Attach `payload` to `schema` in the shared registry and return a\n * clone of `schema` so each call gets its own identity (the registry\n * keys on schema reference, so cloning prevents last-write-wins\n * collisions for sub-schemas reused at multiple paths).\n *\n * Works on both Zod 3 and Zod 4 schemas — branches on the runtime\n * shape of the schema:\n * - Zod 4 schemas expose a public `.clone()` method; we call it.\n * - Zod 3 schemas don't, so we reconstruct via\n * `new schema.constructor(schema._def)`.\n *\n * Both forms produce a fresh schema with the same effective\n * structure, so the registry slot is unique to this call site.\n */\nexport function withMeta<S>(schema: S, payload: FieldMetaPayload): S {\n const target = schema as object\n const existing = getFieldMetaForSchema(target) ?? {}\n const cloned = cloneSchema(schema)\n fieldMetaStore.add(cloned as object, { ...existing, ...payload })\n return cloned\n}\n\nfunction cloneSchema<S>(schema: S): S {\n const candidate = schema as { clone?: unknown; constructor: unknown; _def: unknown }\n if (typeof candidate.clone === 'function') {\n return (candidate.clone as () => S)()\n }\n // Zod 3 path: reconstruct via constructor + _def (no public\n // `.clone()` on v3).\n const Ctor = candidate.constructor as new (def: unknown) => S\n return new Ctor(candidate._def)\n}\n"],"names":["useFormV4","useFormV3"],"mappings":";;;;;;;AAwCO,SAAS,mBAAmB,KAAA,EAAqC;AACtE,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,MAAM,OAAO,KAAA;AACxD,EAAA,MAAM,MAAO,KAAA,CAA4B,GAAA;AACzC,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,KAAQ,MAAM,OAAO,KAAA;AACpD,EAAA,OAAO,OAAQ,IAA2B,IAAA,KAAS,QAAA;AACrD;;ACyFO,SAAS,QACd,aAAA,EACoF;AAEpF,EAAA,IACE,kBAAkB,MAAA,IAClB,aAAA,KAAkB,IAAA,IACjB,aAAA,CAAuC,WAAW,MAAA,EACnD;AACA,IAAA,MAAM,IAAI,yBAAA,EAA0B;AAAA,EACtC;AAEA,EAAA,MAAM,EAAE,QAAO,GAAI,aAAA;AACnB,EAAA,IAAI,kBAAA,CAAmB,MAAM,CAAA,EAAG;AAC9B,IAAA,OAAOA,SAAA;AAAA,MACL;AAAA,KACF;AAAA,EAKF;AAKA,EAAA,OAAOC,SAAA;AAAA,IACL;AAAA,GACF;AACF;;AC/HO,MAAM,SAAA,GAAY;AAiBlB,SAAS,QAAA,CAAY,QAAW,OAAA,EAA8B;AACnE,EAAA,MAAM,MAAA,GAAS,MAAA;AACf,EAAA,MAAM,QAAA,GAAW,qBAAA,CAAsB,MAAM,CAAA,IAAK,EAAC;AACnD,EAAA,MAAM,MAAA,GAAS,YAAY,MAAM,CAAA;AACjC,EAAA,cAAA,CAAe,IAAI,MAAA,EAAkB,EAAE,GAAG,QAAA,EAAU,GAAG,SAAS,CAAA;AAChE,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,YAAe,MAAA,EAAc;AACpC,EAAA,MAAM,SAAA,GAAY,MAAA;AAClB,EAAA,IAAI,OAAO,SAAA,CAAU,KAAA,KAAU,UAAA,EAAY;AACzC,IAAA,OAAQ,UAAU,KAAA,EAAkB;AAAA,EACtC;AAGA,EAAA,MAAM,OAAO,SAAA,CAAU,WAAA;AACvB,EAAA,OAAO,IAAI,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA;AAChC;;;;"}
1
+ {"version":3,"file":"zod.mjs","sources":["../src/runtime/core/zod-shape.ts","../src/runtime/adapters/unified/use-form.ts","../src/runtime/adapters/unified/field-meta.ts"],"sourcesContent":["/**\n * Shape detectors for Zod schemas. Used by the unified `attaform/zod`\n * entry's runtime dispatch (`runtime/adapters/unified/use-form.ts`)\n * to route to the v3 or v4 adapter based on the schema's runtime\n * shape. Mirrors the discrimination already used by the v4\n * introspection helper (`adapters/zod-v4/introspect.ts`'s\n * `assertZodVersion`, which reads `def.type`) and the v3 wrapper's\n * legitimate-input branch (`composables/use-form.ts`'s `isZodType`,\n * which reads `_def`).\n *\n * Why this discriminator and not `_zod` / `_def`:\n * - Zod v4 retained `_def` for backward compat — reading `_def` alone\n * misclassifies v4 schemas as v3.\n * - Zod v4's stable shape is `def.type: string` (lowercase tag like\n * `'object'`); Zod v3's is `_def.typeName: string` (capitalised tag\n * like `'ZodObject'`). Both are checked structurally so consumers\n * who alias one Zod major to a non-standard import path still work.\n */\n\ninterface ZodV4Shape {\n def: { type: unknown }\n}\n\ninterface ZodV3Shape {\n _def: { typeName: unknown }\n}\n\n/**\n * Returns true when `value` looks like a Zod schema of either major\n * version. Convenience wrapper around the v3 / v4 detectors.\n */\nexport function isZodSchemaShape(value: unknown): boolean {\n return isZodV4SchemaShape(value) || isZodV3SchemaShape(value)\n}\n\n/**\n * Returns true when `value` looks like a Zod v4 schema (has\n * `def.type: string`). Used by the unified entry's runtime-dispatch\n * to route to the v4 adapter.\n */\nexport function isZodV4SchemaShape(value: unknown): value is ZodV4Shape {\n if (typeof value !== 'object' || value === null) return false\n const def = (value as { def?: unknown }).def\n if (typeof def !== 'object' || def === null) return false\n return typeof (def as { type?: unknown }).type === 'string'\n}\n\n/**\n * Returns true when `value` looks like a Zod v3 schema (has\n * `_def.typeName: string`). Kept distinct from `isZodV4SchemaShape`\n * because some v4 schemas also expose `_def` for backward compat —\n * the v4 detector wins first in `isZodSchemaShape`.\n */\nexport function isZodV3SchemaShape(value: unknown): value is ZodV3Shape {\n if (typeof value !== 'object' || value === null) return false\n const def = (value as { _def?: unknown })._def\n if (typeof def !== 'object' || def === null) return false\n return typeof (def as { typeName?: unknown }).typeName === 'string'\n}\n","/**\n * Unified `useForm` for the `attaform/zod` entry. Runtime-dispatches\n * on schema shape: a Zod v4 schema (`def.type` truthy) routes to the\n * v4 adapter; a Zod v3 schema (or any other `AbstractSchema`) routes\n * to the v3 wrapper, which already accepts both Zod v3 input and\n * `AbstractSchema` directly via its built-in shape branch.\n *\n * Type-level dispatch happens via TWO typed overloads — v4 first, v3\n * second — plus an untyped impl. Each overload mirrors the matching\n * direct adapter's signature exactly, so a v4-schema call site pays\n * the same per-call depth cost as importing from `attaform/zod-v4`\n * directly. Overload resolution at concrete call sites commits to one\n * overload immediately on argument shape — no type-level dispatch tax.\n *\n * Tests and other call sites that need the equivalent of\n * `typeof useForm<X>` should reach for the `UseFormReturn<X>` /\n * `UseFormConfig<X>` helpers in `types-api.ts` — instantiation\n * expressions on overloaded functions follow brittle resolution rules,\n * and the helper types give a deterministic projection.\n *\n * This module is the FALLBACK path. Vite consumers see the\n * `attaform/vite` plugin's `resolveId` hook rewrite `attaform/zod`\n * imports to either `attaform/zod-v3` or `attaform/zod-v4` at build\n * time — in that case this dispatch never runs and the consumer\n * bundle ships only the matching adapter. Other bundlers (and\n * non-bundled ESM consumption) hit this dispatch instead, paying a\n * modest size cost for the convenience of a single hello-world import.\n *\n * Power users who want a guaranteed lean bundle on non-Vite tooling\n * can import directly from `attaform/zod-v3` or `attaform/zod-v4` —\n * those subpaths are never rewritten and never load the other\n * adapter.\n */\nimport type { z } from 'zod'\nimport type { z as zV3 } from 'zod-v3'\nimport { InvalidUseFormConfigError } from '../../core/errors'\nimport { isZodV4SchemaShape } from '../../core/zod-shape'\nimport { useForm as useFormV3 } from '../../composables/use-form'\nimport { useForm as useFormV4 } from '../zod-v4'\nimport type { StorageShape as StorageShapeV4 } from '../zod-v4/types-storage-shape'\nimport type { StorageShape as StorageShapeV3 } from '../zod-v3/types-storage-shape'\nimport type { UnwrapZodObject } from '../zod-v3/types-zod-adapter'\nimport type {\n AbstractSchema,\n FormKey,\n ValidateOnConfig,\n UseFormReturnType,\n UseFormConfiguration,\n} from '../../types/types-api'\nimport type { DefaultValuesInput, GenericForm } from '../../types/types-core'\n\n// ───────────────────────────────────────────────────────────────────\n// Per-major projection helpers. Each overload's constraint scopes the\n// Schema to one Zod major, so the projection is a direct read — no\n// dispatch in the type body. Mirrors the direct adapter shapes so the\n// unified entry pays the same per-call depth cost as a direct import.\n// ───────────────────────────────────────────────────────────────────\n\ntype V4FormOf<S extends z.ZodObject> = z.input<S> extends GenericForm ? z.input<S> : never\ntype V4OutOf<S extends z.ZodObject> = z.output<S> extends GenericForm ? z.output<S> : never\ntype V4ReadOf<S extends z.ZodObject> =\n StorageShapeV4<S> extends GenericForm ? StorageShapeV4<S> : never\n\ntype V3FormOf<S extends zV3.ZodObject<zV3.ZodRawShape>> =\n zV3.input<UnwrapZodObject<S>> extends GenericForm ? zV3.input<UnwrapZodObject<S>> : never\ntype V3OutOf<S extends zV3.ZodObject<zV3.ZodRawShape>> =\n zV3.output<UnwrapZodObject<S>> extends GenericForm ? zV3.output<UnwrapZodObject<S>> : never\ntype V3ReadOf<S extends zV3.ZodObject<zV3.ZodRawShape>> =\n StorageShapeV3<UnwrapZodObject<S>> extends GenericForm\n ? StorageShapeV3<UnwrapZodObject<S>>\n : never\n\n/**\n * Create a form bound to a Zod v4 schema.\n *\n * ```ts\n * import { useForm } from 'attaform/zod'\n * import { z } from 'zod'\n *\n * const form = useForm({\n * schema: z.object({\n * username: z.string().min(2, 'At least 2 characters'),\n * password: z.string().min(8, 'At least 8 characters'),\n * }),\n * })\n * ```\n *\n * v4 schemas match this overload first via their structural `def`\n * field. v3 schemas fall through to the v3 overload below.\n */\nexport function useForm<Schema extends z.ZodObject, K extends FormKey = FormKey>(\n configuration: Omit<\n UseFormConfiguration<\n V4FormOf<Schema>,\n V4OutOf<Schema>,\n AbstractSchema<V4FormOf<Schema>, V4OutOf<Schema>>,\n DefaultValuesInput<V4FormOf<Schema>>,\n K\n >,\n 'schema' | 'validateOn' | 'debounceMs'\n > & { schema: Schema } & ValidateOnConfig\n): UseFormReturnType<V4FormOf<Schema>, V4OutOf<Schema>, V4ReadOf<Schema>, K>\n/**\n * Create a form bound to a Zod v3 schema.\n *\n * ```ts\n * import { useForm } from 'attaform/zod'\n * import { z } from 'zod-v3'\n *\n * const form = useForm({\n * schema: z.object({\n * username: z.string().min(2, 'At least 2 characters'),\n * password: z.string().min(8, 'At least 8 characters'),\n * }),\n * })\n * ```\n *\n * v3 schemas match this overload; v4 schemas hit the v4 overload\n * above first and never reach here.\n */\nexport function useForm<Schema extends zV3.ZodObject<zV3.ZodRawShape>, K extends FormKey = FormKey>(\n configuration: Omit<\n UseFormConfiguration<\n V3FormOf<Schema>,\n V3OutOf<Schema>,\n AbstractSchema<V3FormOf<Schema>, V3OutOf<Schema>>,\n DefaultValuesInput<V3FormOf<Schema>>,\n K\n >,\n 'schema' | 'validateOn' | 'debounceMs'\n > & { schema: Schema } & ValidateOnConfig\n): UseFormReturnType<V3FormOf<Schema>, V3OutOf<Schema>, V3ReadOf<Schema>, K>\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function useForm(configuration: any): any {\n if (\n configuration === undefined ||\n configuration === null ||\n (configuration as { schema?: unknown }).schema === undefined\n ) {\n throw new InvalidUseFormConfigError()\n }\n const { schema } = configuration as { schema: unknown }\n if (isZodV4SchemaShape(schema)) {\n return useFormV4(configuration as Parameters<typeof useFormV4>[0])\n }\n return useFormV3(configuration as Parameters<typeof useFormV3>[0])\n}\n","/**\n * Field-metadata write/read API for the unified `attaform/zod` entry.\n *\n * Storage is shared with both adapters via `field-meta-store` — a\n * payload written here is visible to whichever adapter the unified\n * `useForm` dispatches to at runtime, regardless of Zod major. No\n * `zod` runtime import; the type-only `import type` is erased at\n * build, so `attaform/zod` carries no `z.registry` reference even\n * when consumed by a Zod 3 project without the Vite plugin alias.\n *\n * The native v4 chain `schema.register(fieldMeta, payload)` continues\n * to work — Zod 4's `.register()` only calls `.add(this, payload)`\n * structurally, satisfied by the shared store.\n */\nimport type { z } from 'zod'\nimport type { FieldMetaPayload } from '../../core/field-meta'\nimport { fieldMetaStore, getFieldMetaForSchema } from '../../core/field-meta-store'\n\n// Zod v4's `$ZodRegistry` class isn't surfaced under the `z` namespace\n// of the classic external entry, but `z.registry()` returns one — so\n// `ReturnType<typeof z.registry<T>>` resolves to the registry type\n// without needing a direct import. The `import type` keeps the\n// reference type-only; nothing about `z.registry` lands in the bundle.\ntype ZodFieldMetaRegistry = ReturnType<typeof z.registry<FieldMetaPayload>>\n\n/**\n * The shared registry every Attaform-aware Zod schema can register\n * field metadata against, regardless of major. Same instance the v3\n * and v4 adapter entries expose — write in one place, read from\n * any.\n *\n * Cast to Zod 4's `$ZodRegistry<FieldMetaPayload>` so the native\n * `schema.register(fieldMeta, payload)` chain type-checks for v4\n * users; the runtime call only needs `.add` structurally, which the\n * shared store provides.\n */\nexport const fieldMeta = fieldMetaStore as unknown as ZodFieldMetaRegistry\n\n/**\n * Attach `payload` to `schema` in the shared registry and return a\n * clone of `schema` so each call gets its own identity (the registry\n * keys on schema reference, so cloning prevents last-write-wins\n * collisions for sub-schemas reused at multiple paths).\n *\n * Works on both Zod 3 and Zod 4 schemas — branches on the runtime\n * shape of the schema:\n * - Zod 4 schemas expose a public `.clone()` method; we call it.\n * - Zod 3 schemas don't, so we reconstruct via\n * `new schema.constructor(schema._def)`.\n *\n * Both forms produce a fresh schema with the same effective\n * structure, so the registry slot is unique to this call site.\n */\nexport function withMeta<S>(schema: S, payload: FieldMetaPayload): S {\n const target = schema as object\n const existing = getFieldMetaForSchema(target) ?? {}\n const cloned = cloneSchema(schema)\n fieldMetaStore.add(cloned as object, { ...existing, ...payload })\n return cloned\n}\n\nfunction cloneSchema<S>(schema: S): S {\n const candidate = schema as { clone?: unknown; constructor: unknown; _def: unknown }\n if (typeof candidate.clone === 'function') {\n return (candidate.clone as () => S)()\n }\n // Zod 3 path: reconstruct via constructor + _def (no public\n // `.clone()` on v3).\n const Ctor = candidate.constructor as new (def: unknown) => S\n return new Ctor(candidate._def)\n}\n"],"names":["useFormV4","useFormV3"],"mappings":";;;;;;;AAwCO,SAAS,mBAAmB,KAAA,EAAqC;AACtE,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,MAAM,OAAO,KAAA;AACxD,EAAA,MAAM,MAAO,KAAA,CAA4B,GAAA;AACzC,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,KAAQ,MAAM,OAAO,KAAA;AACpD,EAAA,OAAO,OAAQ,IAA2B,IAAA,KAAS,QAAA;AACrD;;ACwFO,SAAS,QAAQ,aAAA,EAAyB;AAC/C,EAAA,IACE,kBAAkB,MAAA,IAClB,aAAA,KAAkB,IAAA,IACjB,aAAA,CAAuC,WAAW,MAAA,EACnD;AACA,IAAA,MAAM,IAAI,yBAAA,EAA0B;AAAA,EACtC;AACA,EAAA,MAAM,EAAE,QAAO,GAAI,aAAA;AACnB,EAAA,IAAI,kBAAA,CAAmB,MAAM,CAAA,EAAG;AAC9B,IAAA,OAAOA,UAAU,aAAgD,CAAA;AAAA,EACnE;AACA,EAAA,OAAOC,UAAU,aAAgD,CAAA;AACnE;;AC9GO,MAAM,SAAA,GAAY;AAiBlB,SAAS,QAAA,CAAY,QAAW,OAAA,EAA8B;AACnE,EAAA,MAAM,MAAA,GAAS,MAAA;AACf,EAAA,MAAM,QAAA,GAAW,qBAAA,CAAsB,MAAM,CAAA,IAAK,EAAC;AACnD,EAAA,MAAM,MAAA,GAAS,YAAY,MAAM,CAAA;AACjC,EAAA,cAAA,CAAe,IAAI,MAAA,EAAkB,EAAE,GAAG,QAAA,EAAU,GAAG,SAAS,CAAA;AAChE,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,YAAe,MAAA,EAAc;AACpC,EAAA,MAAM,SAAA,GAAY,MAAA;AAClB,EAAA,IAAI,OAAO,SAAA,CAAU,KAAA,KAAU,UAAA,EAAY;AACzC,IAAA,OAAQ,UAAU,KAAA,EAAkB;AAAA,EACtC;AAGA,EAAA,MAAM,OAAO,SAAA,CAAU,WAAA;AACvB,EAAA,OAAO,IAAI,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA;AAChC;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "attaform",
3
- "version": "0.17.2",
3
+ "version": "0.18.0",
4
4
  "main": "./dist/index.mjs",
5
5
  "types": "./dist/index.d.mts",
6
6
  "files": [
@@ -41,6 +41,9 @@
41
41
  "types": "./dist/vite.d.mts",
42
42
  "import": "./dist/vite.mjs"
43
43
  },
44
+ "./devtools-panel": {
45
+ "default": "./dist/runtime/components/AttaformDevtoolsPanel.vue"
46
+ },
44
47
  "./transforms": {
45
48
  "types": "./dist/transforms.d.mts",
46
49
  "import": "./dist/transforms.mjs"
@@ -83,6 +86,9 @@
83
86
  ],
84
87
  "license": "MIT",
85
88
  "type": "module",
89
+ "dependencies": {
90
+ "magic-string": "^0.30.21"
91
+ },
86
92
  "devDependencies": {
87
93
  "@commitlint/cli": "^21.0.1",
88
94
  "@commitlint/config-conventional": "^21.0.1",
@@ -100,9 +106,11 @@
100
106
  "@types/node": "^25.6.0",
101
107
  "@typescript-eslint/eslint-plugin": "^8.59.0",
102
108
  "@typescript-eslint/parser": "^8.59.0",
109
+ "@nuxt/devtools-kit": "^3.2.0",
103
110
  "@vitejs/plugin-vue": "^6.0.6",
104
111
  "@vitest/coverage-v8": "^4.1.5",
105
112
  "@vue/compiler-core": "^3.5.33",
113
+ "@vue/compiler-sfc": "^3.5.33",
106
114
  "@vue/devtools-api": "^8.1.1",
107
115
  "@vue/language-server": "^3.2.7",
108
116
  "@vue/server-renderer": "^3.5.33",
@@ -139,7 +147,9 @@
139
147
  "zod-v3": "npm:zod@^3.24"
140
148
  },
141
149
  "peerDependencies": {
150
+ "@nuxt/devtools-kit": "^2.0.0 || ^3.0.0",
142
151
  "@vue/compiler-core": ">=3.5.0",
152
+ "@vue/compiler-sfc": ">=3.5.0",
143
153
  "@vue/devtools-api": "^6.6.0 || ^7.0.0",
144
154
  "lodash-es": ">= 4.0.0",
145
155
  "nuxt": ">=3.0.0",
@@ -148,6 +158,9 @@
148
158
  "zod": ">=3.0.0"
149
159
  },
150
160
  "peerDependenciesMeta": {
161
+ "@nuxt/devtools-kit": {
162
+ "optional": true
163
+ },
151
164
  "@vue/devtools-api": {
152
165
  "optional": true
153
166
  },
@@ -175,13 +188,14 @@
175
188
  "typecheck": "tsc --noEmit",
176
189
  "prepack:watch": "chokidar 'src/**/*' -c 'pnpm prepack' --initial",
177
190
  "release": "pnpm check && pnpm version patch && pnpm prepack && pnpm publish && git push --follow-tags",
178
- "test": "vitest run",
191
+ "test": "node scripts/run-with-webstorage-flag.mjs vitest run",
179
192
  "test:types": "pnpm dev:prepare && vue-tsc --noEmit && cd apps/site && vue-tsc --noEmit",
180
- "test:watch": "vitest watch",
181
- "bench": "vitest bench --run",
193
+ "test:watch": "node scripts/run-with-webstorage-flag.mjs vitest watch",
194
+ "bench": "node scripts/run-with-webstorage-flag.mjs vitest bench --run",
182
195
  "check:size": "pnpm prepack && size-limit",
183
- "check:coverage": "vitest run --coverage",
196
+ "check:coverage": "node scripts/run-with-webstorage-flag.mjs vitest run --coverage",
184
197
  "check:bench": "node scripts/check-bench.mjs",
198
+ "check:bundled-types": "node scripts/check-bundled-types.mjs",
185
199
  "check:site": "pnpm dev:prepare && pnpm --filter attaform-site typecheck",
186
200
  "version": "node scripts/promote-changelog.mjs && (node scripts/generate-release-notes.mjs || echo '[version] release-notes step failed; continuing') && git add CHANGELOG.md RELEASES.md"
187
201
  }
@@ -1,156 +0,0 @@
1
- import { G as GenericForm, F as FormKey, d as UseFormReturnType, R as RegisterValue } from './attaform.C_5aB6EQ.mjs';
2
- import { Ref } from 'vue';
3
-
4
- /**
5
- * Access an existing form from a descendant component without passing
6
- * it through props. Counterpart to `useForm` — `useForm` creates and
7
- * provides; `injectForm` looks up via Vue's inject mechanism.
8
- *
9
- * Two ways to call it:
10
- *
11
- * ```ts
12
- * // Reach the nearest ancestor's anonymous useForm() call.
13
- * const form = injectForm<SignupShape>()
14
- *
15
- * // Reach a specific form by its key — works from anywhere in the app.
16
- * const cart = injectForm<CartShape>('cart')
17
- * ```
18
- *
19
- * Resolution rules (no-key form):
20
- * - Closest ambient ancestor wins.
21
- * - Only anonymous `useForm()` (no `key`) fills the ambient slot;
22
- * keyed forms are reachable only via `injectForm(key)`.
23
- * - Inherits the resolved ancestor's `formInstanceId`.
24
- *
25
- * Resolution rules (keyed form): registry lookup by string key,
26
- * independent of component-tree position.
27
- *
28
- * Returns `null` when no matching form exists (no ambient ancestor, or
29
- * the named key isn't registered). A dev-mode warning points at the
30
- * call site to help diagnose typos. Always narrow before using:
31
- *
32
- * ```ts
33
- * const form = injectForm<Shape>('signup')
34
- * if (!form) return
35
- * form.register('email')
36
- * ```
37
- *
38
- * Pass the `Form` generic explicitly — Vue's provide/inject erases
39
- * generics, so the library can't recover the shape automatically.
40
- *
41
- * The form is kept alive for this component's lifetime; once every
42
- * consumer unmounts, the form is cleaned up automatically.
43
- */
44
- declare function injectForm<Form extends GenericForm, GetValueFormType extends GenericForm = Form>(key?: FormKey): UseFormReturnType<Form, GetValueFormType> | null;
45
-
46
- /**
47
- * Re-bind a parent's `v-register` onto an inner native element. Use
48
- * inside a component that wraps a single form field whose root is
49
- * NOT the input itself (e.g. a labelled-row that renders `<label>`
50
- * around the input).
51
- *
52
- * ```vue
53
- * <!-- Parent -->
54
- * <MyInput v-register="form.register('email')" />
55
- *
56
- * <!-- MyInput.vue -->
57
- * <script setup lang="ts">
58
- * import { useRegister } from 'attaform'
59
- * const rv = useRegister()
60
- * // rv.path / rv.segments / rv.formKey / rv.formInstanceId / rv.innerRef
61
- * // are all reachable directly — no `.value` unwrap.
62
- * </script>
63
- *
64
- * <template>
65
- * <label class="field">
66
- * <span>Email</span>
67
- * <input v-register="rv" />
68
- * </label>
69
- * </template>
70
- * ```
71
- *
72
- * Returns a hybrid Proxy: it answers `__v_isRef` / `.value` like a
73
- * Vue `Ref<RegisterValue | undefined>` (so templates auto-unwrap
74
- * correctly and `v-register="rv"` feeds the underlying RV to the
75
- * directive — preserving the directive's path-migration diff across
76
- * renders), AND every other property read pierces to the captured
77
- * RV's field (so `rv.path` works directly in script setup). Reads
78
- * inside reactive scopes (`computed` / `watchEffect`) track the
79
- * underlying `shallowRef`, so `rv.path` re-runs when the parent
80
- * rebinds to a different path.
81
- *
82
- * Unbound state: when the parent didn't pass `v-register`, every
83
- * piercing read returns `undefined` at runtime, and the return type
84
- * surfaces this honestly as `UseRegisterReturn<V> | undefined`.
85
- * Consumers defend with optional chaining (`rv?.formKey`,
86
- * `rv?.segments`); the directive accepts `undefined` peacefully (its
87
- * binding value type is already `RegisterValue<V> | undefined`), so
88
- * `v-register="rv"` works whether or not a parent has bound. The
89
- * composable's `onMounted` warn fires once per instance to surface
90
- * the misuse case at runtime.
91
- *
92
- * Diagnostic: in dev mode, a single `console.warn` fires per instance
93
- * at `onMounted` if the captured value is still `undefined` — by then
94
- * the parent has had its full mount lifecycle to bind, so a missing
95
- * binding is conclusive misuse. The warn does NOT fire on every read
96
- * of the proxy, and is intentionally silent under SSR
97
- * (`renderToString` skips `onMounted`); the CSR hydration pass
98
- * surfaces the same diagnostic without double-counting through Nuxt's
99
- * `dev:ssr-logs` channel.
100
- *
101
- * When the wrapper's root IS the input itself, Vue's attribute
102
- * fallthrough handles the binding and `useRegister` is unnecessary.
103
- * For wrappers that bind multiple fields (compound forms), use
104
- * `injectForm<Form>(key?)` and call `ctx.register(...)` directly.
105
- */
106
-
107
- /**
108
- * Return type of `useRegister()`. Hybrid of `RegisterValue<V>` (so
109
- * `rv.path` / `rv.segments` / `rv.formKey` etc. work directly in
110
- * script setup) and `Ref<RegisterValue<V> | undefined>` (so Vue's
111
- * template auto-unwrap surfaces the underlying RV to `v-register`
112
- * and the directive's path-migration diff sees the real RV across
113
- * renders).
114
- *
115
- * The two surfaces don't clash at the type level: `RegisterValue`
116
- * doesn't carry a `value` field, and `Ref<T>`'s `value: T` becomes
117
- * the hybrid's only `.value`. Older code that read `rv.value?.path`
118
- * keeps working; new code can write `rv.path` directly.
119
- */
120
- type UseRegisterReturn<V = unknown> = RegisterValue<V> & Ref<RegisterValue<V> | undefined>;
121
- declare function useRegister<V = unknown>(): UseRegisterReturn<V> | undefined;
122
-
123
- /**
124
- * Stable identifiers for library-emitted `ValidationError` codes.
125
- *
126
- * Convention: `<scope>:<kebab-case-identifier>`. Three scopes are
127
- * recognised by the library:
128
- *
129
- * - `atta:` — emitted by the framework-agnostic core (this map).
130
- * - `zod:` — emitted by the Zod adapter; computed inline from
131
- * `issue.code` (e.g. `zod:too_small`). No enum here because
132
- * Zod's code list evolves.
133
- * - consumer-defined — anything the consumer's backend / app stamps
134
- * onto a `ValidationError` (via the `parseApiErrors` wire payload
135
- * or `setFieldErrors` directly). Pick a scope (`api:`, `auth:`,
136
- * etc.) and stay consistent.
137
- *
138
- * Use these constants in tests and error-routing UI:
139
- *
140
- * ```ts
141
- * if (error.code === AttaformErrorCode.NoValueSupplied) {
142
- * // user hasn't filled this field
143
- * }
144
- * ```
145
- */
146
- declare const AttaformErrorCode: {
147
- /** A required field is in the blank set — user hasn't supplied a value. */
148
- readonly NoValueSupplied: "atta:no-value-supplied";
149
- /** The schema adapter's `validateAtPath` threw synchronously. */
150
- readonly AdapterThrew: "atta:adapter-threw";
151
- /** The supplied path didn't resolve to any node in the schema. */
152
- readonly PathNotFound: "atta:path-not-found";
153
- };
154
- type AttaformErrorCode = (typeof AttaformErrorCode)[keyof typeof AttaformErrorCode];
155
-
156
- export { AttaformErrorCode as A, injectForm as i, useRegister as u };