attaform 0.15.1 → 0.16.1
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.
- package/README.md +24 -12
- package/dist/chunks/devtools.cjs +4 -4
- package/dist/chunks/devtools.cjs.map +1 -1
- package/dist/chunks/devtools.mjs +2 -2
- package/dist/chunks/indexeddb.cjs +4 -4
- package/dist/chunks/indexeddb.cjs.map +1 -1
- package/dist/chunks/indexeddb.mjs +1 -1
- package/dist/chunks/local-storage.cjs +2 -2
- package/dist/chunks/local-storage.cjs.map +1 -1
- package/dist/chunks/local-storage.mjs +1 -1
- package/dist/chunks/session-storage.cjs +2 -2
- package/dist/chunks/session-storage.cjs.map +1 -1
- package/dist/chunks/session-storage.mjs +1 -1
- package/dist/index.cjs +23 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -70
- package/dist/index.d.mts +75 -70
- package/dist/index.d.ts +75 -70
- package/dist/index.mjs +6 -6
- package/dist/nuxt.cjs +5 -11
- package/dist/nuxt.cjs.map +1 -1
- package/dist/nuxt.d.cts +8 -0
- package/dist/nuxt.d.mts +8 -0
- package/dist/nuxt.d.ts +8 -0
- package/dist/nuxt.mjs +6 -12
- package/dist/nuxt.mjs.map +1 -1
- package/dist/runtime/plugins/attaform.cjs +3 -2
- package/dist/runtime/plugins/attaform.cjs.map +1 -1
- package/dist/runtime/plugins/attaform.mjs +2 -1
- package/dist/runtime/plugins/attaform.mjs.map +1 -1
- package/dist/shared/{attaform.BwaYWtMs.d.cts → attaform.B7rzpK1U.d.cts} +34 -5
- package/dist/shared/{attaform.BwaYWtMs.d.mts → attaform.B7rzpK1U.d.mts} +34 -5
- package/dist/shared/{attaform.BwaYWtMs.d.ts → attaform.B7rzpK1U.d.ts} +34 -5
- package/dist/shared/attaform.BAuJTWuT.d.mts +84 -0
- package/dist/shared/{attaform.CRk8NhlD.mjs → attaform.BfMxsfmE.mjs} +428 -49
- package/dist/shared/attaform.BfMxsfmE.mjs.map +1 -0
- package/dist/shared/attaform.Bp1c-uGF.cjs +1561 -0
- package/dist/shared/attaform.Bp1c-uGF.cjs.map +1 -0
- package/dist/shared/{attaform.CDJVeoJU.cjs → attaform.C9Ph2SMx.cjs} +49 -42
- package/dist/shared/{attaform.qxyip_aN.mjs.map → attaform.C9Ph2SMx.cjs.map} +1 -1
- package/dist/shared/attaform.CINUMjPq.mjs +29 -0
- package/dist/shared/attaform.CINUMjPq.mjs.map +1 -0
- package/dist/shared/attaform.CJttVxRj.cjs +32 -0
- package/dist/shared/attaform.CJttVxRj.cjs.map +1 -0
- package/dist/shared/attaform.CvOXSpCb.mjs +1908 -0
- package/dist/shared/attaform.CvOXSpCb.mjs.map +1 -0
- package/dist/shared/{attaform.qxyip_aN.mjs → attaform.DILbdvfo.mjs} +12 -5
- package/dist/shared/{attaform.CDJVeoJU.cjs.map → attaform.DILbdvfo.mjs.map} +1 -1
- package/dist/shared/attaform.DdnithOf.mjs +1555 -0
- package/dist/shared/attaform.DdnithOf.mjs.map +1 -0
- package/dist/shared/attaform.DfrYByDj.cjs +1916 -0
- package/dist/shared/attaform.DfrYByDj.cjs.map +1 -0
- package/dist/shared/{attaform.BOi138GE.cjs → attaform.c_NzdRyc.cjs} +4 -4
- package/dist/shared/{attaform.BOi138GE.cjs.map → attaform.c_NzdRyc.cjs.map} +1 -1
- package/dist/shared/{attaform.DXye3JKf.mjs → attaform.jrxE_xZw.mjs} +2 -2
- package/dist/shared/{attaform.DXye3JKf.mjs.map → attaform.jrxE_xZw.mjs.map} +1 -1
- package/dist/shared/attaform.ls_7jBYc.d.ts +84 -0
- package/dist/shared/{attaform.BgYBU8gV.cjs → attaform.rIRYSUI1.cjs} +461 -61
- package/dist/shared/attaform.rIRYSUI1.cjs.map +1 -0
- package/dist/shared/attaform.xIcmqscx.d.cts +84 -0
- package/dist/vite.cjs +62 -9
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.cts +23 -32
- package/dist/vite.d.mts +23 -32
- package/dist/vite.d.ts +23 -32
- package/dist/vite.mjs +62 -9
- package/dist/vite.mjs.map +1 -1
- package/dist/zod-v3.cjs +9 -1553
- package/dist/zod-v3.cjs.map +1 -1
- package/dist/zod-v3.mjs +3 -1553
- package/dist/zod-v3.mjs.map +1 -1
- package/dist/zod-v4.cjs +21 -0
- package/dist/zod-v4.cjs.map +1 -0
- package/dist/zod-v4.d.cts +104 -0
- package/dist/zod-v4.d.mts +104 -0
- package/dist/zod-v4.d.ts +104 -0
- package/dist/zod-v4.mjs +4 -0
- package/dist/zod-v4.mjs.map +1 -0
- package/dist/zod.cjs +19 -1900
- package/dist/zod.cjs.map +1 -1
- package/dist/zod.d.cts +27 -155
- package/dist/zod.d.mts +27 -155
- package/dist/zod.d.ts +27 -155
- package/dist/zod.mjs +19 -1896
- package/dist/zod.mjs.map +1 -1
- package/package.json +6 -2
- package/dist/shared/attaform.BgYBU8gV.cjs.map +0 -1
- package/dist/shared/attaform.CRk8NhlD.mjs.map +0 -1
- package/dist/shared/attaform.RypIkgVy.cjs +0 -417
- package/dist/shared/attaform.RypIkgVy.cjs.map +0 -1
- package/dist/shared/attaform.a99dQV7Q.mjs +0 -392
- package/dist/shared/attaform.a99dQV7Q.mjs.map +0 -1
package/dist/nuxt.d.mts
CHANGED
|
@@ -23,6 +23,14 @@ interface AttaformModuleOptions {
|
|
|
23
23
|
* supported option set and merge rules.
|
|
24
24
|
*/
|
|
25
25
|
defaults?: AttaformDefaults;
|
|
26
|
+
/**
|
|
27
|
+
* Forwarded to `attaform/vite`'s `resolveZodAlias` option.
|
|
28
|
+
* Default `true` — `attaform/zod` imports are rewritten at build
|
|
29
|
+
* time to either `attaform/zod-v3` or `attaform/zod-v4`, based on
|
|
30
|
+
* the consumer's installed Zod major. Set to `false` to bypass
|
|
31
|
+
* the rewrite and ship the runtime-dispatch unified entry instead.
|
|
32
|
+
*/
|
|
33
|
+
resolveZodAlias?: boolean;
|
|
26
34
|
}
|
|
27
35
|
/**
|
|
28
36
|
* Shape of the Nuxt public runtime-config slot the module populates.
|
package/dist/nuxt.d.ts
CHANGED
|
@@ -23,6 +23,14 @@ interface AttaformModuleOptions {
|
|
|
23
23
|
* supported option set and merge rules.
|
|
24
24
|
*/
|
|
25
25
|
defaults?: AttaformDefaults;
|
|
26
|
+
/**
|
|
27
|
+
* Forwarded to `attaform/vite`'s `resolveZodAlias` option.
|
|
28
|
+
* Default `true` — `attaform/zod` imports are rewritten at build
|
|
29
|
+
* time to either `attaform/zod-v3` or `attaform/zod-v4`, based on
|
|
30
|
+
* the consumer's installed Zod major. Set to `false` to bypass
|
|
31
|
+
* the rewrite and ship the runtime-dispatch unified entry instead.
|
|
32
|
+
*/
|
|
33
|
+
resolveZodAlias?: boolean;
|
|
26
34
|
}
|
|
27
35
|
/**
|
|
28
36
|
* Shape of the Nuxt public runtime-config slot the module populates.
|
package/dist/nuxt.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
2
|
import { pathToFileURL } from 'node:url';
|
|
3
|
-
import { defineNuxtModule, createResolver, addImports, addPlugin, addTypeTemplate } from '@nuxt/kit';
|
|
4
|
-
import {
|
|
3
|
+
import { defineNuxtModule, addVitePlugin, createResolver, addImports, addPlugin, addTypeTemplate } from '@nuxt/kit';
|
|
4
|
+
import { attaform } from './vite.mjs';
|
|
5
5
|
|
|
6
6
|
function isResolvableForVite(specifier, consumerRootDir) {
|
|
7
7
|
const consumerURL = pathToFileURL(join(consumerRootDir, "package.json")).href;
|
|
@@ -25,20 +25,14 @@ var nuxt_default = defineNuxtModule({
|
|
|
25
25
|
},
|
|
26
26
|
defaults: {},
|
|
27
27
|
setup(_options, nuxt) {
|
|
28
|
-
var _a, _b
|
|
29
|
-
(
|
|
30
|
-
nuxt.options.vue.compilerOptions.nodeTransforms.push(
|
|
31
|
-
selectNodeTransform,
|
|
32
|
-
inputTextAreaNodeTransform,
|
|
33
|
-
vRegisterPreambleTransform,
|
|
34
|
-
vRegisterHintTransform
|
|
35
|
-
);
|
|
28
|
+
var _a, _b;
|
|
29
|
+
addVitePlugin(attaform({ resolveZodAlias: _options.resolveZodAlias !== false }));
|
|
36
30
|
const runtimePublic = nuxt.options.runtimeConfig.public;
|
|
37
31
|
runtimePublic["attaform"] = {
|
|
38
32
|
defaults: _options.defaults ?? {}
|
|
39
33
|
};
|
|
40
|
-
(
|
|
41
|
-
(
|
|
34
|
+
(_a = nuxt.options.vite).optimizeDeps ?? (_a.optimizeDeps = {});
|
|
35
|
+
(_b = nuxt.options.vite.optimizeDeps).include ?? (_b.include = []);
|
|
42
36
|
const include = nuxt.options.vite.optimizeDeps.include;
|
|
43
37
|
for (const spec of ["@vue/devtools-api", "zod"]) {
|
|
44
38
|
if (!isResolvableForVite(spec, nuxt.options.rootDir)) continue;
|
package/dist/nuxt.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nuxt.mjs","sources":["../src/nuxt.ts"],"sourcesContent":["import { join } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport { addImports, addPlugin, addTypeTemplate, createResolver, defineNuxtModule } from '@nuxt/kit'\nimport { inputTextAreaNodeTransform } from './runtime/lib/core/transforms/input-text-area-transform'\nimport { selectNodeTransform } from './runtime/lib/core/transforms/select-transform'\nimport { vRegisterHintTransform } from './runtime/lib/core/transforms/v-register-hint-transform'\nimport { vRegisterPreambleTransform } from './runtime/lib/core/transforms/v-register-preamble-transform'\nimport type { AttaformDefaults } from './runtime/types/types-api'\n\n/**\n * Options accepted by `attaform/nuxt` under the `attaform`\n * config key.\n *\n * ```ts\n * // nuxt.config.ts\n * export default defineNuxtConfig({\n * modules: ['attaform/nuxt'],\n * attaform: {\n * defaults: { debounceMs: 100 },\n * },\n * })\n * ```\n */\nexport interface AttaformModuleOptions {\n /**\n * App-level defaults applied to every `useForm` call. Per-form\n * options always win. See `AttaformDefaults` for the\n * supported option set and merge rules.\n */\n defaults?: AttaformDefaults\n}\n\n/**\n * Shape of the Nuxt public runtime-config slot the module populates.\n * Reach it via `useRuntimeConfig().public.attaform` if you need to\n * read the configured defaults outside the form library itself.\n */\nexport type AttaformRuntimeConfig = {\n defaults: AttaformDefaults\n}\n\n/**\n * Whether `specifier` is resolvable using ESM resolution from either the\n * consumer's project root or attaform's own module location. Returning\n * true matches what Vite's resolver would do for `optimizeDeps.include`,\n * so a true here means Vite will pre-bundle the dep without warning.\n *\n * Why two probe locations:\n * - Consumer-rootDir probe finds direct deps + their declared peers\n * (the standard pnpm strict-isolation visibility).\n * - attaform-module probe finds peers attaform itself declares —\n * specifically the optional `@vue/devtools-api`, which lands in\n * attaform's own node_modules tree (or pnpm virtual store) when\n * installed, even if the consumer never references it directly.\n *\n * Why ESM resolution (`import.meta.resolve`) rather than CJS\n * (`createRequire(...).resolve`):\n * - attaform's exports map declares only `import` conditions for\n * non-`/nuxt` entries. CJS resolve hits ERR_PACKAGE_PATH_NOT_EXPORTED\n * for `attaform` and its sub-entries.\n * - pnpm strict isolation hides hoisted transitives behind the\n * virtual store. CJS resolve walks the bare node_modules chain and\n * misses them; ESM resolve follows pnpm's symlinks correctly.\n * - `import.meta.resolve(spec, parentURL)` is sync and stable in\n * Node 20.6+, which attaform already requires (engines.node).\n */\nfunction isResolvableForVite(specifier: string, consumerRootDir: string): boolean {\n const consumerURL = pathToFileURL(join(consumerRootDir, 'package.json')).href\n return canResolve(specifier, consumerURL) || canResolve(specifier, import.meta.url)\n}\n\nfunction canResolve(specifier: string, fromURL: string): boolean {\n try {\n import.meta.resolve(specifier, fromURL)\n return true\n } catch {\n return false\n }\n}\n\nexport default defineNuxtModule<AttaformModuleOptions>({\n meta: {\n name: 'attaform',\n configKey: 'attaform',\n compatibility: {\n nuxt: '>=3.0.0',\n },\n },\n defaults: {},\n setup(_options, nuxt) {\n // vRegisterPreambleTransform MUST come before vRegisterHintTransform\n // — see src/vite.ts for the ordering rationale.\n nuxt.options.vue.compilerOptions.nodeTransforms ??= []\n nuxt.options.vue.compilerOptions.nodeTransforms.push(\n selectNodeTransform,\n inputTextAreaNodeTransform,\n vRegisterPreambleTransform,\n vRegisterHintTransform\n )\n\n // Publish module options to public runtime config so the plugin can\n // read them at install time on both server and client. Frozen-empty\n // by default — the plugin's merge code reads this slot directly\n // without a `?? {}` guard at every call site.\n const runtimePublic = nuxt.options.runtimeConfig.public as Record<string, unknown>\n runtimePublic['attaform'] = {\n defaults: _options.defaults ?? {},\n } satisfies AttaformRuntimeConfig\n\n // Force-include attaform's own peers that Vite's startup crawl\n // tends to miss for Nuxt projects. Vite scans `index.html` + the\n // statically-known entry points but doesn't deeply follow into\n // pages that get loaded via Nuxt's dynamic router; deps imported\n // exclusively from page chunks are discovered when the page first\n // requests, the optimizer rebundles, and Vite silently broadcasts\n // `{\"type\":\"full-reload\",\"path\":\"*\"}` over the HMR WebSocket — what\n // consumers see as \"the page loads, then reloads itself a second\n // later.\" Vite's own \"discovered new dependencies at runtime\"\n // warning recommends exactly this remediation.\n //\n // We declare here only deps attaform itself owns the relationship\n // with — `@vue/devtools-api` (attaform's DevTools integration\n // peer) and `zod` (the `/zod` and `/zod-v3` adapter peer). Consumer-\n // side deps (vue-query, immer, etc.) are the consumer's\n // responsibility — they declare them in their own\n // `vite.optimizeDeps.include`. Each push is gated on the spec\n // being resolvable from the consumer's project (or attaform's\n // own module context for attaform's optional peers like\n // devtools-api), so consumers without the optional peer don't see\n // a \"failed to resolve\" warning at boot.\n nuxt.options.vite.optimizeDeps ??= {}\n nuxt.options.vite.optimizeDeps.include ??= []\n const include = nuxt.options.vite.optimizeDeps.include\n for (const spec of ['@vue/devtools-api', 'zod']) {\n if (!isResolvableForVite(spec, nuxt.options.rootDir)) continue\n if (!include.includes(spec)) include.push(spec)\n }\n\n const resolver = createResolver(import.meta.url)\n\n // Auto-import `useForm` — the framework-agnostic core composable (same\n // binding as `attaform`'s top-level `useForm` export, which\n // is the abstract form composable). Consumers who want the zod-typed\n // wrapper must import from `attaform/zod` or `/zod-v3`\n // explicitly.\n //\n // We point at the public package entry rather than a relative\n // `./runtime/…` path on purpose: in the published package the\n // `src/runtime/composables/use-abstract-form` path has no matching\n // `dist/runtime/…` file (build.config's entries don't include it),\n // so a `resolver.resolve(...)` would raise ENOENT at Nuxt's auto-\n // import step. Importing from `attaform` resolves through\n // the shared chunk, identical to what `attaform/zod`\n // consumers bundle — single registry instance across both import\n // surfaces.\n addImports([{ name: 'useForm', from: 'attaform' }])\n\n // Plugin that installs `createAttaform()` on the Vue app and\n // wires the payload serialize/hydrate bridge. Uses a physical\n // `src/runtime/plugins/attaform.ts` file (shipped to\n // `dist/runtime/plugins/attaform.mjs` via an explicit entry in\n // build.config.ts) rather than an inline plugin template, because a\n // template's `import { createAttaform } from 'attaform'`\n // resolves through the `attaform` package entry — which in\n // local dev (`unbuild --stub`) is a jiti runtime transpiler whose\n // `node:module`/`createRequire` imports Nitro's Rollup build cannot\n // bundle. A physical file lets Nitro follow its imports directly\n // (TS source in dev, ESM in the published package), avoiding the\n // jiti indirection entirely. Unbuild's shared-chunk splitter keeps\n // `core/plugin` + `core/serialize` deduplicated with `src/zod` /\n // `src/index`, so there's still only one `registry` module at runtime.\n //\n // `addPlugin` defaults to PREPEND so the plugin runs before any\n // user plugin / page; `enforce: 'pre'` inside the plugin body makes\n // that ordering explicit at the Nuxt-plugin layer too. Together\n // they guarantee the registry is installed (and SSR payload staged\n // into `pendingHydration`) before any `useForm` call runs.\n addPlugin({\n src: resolver.resolve('./runtime/plugins/attaform'),\n })\n\n // v-register directive type. The directive itself is globally\n // registered by `createAttaform().install(app)` in the plugin\n // above; this template only publishes the type so that\n // `<input v-register=\"…\">` type-checks in consumer SFCs.\n addTypeTemplate({\n filename: 'types/v-register.d.ts',\n getContents: () => `// Generated by attaform\nimport type { ObjectDirective } from \"vue\"\nimport type { RegisterDirective } from \"attaform/types\"\n\ndeclare module \"vue\" {\n interface GlobalDirectives {\n /**\n * The \\`v-register\\` directive. Binds a form field to a native\n * input, select, textarea, checkbox, or radio:\n *\n * \\`\\`\\`vue\n * <input v-register=\"form.register('email')\" />\n * \\`\\`\\`\n *\n * Also works on custom components whose root is NOT a native\n * input — call \\`useRegister()\\` in the child's setup to read\n * the parent's binding, then re-bind \\`v-register\\` onto an\n * inner native element. (When the wrapper's root IS the input\n * itself, attribute fallthrough handles it; \\`useRegister\\` is\n * unnecessary.) See \\`RegisterDirective\\` for the full\n * non-input-root example.\n *\n * Modifier support varies by element:\n * - text / number / textarea: \\`.lazy\\`, \\`.trim\\`, \\`.number\\`\n * - select: \\`.number\\`\n * - checkbox / radio: none\n *\n * See \\`RegisterDirective\\` for full usage and per-modifier\n * semantics.\n */\n vRegister: RegisterDirective\n }\n}\n\nexport { }`,\n })\n },\n})\n"],"names":[],"mappings":";;;;;AAkEA,SAAS,mBAAA,CAAoB,WAAmB,eAAA,EAAkC;AAChF,EAAA,MAAM,cAAc,aAAA,CAAc,IAAA,CAAK,eAAA,EAAiB,cAAc,CAAC,CAAA,CAAE,IAAA;AACzE,EAAA,OAAO,WAAW,SAAA,EAAW,WAAW,KAAK,UAAA,CAAW,SAAA,EAAW,YAAY,GAAG,CAAA;AACpF;AAEA,SAAS,UAAA,CAAW,WAAmB,OAAA,EAA0B;AAC/D,EAAA,IAAI;AACF,IAAA,MAAA,CAAA,IAAA,CAAY,OAAA,CAAQ,WAAW,OAAO,CAAA;AACtC,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,IAAO,eAAQ,gBAAA,CAAwC;AAAA,EACrD,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,UAAA;AAAA,IACN,SAAA,EAAW,UAAA;AAAA,IACX,aAAA,EAAe;AAAA,MACb,IAAA,EAAM;AAAA;AACR,GACF;AAAA,EACA,UAAU,EAAC;AAAA,EACX,KAAA,CAAM,UAAU,IAAA,EAAM;AAzFxB,IAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AA4FI,IAAA,CAAA,EAAA,GAAA,IAAA,CAAK,QAAQ,GAAA,CAAI,eAAA,EAAgB,cAAA,KAAjC,EAAA,CAAiC,iBAAmB,EAAC,CAAA;AACrD,IAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,eAAA,CAAgB,cAAA,CAAe,IAAA;AAAA,MAC9C,mBAAA;AAAA,MACA,0BAAA;AAAA,MACA,0BAAA;AAAA,MACA;AAAA,KACF;AAMA,IAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,MAAA;AACjD,IAAA,aAAA,CAAc,UAAU,CAAA,GAAI;AAAA,MAC1B,QAAA,EAAU,QAAA,CAAS,QAAA,IAAY;AAAC,KAClC;AAuBA,IAAA,CAAA,EAAA,GAAA,IAAA,CAAK,OAAA,CAAQ,IAAA,EAAK,YAAA,KAAlB,EAAA,CAAkB,eAAiB,EAAC,CAAA;AACpC,IAAA,CAAA,EAAA,GAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,YAAA,EAAa,OAAA,KAA/B,EAAA,CAA+B,UAAY,EAAC,CAAA;AAC5C,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,YAAA,CAAa,OAAA;AAC/C,IAAA,KAAA,MAAW,IAAA,IAAQ,CAAC,mBAAA,EAAqB,KAAK,CAAA,EAAG;AAC/C,MAAA,IAAI,CAAC,mBAAA,CAAoB,IAAA,EAAM,IAAA,CAAK,OAAA,CAAQ,OAAO,CAAA,EAAG;AACtD,MAAA,IAAI,CAAC,OAAA,CAAQ,QAAA,CAAS,IAAI,CAAA,EAAG,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,IAChD;AAEA,IAAA,MAAM,QAAA,GAAW,cAAA,CAAe,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AAiB/C,IAAA,UAAA,CAAW,CAAC,EAAE,IAAA,EAAM,WAAW,IAAA,EAAM,UAAA,EAAY,CAAC,CAAA;AAsBlD,IAAA,SAAA,CAAU;AAAA,MACR,GAAA,EAAK,QAAA,CAAS,OAAA,CAAQ,4BAA4B;AAAA,KACnD,CAAA;AAMD,IAAA,eAAA,CAAgB;AAAA,MACd,QAAA,EAAU,uBAAA;AAAA,MACV,aAAa,MAAM,CAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,UAAA;AAAA,KAmCpB,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
|
|
1
|
+
{"version":3,"file":"nuxt.mjs","sources":["../src/nuxt.ts"],"sourcesContent":["import { join } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport {\n addImports,\n addPlugin,\n addTypeTemplate,\n addVitePlugin,\n createResolver,\n defineNuxtModule,\n} from '@nuxt/kit'\nimport type { AttaformDefaults } from './runtime/types/types-api'\nimport { attaform as attaformVitePlugin } from './vite'\n\n/**\n * Options accepted by `attaform/nuxt` under the `attaform`\n * config key.\n *\n * ```ts\n * // nuxt.config.ts\n * export default defineNuxtConfig({\n * modules: ['attaform/nuxt'],\n * attaform: {\n * defaults: { debounceMs: 100 },\n * },\n * })\n * ```\n */\nexport interface AttaformModuleOptions {\n /**\n * App-level defaults applied to every `useForm` call. Per-form\n * options always win. See `AttaformDefaults` for the\n * supported option set and merge rules.\n */\n defaults?: AttaformDefaults\n /**\n * Forwarded to `attaform/vite`'s `resolveZodAlias` option.\n * Default `true` — `attaform/zod` imports are rewritten at build\n * time to either `attaform/zod-v3` or `attaform/zod-v4`, based on\n * the consumer's installed Zod major. Set to `false` to bypass\n * the rewrite and ship the runtime-dispatch unified entry instead.\n */\n resolveZodAlias?: boolean\n}\n\n/**\n * Shape of the Nuxt public runtime-config slot the module populates.\n * Reach it via `useRuntimeConfig().public.attaform` if you need to\n * read the configured defaults outside the form library itself.\n */\nexport type AttaformRuntimeConfig = {\n defaults: AttaformDefaults\n}\n\n/**\n * Whether `specifier` is resolvable using ESM resolution from either the\n * consumer's project root or attaform's own module location. Returning\n * true matches what Vite's resolver would do for `optimizeDeps.include`,\n * so a true here means Vite will pre-bundle the dep without warning.\n *\n * Why two probe locations:\n * - Consumer-rootDir probe finds direct deps + their declared peers\n * (the standard pnpm strict-isolation visibility).\n * - attaform-module probe finds peers attaform itself declares —\n * specifically the optional `@vue/devtools-api`, which lands in\n * attaform's own node_modules tree (or pnpm virtual store) when\n * installed, even if the consumer never references it directly.\n *\n * Why ESM resolution (`import.meta.resolve`) rather than CJS\n * (`createRequire(...).resolve`):\n * - attaform's exports map declares only `import` conditions for\n * non-`/nuxt` entries. CJS resolve hits ERR_PACKAGE_PATH_NOT_EXPORTED\n * for `attaform` and its sub-entries.\n * - pnpm strict isolation hides hoisted transitives behind the\n * virtual store. CJS resolve walks the bare node_modules chain and\n * misses them; ESM resolve follows pnpm's symlinks correctly.\n * - `import.meta.resolve(spec, parentURL)` is sync and stable in\n * Node 20.6+, which attaform already requires (engines.node).\n */\nfunction isResolvableForVite(specifier: string, consumerRootDir: string): boolean {\n const consumerURL = pathToFileURL(join(consumerRootDir, 'package.json')).href\n return canResolve(specifier, consumerURL) || canResolve(specifier, import.meta.url)\n}\n\nfunction canResolve(specifier: string, fromURL: string): boolean {\n try {\n import.meta.resolve(specifier, fromURL)\n return true\n } catch {\n return false\n }\n}\n\nexport default defineNuxtModule<AttaformModuleOptions>({\n meta: {\n name: 'attaform',\n configKey: 'attaform',\n compatibility: {\n nuxt: '>=3.0.0',\n },\n },\n defaults: {},\n setup(_options, nuxt) {\n // Register `attaform/vite` so the same plugin handles every Vite-\n // surface concern: pushing the compile-time node transforms into\n // `@vitejs/plugin-vue`'s `api.options.template.compilerOptions.\n // nodeTransforms`, AND rewriting `attaform/zod` imports at build\n // time to either `/zod-v3` or `/zod-v4` based on the consumer's\n // installed Zod major. Consolidating both behaviors in one Vite\n // plugin instance keeps the Nuxt-side wiring minimal and ensures\n // the consumer's Nuxt build sees the exact same DX as a bare-Vite\n // consumer.\n addVitePlugin(attaformVitePlugin({ resolveZodAlias: _options.resolveZodAlias !== false }))\n\n // Publish module options to public runtime config so the plugin can\n // read them at install time on both server and client. Frozen-empty\n // by default — the plugin's merge code reads this slot directly\n // without a `?? {}` guard at every call site.\n const runtimePublic = nuxt.options.runtimeConfig.public as Record<string, unknown>\n runtimePublic['attaform'] = {\n defaults: _options.defaults ?? {},\n } satisfies AttaformRuntimeConfig\n\n // Force-include attaform's own peers that Vite's startup crawl\n // tends to miss for Nuxt projects. Vite scans `index.html` + the\n // statically-known entry points but doesn't deeply follow into\n // pages that get loaded via Nuxt's dynamic router; deps imported\n // exclusively from page chunks are discovered when the page first\n // requests, the optimizer rebundles, and Vite silently broadcasts\n // `{\"type\":\"full-reload\",\"path\":\"*\"}` over the HMR WebSocket — what\n // consumers see as \"the page loads, then reloads itself a second\n // later.\" Vite's own \"discovered new dependencies at runtime\"\n // warning recommends exactly this remediation.\n //\n // We declare here only deps attaform itself owns the relationship\n // with — `@vue/devtools-api` (attaform's DevTools integration\n // peer) and `zod` (the adapter peer for `/zod`, `/zod-v3`, and\n // `/zod-v4`). Consumer-\n // side deps (vue-query, immer, etc.) are the consumer's\n // responsibility — they declare them in their own\n // `vite.optimizeDeps.include`. Each push is gated on the spec\n // being resolvable from the consumer's project (or attaform's\n // own module context for attaform's optional peers like\n // devtools-api), so consumers without the optional peer don't see\n // a \"failed to resolve\" warning at boot.\n nuxt.options.vite.optimizeDeps ??= {}\n nuxt.options.vite.optimizeDeps.include ??= []\n const include = nuxt.options.vite.optimizeDeps.include\n for (const spec of ['@vue/devtools-api', 'zod']) {\n if (!isResolvableForVite(spec, nuxt.options.rootDir)) continue\n if (!include.includes(spec)) include.push(spec)\n }\n\n const resolver = createResolver(import.meta.url)\n\n // Auto-import `useForm` — the framework-agnostic core composable (same\n // binding as `attaform`'s top-level `useForm` export, which\n // is the abstract form composable). Consumers who want the zod-typed\n // wrapper must import from `attaform/zod` or `/zod-v3`\n // explicitly.\n //\n // We point at the public package entry rather than a relative\n // `./runtime/…` path on purpose: in the published package the\n // `src/runtime/composables/use-abstract-form` path has no matching\n // `dist/runtime/…` file (build.config's entries don't include it),\n // so a `resolver.resolve(...)` would raise ENOENT at Nuxt's auto-\n // import step. Importing from `attaform` resolves through\n // the shared chunk, identical to what `attaform/zod`\n // consumers bundle — single registry instance across both import\n // surfaces.\n addImports([{ name: 'useForm', from: 'attaform' }])\n\n // Plugin that installs `createAttaform()` on the Vue app and\n // wires the payload serialize/hydrate bridge. Uses a physical\n // `src/runtime/plugins/attaform.ts` file (shipped to\n // `dist/runtime/plugins/attaform.mjs` via an explicit entry in\n // build.config.ts) rather than an inline plugin template, because a\n // template's `import { createAttaform } from 'attaform'`\n // resolves through the `attaform` package entry — which in\n // local dev (`unbuild --stub`) is a jiti runtime transpiler whose\n // `node:module`/`createRequire` imports Nitro's Rollup build cannot\n // bundle. A physical file lets Nitro follow its imports directly\n // (TS source in dev, ESM in the published package), avoiding the\n // jiti indirection entirely. Unbuild's shared-chunk splitter keeps\n // `core/plugin` + `core/serialize` deduplicated with `src/zod` /\n // `src/index`, so there's still only one `registry` module at runtime.\n //\n // `addPlugin` defaults to PREPEND so the plugin runs before any\n // user plugin / page; `enforce: 'pre'` inside the plugin body makes\n // that ordering explicit at the Nuxt-plugin layer too. Together\n // they guarantee the registry is installed (and SSR payload staged\n // into `pendingHydration`) before any `useForm` call runs.\n addPlugin({\n src: resolver.resolve('./runtime/plugins/attaform'),\n })\n\n // v-register directive type. The directive itself is globally\n // registered by `createAttaform().install(app)` in the plugin\n // above; this template only publishes the type so that\n // `<input v-register=\"…\">` type-checks in consumer SFCs.\n addTypeTemplate({\n filename: 'types/v-register.d.ts',\n getContents: () => `// Generated by attaform\nimport type { ObjectDirective } from \"vue\"\nimport type { RegisterDirective } from \"attaform/types\"\n\ndeclare module \"vue\" {\n interface GlobalDirectives {\n /**\n * The \\`v-register\\` directive. Binds a form field to a native\n * input, select, textarea, checkbox, or radio:\n *\n * \\`\\`\\`vue\n * <input v-register=\"form.register('email')\" />\n * \\`\\`\\`\n *\n * Also works on custom components whose root is NOT a native\n * input — call \\`useRegister()\\` in the child's setup to read\n * the parent's binding, then re-bind \\`v-register\\` onto an\n * inner native element. (When the wrapper's root IS the input\n * itself, attribute fallthrough handles it; \\`useRegister\\` is\n * unnecessary.) See \\`RegisterDirective\\` for the full\n * non-input-root example.\n *\n * Modifier support varies by element:\n * - text / number / textarea: \\`.lazy\\`, \\`.trim\\`, \\`.number\\`\n * - select: \\`.number\\`\n * - checkbox / radio: none\n *\n * See \\`RegisterDirective\\` for full usage and per-modifier\n * semantics.\n */\n vRegister: RegisterDirective\n }\n}\n\nexport { }`,\n })\n },\n})\n"],"names":["attaformVitePlugin"],"mappings":";;;;;AA8EA,SAAS,mBAAA,CAAoB,WAAmB,eAAA,EAAkC;AAChF,EAAA,MAAM,cAAc,aAAA,CAAc,IAAA,CAAK,eAAA,EAAiB,cAAc,CAAC,CAAA,CAAE,IAAA;AACzE,EAAA,OAAO,WAAW,SAAA,EAAW,WAAW,KAAK,UAAA,CAAW,SAAA,EAAW,YAAY,GAAG,CAAA;AACpF;AAEA,SAAS,UAAA,CAAW,WAAmB,OAAA,EAA0B;AAC/D,EAAA,IAAI;AACF,IAAA,MAAA,CAAA,IAAA,CAAY,OAAA,CAAQ,WAAW,OAAO,CAAA;AACtC,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,IAAO,eAAQ,gBAAA,CAAwC;AAAA,EACrD,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,UAAA;AAAA,IACN,SAAA,EAAW,UAAA;AAAA,IACX,aAAA,EAAe;AAAA,MACb,IAAA,EAAM;AAAA;AACR,GACF;AAAA,EACA,UAAU,EAAC;AAAA,EACX,KAAA,CAAM,UAAU,IAAA,EAAM;AArGxB,IAAA,IAAA,EAAA,EAAA,EAAA;AA+GI,IAAA,aAAA,CAAcA,SAAmB,EAAE,eAAA,EAAiB,SAAS,eAAA,KAAoB,KAAA,EAAO,CAAC,CAAA;AAMzF,IAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,MAAA;AACjD,IAAA,aAAA,CAAc,UAAU,CAAA,GAAI;AAAA,MAC1B,QAAA,EAAU,QAAA,CAAS,QAAA,IAAY;AAAC,KAClC;AAwBA,IAAA,CAAA,EAAA,GAAA,IAAA,CAAK,OAAA,CAAQ,IAAA,EAAK,YAAA,KAAlB,EAAA,CAAkB,eAAiB,EAAC,CAAA;AACpC,IAAA,CAAA,EAAA,GAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,YAAA,EAAa,OAAA,KAA/B,EAAA,CAA+B,UAAY,EAAC,CAAA;AAC5C,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,YAAA,CAAa,OAAA;AAC/C,IAAA,KAAA,MAAW,IAAA,IAAQ,CAAC,mBAAA,EAAqB,KAAK,CAAA,EAAG;AAC/C,MAAA,IAAI,CAAC,mBAAA,CAAoB,IAAA,EAAM,IAAA,CAAK,OAAA,CAAQ,OAAO,CAAA,EAAG;AACtD,MAAA,IAAI,CAAC,OAAA,CAAQ,QAAA,CAAS,IAAI,CAAA,EAAG,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,IAChD;AAEA,IAAA,MAAM,QAAA,GAAW,cAAA,CAAe,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AAiB/C,IAAA,UAAA,CAAW,CAAC,EAAE,IAAA,EAAM,WAAW,IAAA,EAAM,UAAA,EAAY,CAAC,CAAA;AAsBlD,IAAA,SAAA,CAAU;AAAA,MACR,GAAA,EAAK,QAAA,CAAS,OAAA,CAAQ,4BAA4B;AAAA,KACnD,CAAA;AAMD,IAAA,eAAA,CAAgB;AAAA,MACd,QAAA,EAAU,uBAAA;AAAA,MACV,aAAa,MAAM,CAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,UAAA;AAAA,KAmCpB,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const app = require('nuxt/app');
|
|
4
|
-
const
|
|
4
|
+
const plugin = require('../../shared/attaform.rIRYSUI1.cjs');
|
|
5
|
+
const serialize = require('../../shared/attaform.CJttVxRj.cjs');
|
|
5
6
|
|
|
6
7
|
var attaform_default = app.defineNuxtPlugin({
|
|
7
8
|
// `enforce: 'pre'` makes the "we run before any component's setup" claim
|
|
@@ -13,7 +14,7 @@ var attaform_default = app.defineNuxtPlugin({
|
|
|
13
14
|
setup(nuxtApp) {
|
|
14
15
|
const isServer = undefined;
|
|
15
16
|
const { defaults } = app.useRuntimeConfig().public.attaform;
|
|
16
|
-
nuxtApp.vueApp.use(
|
|
17
|
+
nuxtApp.vueApp.use(plugin.createAttaform({ override: isServer, defaults }));
|
|
17
18
|
if (isServer) {
|
|
18
19
|
nuxtApp.hook("app:rendered", () => {
|
|
19
20
|
const state = serialize.renderAttaformState(nuxtApp.vueApp);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attaform.cjs","sources":["../../../src/runtime/plugins/attaform.ts"],"sourcesContent":["/**\n * Nuxt plugin: installs the framework-agnostic createAttaform Vue\n * plugin on nuxtApp.vueApp and wires the Nuxt payload mechanism to the\n * registry's SSR serialization helpers. Replaces the old split of\n * register.ts (client-only) + register-stub.ts (server-only).\n *\n * Runs on BOTH server and client — Vue's SSR renderer is a natural no-op\n * for directive lifecycle hooks, so the same plugin works on both sides\n * without a stub.\n */\nimport { defineNuxtPlugin, useRuntimeConfig } from 'nuxt/app'\nimport { createAttaform } from '../core/plugin'\nimport { hydrateAttaformState, renderAttaformState } from '../core/serialize'\nimport type { SerializedAttaformState } from '../core/serialize'\nimport type { AttaformDefaults } from '../types/types-api'\n\nexport default defineNuxtPlugin({\n // `enforce: 'pre'` makes the \"we run before any component's setup\" claim\n // explicit. Combined with `prepend: true` on the addPlugin call in\n // src/nuxt.ts, this guarantees hydration is staged into pendingHydration\n // before any user plugin or page can call `useForm`. Without it, a user\n // plugin running first would observe an empty registry and skip hydration.\n enforce: 'pre',\n setup(nuxtApp) {\n const isServer = import.meta.server\n\n // Read app-level defaults from the Nuxt module's runtime-config slot\n // (populated in src/nuxt.ts). The module ships in the same package\n // as this plugin, so the slot is always present and well-typed.\n const { defaults } = (useRuntimeConfig().public as { attaform: { defaults: AttaformDefaults } })\n .attaform\n\n nuxtApp.vueApp.use(createAttaform({ override: isServer, defaults }))\n\n if (isServer) {\n // After the app renders, capture every FormStore into the Nuxt payload\n // so the client can hydrate with matching form values and errors.\n nuxtApp.hook('app:rendered', () => {\n const state = renderAttaformState(nuxtApp.vueApp)\n ;(nuxtApp.payload as unknown as { attaform?: SerializedAttaformState }).attaform = state\n })\n } else {\n // Stage the payload into pendingHydration so `useForm` finds it. The\n // `enforce: 'pre'` + `prepend: true` pair above is what makes it safe\n // to assume this runs before any user setup.\n const serialized = (nuxtApp.payload as unknown as { attaform?: SerializedAttaformState })\n .attaform\n if (serialized !== undefined) {\n hydrateAttaformState(nuxtApp.vueApp, serialized)\n }\n }\n },\n})\n"],"names":["defineNuxtPlugin","useRuntimeConfig","createAttaform","renderAttaformState","hydrateAttaformState"],"mappings":"
|
|
1
|
+
{"version":3,"file":"attaform.cjs","sources":["../../../src/runtime/plugins/attaform.ts"],"sourcesContent":["/**\n * Nuxt plugin: installs the framework-agnostic createAttaform Vue\n * plugin on nuxtApp.vueApp and wires the Nuxt payload mechanism to the\n * registry's SSR serialization helpers. Replaces the old split of\n * register.ts (client-only) + register-stub.ts (server-only).\n *\n * Runs on BOTH server and client — Vue's SSR renderer is a natural no-op\n * for directive lifecycle hooks, so the same plugin works on both sides\n * without a stub.\n */\nimport { defineNuxtPlugin, useRuntimeConfig } from 'nuxt/app'\nimport { createAttaform } from '../core/plugin'\nimport { hydrateAttaformState, renderAttaformState } from '../core/serialize'\nimport type { SerializedAttaformState } from '../core/serialize'\nimport type { AttaformDefaults } from '../types/types-api'\n\nexport default defineNuxtPlugin({\n // `enforce: 'pre'` makes the \"we run before any component's setup\" claim\n // explicit. Combined with `prepend: true` on the addPlugin call in\n // src/nuxt.ts, this guarantees hydration is staged into pendingHydration\n // before any user plugin or page can call `useForm`. Without it, a user\n // plugin running first would observe an empty registry and skip hydration.\n enforce: 'pre',\n setup(nuxtApp) {\n const isServer = import.meta.server\n\n // Read app-level defaults from the Nuxt module's runtime-config slot\n // (populated in src/nuxt.ts). The module ships in the same package\n // as this plugin, so the slot is always present and well-typed.\n const { defaults } = (useRuntimeConfig().public as { attaform: { defaults: AttaformDefaults } })\n .attaform\n\n nuxtApp.vueApp.use(createAttaform({ override: isServer, defaults }))\n\n if (isServer) {\n // After the app renders, capture every FormStore into the Nuxt payload\n // so the client can hydrate with matching form values and errors.\n nuxtApp.hook('app:rendered', () => {\n const state = renderAttaformState(nuxtApp.vueApp)\n ;(nuxtApp.payload as unknown as { attaform?: SerializedAttaformState }).attaform = state\n })\n } else {\n // Stage the payload into pendingHydration so `useForm` finds it. The\n // `enforce: 'pre'` + `prepend: true` pair above is what makes it safe\n // to assume this runs before any user setup.\n const serialized = (nuxtApp.payload as unknown as { attaform?: SerializedAttaformState })\n .attaform\n if (serialized !== undefined) {\n hydrateAttaformState(nuxtApp.vueApp, serialized)\n }\n }\n },\n})\n"],"names":["defineNuxtPlugin","useRuntimeConfig","createAttaform","renderAttaformState","hydrateAttaformState"],"mappings":";;;;;;AAgBA,IAAO,mBAAQA,oBAAA,CAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM9B,OAAA,EAAS,KAAA;AAAA,EACT,MAAM,OAAA,EAAS;AACb,IAAA,MAAM,WAAW,SAAY;AAK7B,IAAA,MAAM,EAAE,QAAA,EAAS,GAAKC,oBAAA,GAAmB,MAAA,CACtC,QAAA;AAEH,IAAA,OAAA,CAAQ,MAAA,CAAO,IAAIC,qBAAA,CAAe,EAAE,UAAU,QAAA,EAAU,QAAA,EAAU,CAAC,CAAA;AAEnE,IAAA,IAAI,QAAA,EAAU;AAGZ,MAAA,OAAA,CAAQ,IAAA,CAAK,gBAAgB,MAAM;AACjC,QAAA,MAAM,KAAA,GAAQC,6BAAA,CAAoB,OAAA,CAAQ,MAAM,CAAA;AAC/C,QAAC,OAAA,CAAQ,QAA8D,QAAA,GAAW,KAAA;AAAA,MACrF,CAAC,CAAA;AAAA,IACH,CAAA,MAAO;AAIL,MAAA,MAAM,UAAA,GAAc,QAAQ,OAAA,CACzB,QAAA;AACH,MAAA,IAAI,eAAe,MAAA,EAAW;AAC5B,QAAAC,8BAAA,CAAqB,OAAA,CAAQ,QAAQ,UAAU,CAAA;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;;"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineNuxtPlugin, useRuntimeConfig } from 'nuxt/app';
|
|
2
|
-
import { c as createAttaform
|
|
2
|
+
import { c as createAttaform } from '../../shared/attaform.BfMxsfmE.mjs';
|
|
3
|
+
import { r as renderAttaformState, h as hydrateAttaformState } from '../../shared/attaform.CINUMjPq.mjs';
|
|
3
4
|
|
|
4
5
|
var attaform_default = defineNuxtPlugin({
|
|
5
6
|
// `enforce: 'pre'` makes the "we run before any component's setup" claim
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attaform.mjs","sources":["../../../src/runtime/plugins/attaform.ts"],"sourcesContent":["/**\n * Nuxt plugin: installs the framework-agnostic createAttaform Vue\n * plugin on nuxtApp.vueApp and wires the Nuxt payload mechanism to the\n * registry's SSR serialization helpers. Replaces the old split of\n * register.ts (client-only) + register-stub.ts (server-only).\n *\n * Runs on BOTH server and client — Vue's SSR renderer is a natural no-op\n * for directive lifecycle hooks, so the same plugin works on both sides\n * without a stub.\n */\nimport { defineNuxtPlugin, useRuntimeConfig } from 'nuxt/app'\nimport { createAttaform } from '../core/plugin'\nimport { hydrateAttaformState, renderAttaformState } from '../core/serialize'\nimport type { SerializedAttaformState } from '../core/serialize'\nimport type { AttaformDefaults } from '../types/types-api'\n\nexport default defineNuxtPlugin({\n // `enforce: 'pre'` makes the \"we run before any component's setup\" claim\n // explicit. Combined with `prepend: true` on the addPlugin call in\n // src/nuxt.ts, this guarantees hydration is staged into pendingHydration\n // before any user plugin or page can call `useForm`. Without it, a user\n // plugin running first would observe an empty registry and skip hydration.\n enforce: 'pre',\n setup(nuxtApp) {\n const isServer = import.meta.server\n\n // Read app-level defaults from the Nuxt module's runtime-config slot\n // (populated in src/nuxt.ts). The module ships in the same package\n // as this plugin, so the slot is always present and well-typed.\n const { defaults } = (useRuntimeConfig().public as { attaform: { defaults: AttaformDefaults } })\n .attaform\n\n nuxtApp.vueApp.use(createAttaform({ override: isServer, defaults }))\n\n if (isServer) {\n // After the app renders, capture every FormStore into the Nuxt payload\n // so the client can hydrate with matching form values and errors.\n nuxtApp.hook('app:rendered', () => {\n const state = renderAttaformState(nuxtApp.vueApp)\n ;(nuxtApp.payload as unknown as { attaform?: SerializedAttaformState }).attaform = state\n })\n } else {\n // Stage the payload into pendingHydration so `useForm` finds it. The\n // `enforce: 'pre'` + `prepend: true` pair above is what makes it safe\n // to assume this runs before any user setup.\n const serialized = (nuxtApp.payload as unknown as { attaform?: SerializedAttaformState })\n .attaform\n if (serialized !== undefined) {\n hydrateAttaformState(nuxtApp.vueApp, serialized)\n }\n }\n },\n})\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"attaform.mjs","sources":["../../../src/runtime/plugins/attaform.ts"],"sourcesContent":["/**\n * Nuxt plugin: installs the framework-agnostic createAttaform Vue\n * plugin on nuxtApp.vueApp and wires the Nuxt payload mechanism to the\n * registry's SSR serialization helpers. Replaces the old split of\n * register.ts (client-only) + register-stub.ts (server-only).\n *\n * Runs on BOTH server and client — Vue's SSR renderer is a natural no-op\n * for directive lifecycle hooks, so the same plugin works on both sides\n * without a stub.\n */\nimport { defineNuxtPlugin, useRuntimeConfig } from 'nuxt/app'\nimport { createAttaform } from '../core/plugin'\nimport { hydrateAttaformState, renderAttaformState } from '../core/serialize'\nimport type { SerializedAttaformState } from '../core/serialize'\nimport type { AttaformDefaults } from '../types/types-api'\n\nexport default defineNuxtPlugin({\n // `enforce: 'pre'` makes the \"we run before any component's setup\" claim\n // explicit. Combined with `prepend: true` on the addPlugin call in\n // src/nuxt.ts, this guarantees hydration is staged into pendingHydration\n // before any user plugin or page can call `useForm`. Without it, a user\n // plugin running first would observe an empty registry and skip hydration.\n enforce: 'pre',\n setup(nuxtApp) {\n const isServer = import.meta.server\n\n // Read app-level defaults from the Nuxt module's runtime-config slot\n // (populated in src/nuxt.ts). The module ships in the same package\n // as this plugin, so the slot is always present and well-typed.\n const { defaults } = (useRuntimeConfig().public as { attaform: { defaults: AttaformDefaults } })\n .attaform\n\n nuxtApp.vueApp.use(createAttaform({ override: isServer, defaults }))\n\n if (isServer) {\n // After the app renders, capture every FormStore into the Nuxt payload\n // so the client can hydrate with matching form values and errors.\n nuxtApp.hook('app:rendered', () => {\n const state = renderAttaformState(nuxtApp.vueApp)\n ;(nuxtApp.payload as unknown as { attaform?: SerializedAttaformState }).attaform = state\n })\n } else {\n // Stage the payload into pendingHydration so `useForm` finds it. The\n // `enforce: 'pre'` + `prepend: true` pair above is what makes it safe\n // to assume this runs before any user setup.\n const serialized = (nuxtApp.payload as unknown as { attaform?: SerializedAttaformState })\n .attaform\n if (serialized !== undefined) {\n hydrateAttaformState(nuxtApp.vueApp, serialized)\n }\n }\n },\n})\n"],"names":[],"mappings":";;;;AAgBA,IAAO,mBAAQ,gBAAA,CAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM9B,OAAA,EAAS,KAAA;AAAA,EACT,MAAM,OAAA,EAAS;AACb,IAAA,MAAM,WAAW,MAAA,CAAA,IAAA,CAAY,MAAA;AAK7B,IAAA,MAAM,EAAE,QAAA,EAAS,GAAK,gBAAA,GAAmB,MAAA,CACtC,QAAA;AAEH,IAAA,OAAA,CAAQ,MAAA,CAAO,IAAI,cAAA,CAAe,EAAE,UAAU,QAAA,EAAU,QAAA,EAAU,CAAC,CAAA;AAEnE,IAAA,IAAI,QAAA,EAAU;AAGZ,MAAA,OAAA,CAAQ,IAAA,CAAK,gBAAgB,MAAM;AACjC,QAAA,MAAM,KAAA,GAAQ,mBAAA,CAAoB,OAAA,CAAQ,MAAM,CAAA;AAC/C,QAAC,OAAA,CAAQ,QAA8D,QAAA,GAAW,KAAA;AAAA,MACrF,CAAC,CAAA;AAAA,IACH,CAAA,MAAO;AAIL,MAAA,MAAM,UAAA,GAAc,QAAQ,OAAA,CACzB,QAAA;AACH,MAAA,IAAI,eAAe,MAAA,EAAW;AAC5B,QAAA,oBAAA,CAAqB,OAAA,CAAQ,QAAQ,UAAU,CAAA;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;;"}
|
|
@@ -24,6 +24,28 @@ declare class AttaformError extends Error {
|
|
|
24
24
|
*/
|
|
25
25
|
declare class InvalidPathError extends AttaformError {
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Thrown when `useForm` receives an invalid configuration — most often
|
|
29
|
+
* a schema passed directly as the first argument, or no argument at
|
|
30
|
+
* all. The configuration is an options bag; the schema is one of
|
|
31
|
+
* several fields, even when it's the only one in use.
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* // ✗ Crashes deep inside the validator with an opaque message:
|
|
35
|
+
* const form = useForm(z.object({ ... }))
|
|
36
|
+
* // ✗ Same:
|
|
37
|
+
* const form = useForm()
|
|
38
|
+
* // ✓ Pass the schema as the `schema` field:
|
|
39
|
+
* const form = useForm({ schema: z.object({ ... }) })
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* The same shape applies to every entry point: `attaform/zod`,
|
|
43
|
+
* `attaform/zod-v3`, `attaform/zod-v4`, and the schema-agnostic
|
|
44
|
+
* `attaform` root.
|
|
45
|
+
*/
|
|
46
|
+
declare class InvalidUseFormConfigError extends AttaformError {
|
|
47
|
+
constructor();
|
|
48
|
+
}
|
|
27
49
|
/**
|
|
28
50
|
* Thrown when a `handleSubmit`-supplied `onError` callback itself
|
|
29
51
|
* throws or rejects. Wraps the inner failure so both the original
|
|
@@ -32,11 +54,18 @@ declare class InvalidPathError extends AttaformError {
|
|
|
32
54
|
declare class SubmitErrorHandlerError extends AttaformError {
|
|
33
55
|
}
|
|
34
56
|
/**
|
|
35
|
-
* Thrown
|
|
36
|
-
*
|
|
57
|
+
* Thrown when an `attaform` API needs the registry attached to a Vue
|
|
58
|
+
* app but it isn't there yet. Component-level entry points (`useForm`,
|
|
59
|
+
* `injectForm`, `useRegister`) lazy-install the registry on first use,
|
|
60
|
+
* so this error is mostly reached by SSR helpers — `renderAttaformState`
|
|
61
|
+
* and `hydrateAttaformState` — which run outside a setup context and
|
|
62
|
+
* have no current instance to install against.
|
|
37
63
|
*
|
|
38
|
-
* Fix: add `app.use(createAttaform())`
|
|
39
|
-
*
|
|
64
|
+
* Fix: add `app.use(createAttaform())` (or `app.use(createAttaform({
|
|
65
|
+
* ssr: true }))` on the server) to your SSR entry, before
|
|
66
|
+
* `renderToString` / hydration. Under Nuxt, `attaform/nuxt` already
|
|
67
|
+
* does this; the error usually points at a non-Nuxt SSR setup that
|
|
68
|
+
* hasn't installed explicitly.
|
|
40
69
|
*/
|
|
41
70
|
declare class RegistryNotInstalledError extends AttaformError {
|
|
42
71
|
constructor();
|
|
@@ -123,4 +152,4 @@ declare class AnonPersistError extends AttaformError {
|
|
|
123
152
|
});
|
|
124
153
|
}
|
|
125
154
|
|
|
126
|
-
export { AnonPersistError as A, InvalidPathError as I, OutsideSetupError as O, RegistryNotInstalledError as R, SensitivePersistFieldError as S, AttaformError as a,
|
|
155
|
+
export { AnonPersistError as A, InvalidPathError as I, OutsideSetupError as O, RegistryNotInstalledError as R, SensitivePersistFieldError as S, AttaformError as a, InvalidUseFormConfigError as b, ReservedFormKeyError as c, SubmitErrorHandlerError as d };
|
|
@@ -24,6 +24,28 @@ declare class AttaformError extends Error {
|
|
|
24
24
|
*/
|
|
25
25
|
declare class InvalidPathError extends AttaformError {
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Thrown when `useForm` receives an invalid configuration — most often
|
|
29
|
+
* a schema passed directly as the first argument, or no argument at
|
|
30
|
+
* all. The configuration is an options bag; the schema is one of
|
|
31
|
+
* several fields, even when it's the only one in use.
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* // ✗ Crashes deep inside the validator with an opaque message:
|
|
35
|
+
* const form = useForm(z.object({ ... }))
|
|
36
|
+
* // ✗ Same:
|
|
37
|
+
* const form = useForm()
|
|
38
|
+
* // ✓ Pass the schema as the `schema` field:
|
|
39
|
+
* const form = useForm({ schema: z.object({ ... }) })
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* The same shape applies to every entry point: `attaform/zod`,
|
|
43
|
+
* `attaform/zod-v3`, `attaform/zod-v4`, and the schema-agnostic
|
|
44
|
+
* `attaform` root.
|
|
45
|
+
*/
|
|
46
|
+
declare class InvalidUseFormConfigError extends AttaformError {
|
|
47
|
+
constructor();
|
|
48
|
+
}
|
|
27
49
|
/**
|
|
28
50
|
* Thrown when a `handleSubmit`-supplied `onError` callback itself
|
|
29
51
|
* throws or rejects. Wraps the inner failure so both the original
|
|
@@ -32,11 +54,18 @@ declare class InvalidPathError extends AttaformError {
|
|
|
32
54
|
declare class SubmitErrorHandlerError extends AttaformError {
|
|
33
55
|
}
|
|
34
56
|
/**
|
|
35
|
-
* Thrown
|
|
36
|
-
*
|
|
57
|
+
* Thrown when an `attaform` API needs the registry attached to a Vue
|
|
58
|
+
* app but it isn't there yet. Component-level entry points (`useForm`,
|
|
59
|
+
* `injectForm`, `useRegister`) lazy-install the registry on first use,
|
|
60
|
+
* so this error is mostly reached by SSR helpers — `renderAttaformState`
|
|
61
|
+
* and `hydrateAttaformState` — which run outside a setup context and
|
|
62
|
+
* have no current instance to install against.
|
|
37
63
|
*
|
|
38
|
-
* Fix: add `app.use(createAttaform())`
|
|
39
|
-
*
|
|
64
|
+
* Fix: add `app.use(createAttaform())` (or `app.use(createAttaform({
|
|
65
|
+
* ssr: true }))` on the server) to your SSR entry, before
|
|
66
|
+
* `renderToString` / hydration. Under Nuxt, `attaform/nuxt` already
|
|
67
|
+
* does this; the error usually points at a non-Nuxt SSR setup that
|
|
68
|
+
* hasn't installed explicitly.
|
|
40
69
|
*/
|
|
41
70
|
declare class RegistryNotInstalledError extends AttaformError {
|
|
42
71
|
constructor();
|
|
@@ -123,4 +152,4 @@ declare class AnonPersistError extends AttaformError {
|
|
|
123
152
|
});
|
|
124
153
|
}
|
|
125
154
|
|
|
126
|
-
export { AnonPersistError as A, InvalidPathError as I, OutsideSetupError as O, RegistryNotInstalledError as R, SensitivePersistFieldError as S, AttaformError as a,
|
|
155
|
+
export { AnonPersistError as A, InvalidPathError as I, OutsideSetupError as O, RegistryNotInstalledError as R, SensitivePersistFieldError as S, AttaformError as a, InvalidUseFormConfigError as b, ReservedFormKeyError as c, SubmitErrorHandlerError as d };
|
|
@@ -24,6 +24,28 @@ declare class AttaformError extends Error {
|
|
|
24
24
|
*/
|
|
25
25
|
declare class InvalidPathError extends AttaformError {
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Thrown when `useForm` receives an invalid configuration — most often
|
|
29
|
+
* a schema passed directly as the first argument, or no argument at
|
|
30
|
+
* all. The configuration is an options bag; the schema is one of
|
|
31
|
+
* several fields, even when it's the only one in use.
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* // ✗ Crashes deep inside the validator with an opaque message:
|
|
35
|
+
* const form = useForm(z.object({ ... }))
|
|
36
|
+
* // ✗ Same:
|
|
37
|
+
* const form = useForm()
|
|
38
|
+
* // ✓ Pass the schema as the `schema` field:
|
|
39
|
+
* const form = useForm({ schema: z.object({ ... }) })
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* The same shape applies to every entry point: `attaform/zod`,
|
|
43
|
+
* `attaform/zod-v3`, `attaform/zod-v4`, and the schema-agnostic
|
|
44
|
+
* `attaform` root.
|
|
45
|
+
*/
|
|
46
|
+
declare class InvalidUseFormConfigError extends AttaformError {
|
|
47
|
+
constructor();
|
|
48
|
+
}
|
|
27
49
|
/**
|
|
28
50
|
* Thrown when a `handleSubmit`-supplied `onError` callback itself
|
|
29
51
|
* throws or rejects. Wraps the inner failure so both the original
|
|
@@ -32,11 +54,18 @@ declare class InvalidPathError extends AttaformError {
|
|
|
32
54
|
declare class SubmitErrorHandlerError extends AttaformError {
|
|
33
55
|
}
|
|
34
56
|
/**
|
|
35
|
-
* Thrown
|
|
36
|
-
*
|
|
57
|
+
* Thrown when an `attaform` API needs the registry attached to a Vue
|
|
58
|
+
* app but it isn't there yet. Component-level entry points (`useForm`,
|
|
59
|
+
* `injectForm`, `useRegister`) lazy-install the registry on first use,
|
|
60
|
+
* so this error is mostly reached by SSR helpers — `renderAttaformState`
|
|
61
|
+
* and `hydrateAttaformState` — which run outside a setup context and
|
|
62
|
+
* have no current instance to install against.
|
|
37
63
|
*
|
|
38
|
-
* Fix: add `app.use(createAttaform())`
|
|
39
|
-
*
|
|
64
|
+
* Fix: add `app.use(createAttaform())` (or `app.use(createAttaform({
|
|
65
|
+
* ssr: true }))` on the server) to your SSR entry, before
|
|
66
|
+
* `renderToString` / hydration. Under Nuxt, `attaform/nuxt` already
|
|
67
|
+
* does this; the error usually points at a non-Nuxt SSR setup that
|
|
68
|
+
* hasn't installed explicitly.
|
|
40
69
|
*/
|
|
41
70
|
declare class RegistryNotInstalledError extends AttaformError {
|
|
42
71
|
constructor();
|
|
@@ -123,4 +152,4 @@ declare class AnonPersistError extends AttaformError {
|
|
|
123
152
|
});
|
|
124
153
|
}
|
|
125
154
|
|
|
126
|
-
export { AnonPersistError as A, InvalidPathError as I, OutsideSetupError as O, RegistryNotInstalledError as R, SensitivePersistFieldError as S, AttaformError as a,
|
|
155
|
+
export { AnonPersistError as A, InvalidPathError as I, OutsideSetupError as O, RegistryNotInstalledError as R, SensitivePersistFieldError as S, AttaformError as a, InvalidUseFormConfigError as b, ReservedFormKeyError as c, SubmitErrorHandlerError as d };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { n as FieldMetaPayload } from './attaform.0Gxd_OOx.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Field-metadata write/read API for the Zod v4 adapter.
|
|
6
|
+
*
|
|
7
|
+
* Backed by Zod 4's native `z.registry<T>()` mechanism — the schema
|
|
8
|
+
* carries the metadata directly through `schema.register(fieldMeta,
|
|
9
|
+
* payload)` (returns the schema, chainable) or the `withMeta()`
|
|
10
|
+
* helper (same effect, version-agnostic across the v3 / v4 adapter
|
|
11
|
+
* split).
|
|
12
|
+
*
|
|
13
|
+
* **Registration patterns:** both styles work — register on whatever
|
|
14
|
+
* schema reference you assign into the parent's shape, OR on the
|
|
15
|
+
* inner schema before wrapping. The adapter's resolver tries the
|
|
16
|
+
* walker-returned schema first, then falls back to the peeled
|
|
17
|
+
* inner so either ordering hits:
|
|
18
|
+
*
|
|
19
|
+
* // both equivalent — registry hits at lookup time
|
|
20
|
+
* withMeta(z.string(), { label: 'Email' }).optional()
|
|
21
|
+
* withMeta(z.string().optional(), { label: 'Email' })
|
|
22
|
+
* z.string().optional().register(fieldMeta, { label: 'Email' })
|
|
23
|
+
* z.string().register(fieldMeta, { label: 'Email' }).optional()
|
|
24
|
+
*
|
|
25
|
+
* The path walker returns the wrapper at terminal positions
|
|
26
|
+
* (`['email']` against `{ email: z.string().optional() }` resolves
|
|
27
|
+
* to `ZodOptional<ZodString>`) and peels at intermediate descent
|
|
28
|
+
* (`['address', 'street']` peels through `address`'s wrapper to
|
|
29
|
+
* reach the inner object). The two-stage lookup covers both leaf
|
|
30
|
+
* and container registrations symmetrically.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The shared registry every Attaform-aware Zod 4 schema can register
|
|
35
|
+
* field metadata against. One module-scoped instance per consumer
|
|
36
|
+
* project — re-exported from `attaform/zod` so user code reads the
|
|
37
|
+
* same registry the runtime does.
|
|
38
|
+
*
|
|
39
|
+
* Consumers extending `FieldMetaPayload` via declaration merging
|
|
40
|
+
* automatically get the richer payload type at every `register` /
|
|
41
|
+
* `add` / `get` call site.
|
|
42
|
+
*
|
|
43
|
+
* **Shared-instance disambiguation.** A single schema instance reused
|
|
44
|
+
* at multiple form paths (e.g. one address schema bound to both
|
|
45
|
+
* `pickup` and `delivery`) can carry distinct metadata per path —
|
|
46
|
+
* even via the canonical `schema.register(fieldMeta, payload)` chain.
|
|
47
|
+
* Internally we maintain a parallel WeakMap of payload LISTS indexed
|
|
48
|
+
* per schema reference, and the path-resolver walks the form's
|
|
49
|
+
* schema tree counting per-schema occurrences to pick the right
|
|
50
|
+
* payload for each path. Object literals evaluate left-to-right, so
|
|
51
|
+
* registration order matches tree-walk order, and shared schemas
|
|
52
|
+
* pair their two registrations to the two paths correctly:
|
|
53
|
+
*
|
|
54
|
+
* z.object({
|
|
55
|
+
* pickup: addressSchema.register(fieldMeta, { label: 'Pickup address' }),
|
|
56
|
+
* delivery: addressSchema.register(fieldMeta, { label: 'Delivery address' }),
|
|
57
|
+
* })
|
|
58
|
+
* // form.fields('pickup').label → 'Pickup address'
|
|
59
|
+
* // form.fields('delivery').label → 'Delivery address'
|
|
60
|
+
*
|
|
61
|
+
* Schemas reused via `withMeta()` get a fresh clone per call (see
|
|
62
|
+
* `withMeta` below), so they never share a registry slot in the
|
|
63
|
+
* first place.
|
|
64
|
+
*/
|
|
65
|
+
declare const fieldMeta: z.core.$ZodRegistry<FieldMetaPayload, z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
|
|
66
|
+
/**
|
|
67
|
+
* Attach `payload` to `schema` in the shared `fieldMeta` registry
|
|
68
|
+
* and return `schema` (chainable). Cross-version with `attaform/zod-v3`'s
|
|
69
|
+
* `withMeta()`; user code that uses this helper reads the same on
|
|
70
|
+
* either adapter.
|
|
71
|
+
*
|
|
72
|
+
* Equivalent to `schema.register(fieldMeta, payload)` on Zod 4.
|
|
73
|
+
* Prefer the native chain for v4-only code; reach for `withMeta`
|
|
74
|
+
* when authoring schema modules that may need to compile under both
|
|
75
|
+
* adapters.
|
|
76
|
+
*
|
|
77
|
+
* Registers on the schema reference passed in. See the
|
|
78
|
+
* "Registration rule" note in this file's header — register on the
|
|
79
|
+
* inner schema before wrapping with `.optional()` / `.nullable()` /
|
|
80
|
+
* `.default()` / etc.
|
|
81
|
+
*/
|
|
82
|
+
declare function withMeta<S extends z.ZodType>(schema: S, payload: FieldMetaPayload): S;
|
|
83
|
+
|
|
84
|
+
export { fieldMeta as f, withMeta as w };
|