attaform 0.22.0 → 0.24.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 (114) hide show
  1. package/README.md +8 -11
  2. package/dist/chunks/dev-key-collision-warnings.cjs +0 -33
  3. package/dist/chunks/dev-key-collision-warnings.cjs.map +1 -1
  4. package/dist/chunks/dev-key-collision-warnings.mjs +1 -33
  5. package/dist/chunks/dev-key-collision-warnings.mjs.map +1 -1
  6. package/dist/chunks/devtools.cjs +3 -5
  7. package/dist/chunks/devtools.cjs.map +1 -1
  8. package/dist/chunks/devtools.mjs +3 -5
  9. package/dist/chunks/devtools.mjs.map +1 -1
  10. package/dist/chunks/fingerprint2.cjs +1 -1
  11. package/dist/chunks/fingerprint2.mjs +1 -1
  12. package/dist/index.cjs +3 -151
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +7 -168
  15. package/dist/index.d.mts +7 -168
  16. package/dist/index.d.ts +7 -168
  17. package/dist/index.mjs +4 -150
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/nuxt.d.cts +1 -1
  20. package/dist/nuxt.d.mts +1 -1
  21. package/dist/nuxt.d.ts +1 -1
  22. package/dist/runtime/components/AttaformDevtoolsPanel.vue +5 -13
  23. package/dist/runtime/plugins/attaform.cjs +2 -2
  24. package/dist/runtime/plugins/attaform.mjs +2 -2
  25. package/dist/shared/{attaform.DgCfLqay.mjs → attaform.BJ_W7q3U.mjs} +8 -6
  26. package/dist/shared/attaform.BJ_W7q3U.mjs.map +1 -0
  27. package/dist/shared/{attaform.aekT7mMx.d.cts → attaform.BNmkKz0q.d.mts} +38 -6
  28. package/dist/shared/{attaform.Q3eAD2wD.cjs → attaform.BV_HyaMO.cjs} +6 -4
  29. package/dist/shared/attaform.BV_HyaMO.cjs.map +1 -0
  30. package/dist/shared/{attaform.AyujQoHp.cjs → attaform.BnUXV01g.cjs} +4 -4
  31. package/dist/shared/attaform.BnUXV01g.cjs.map +1 -0
  32. package/dist/shared/{attaform.DNuiFCXG.mjs → attaform.C-dAB90u.mjs} +4 -4
  33. package/dist/shared/attaform.C-dAB90u.mjs.map +1 -0
  34. package/dist/shared/{attaform.CjMcwV7W.cjs → attaform.C42wL7EJ.cjs} +272 -776
  35. package/dist/shared/attaform.C42wL7EJ.cjs.map +1 -0
  36. package/dist/shared/{attaform.D4XYaasQ.d.ts → attaform.C6eE50re.d.ts} +27 -87
  37. package/dist/shared/{attaform.6xE0Lcfd.mjs → attaform.CAWKNCzc.mjs} +2 -2
  38. package/dist/shared/{attaform.6xE0Lcfd.mjs.map → attaform.CAWKNCzc.mjs.map} +1 -1
  39. package/dist/shared/{attaform.DkA5J8NW.d.cts → attaform.CO0e7YVY.d.cts} +1 -46
  40. package/dist/shared/{attaform.DkA5J8NW.d.ts → attaform.CO0e7YVY.d.mts} +1 -46
  41. package/dist/shared/{attaform.DkA5J8NW.d.mts → attaform.CO0e7YVY.d.ts} +1 -46
  42. package/dist/shared/{attaform.CsB-iKbU.mjs → attaform.CuBdtfbe.mjs} +274 -767
  43. package/dist/shared/attaform.CuBdtfbe.mjs.map +1 -0
  44. package/dist/shared/{attaform.FN0vaQAg.d.mts → attaform.CwFZGv5-.d.ts} +38 -6
  45. package/dist/shared/{attaform.BGwNZ9GV.d.cts → attaform.DdUYEhkV.d.cts} +27 -87
  46. package/dist/shared/attaform.DdjDqTah.d.cts +56 -0
  47. package/dist/shared/attaform.DdjDqTah.d.mts +56 -0
  48. package/dist/shared/attaform.DdjDqTah.d.ts +56 -0
  49. package/dist/shared/{attaform.BKFwekY2.mjs → attaform.Df-s8j1X.mjs} +3 -289
  50. package/dist/shared/attaform.Df-s8j1X.mjs.map +1 -0
  51. package/dist/shared/{attaform.CCCeEPwa.d.mts → attaform.DiWNbKWa.d.mts} +27 -87
  52. package/dist/shared/{attaform.01iKS_lz.cjs → attaform.DwkU0oY9.cjs} +2 -298
  53. package/dist/shared/attaform.DwkU0oY9.cjs.map +1 -0
  54. package/dist/shared/{attaform.DvUH4a3o.d.ts → attaform.GJbSmwLB.d.cts} +224 -824
  55. package/dist/shared/{attaform.DvUH4a3o.d.cts → attaform.GJbSmwLB.d.mts} +224 -824
  56. package/dist/shared/{attaform.DvUH4a3o.d.mts → attaform.GJbSmwLB.d.ts} +224 -824
  57. package/dist/shared/{attaform.DUMWQefY.d.ts → attaform.K-3glmiT.d.cts} +38 -6
  58. package/dist/shared/{attaform.C-RtnCJM.cjs → attaform.Z1qTwOYE.cjs} +8 -6
  59. package/dist/shared/attaform.Z1qTwOYE.cjs.map +1 -0
  60. package/dist/shared/{attaform.CRzpFCjV.cjs → attaform.nycEksJn.cjs} +2 -2
  61. package/dist/shared/{attaform.CRzpFCjV.cjs.map → attaform.nycEksJn.cjs.map} +1 -1
  62. package/dist/shared/{attaform.DCjgGir_.mjs → attaform.o95Kjd3U.mjs} +6 -4
  63. package/dist/shared/attaform.o95Kjd3U.mjs.map +1 -0
  64. package/dist/zod-v3.cjs +2 -2
  65. package/dist/zod-v3.d.cts +12 -11
  66. package/dist/zod-v3.d.mts +12 -11
  67. package/dist/zod-v3.d.ts +12 -11
  68. package/dist/zod-v3.mjs +2 -2
  69. package/dist/zod-v4.cjs +2 -2
  70. package/dist/zod-v4.d.cts +7 -6
  71. package/dist/zod-v4.d.mts +7 -6
  72. package/dist/zod-v4.d.ts +7 -6
  73. package/dist/zod-v4.mjs +2 -2
  74. package/dist/zod.cjs +5 -5
  75. package/dist/zod.cjs.map +1 -1
  76. package/dist/zod.d.cts +21 -52
  77. package/dist/zod.d.mts +21 -52
  78. package/dist/zod.d.ts +21 -52
  79. package/dist/zod.mjs +5 -5
  80. package/dist/zod.mjs.map +1 -1
  81. package/package.json +1 -1
  82. package/dist/chunks/indexeddb.cjs +0 -119
  83. package/dist/chunks/indexeddb.cjs.map +0 -1
  84. package/dist/chunks/indexeddb.mjs +0 -117
  85. package/dist/chunks/indexeddb.mjs.map +0 -1
  86. package/dist/chunks/local-storage.cjs +0 -58
  87. package/dist/chunks/local-storage.cjs.map +0 -1
  88. package/dist/chunks/local-storage.mjs +0 -56
  89. package/dist/chunks/local-storage.mjs.map +0 -1
  90. package/dist/chunks/multi-tab-sync.cjs +0 -367
  91. package/dist/chunks/multi-tab-sync.cjs.map +0 -1
  92. package/dist/chunks/multi-tab-sync.mjs +0 -364
  93. package/dist/chunks/multi-tab-sync.mjs.map +0 -1
  94. package/dist/chunks/session-storage.cjs +0 -58
  95. package/dist/chunks/session-storage.cjs.map +0 -1
  96. package/dist/chunks/session-storage.mjs +0 -56
  97. package/dist/chunks/session-storage.mjs.map +0 -1
  98. package/dist/chunks/wire-persistence.cjs +0 -396
  99. package/dist/chunks/wire-persistence.cjs.map +0 -1
  100. package/dist/chunks/wire-persistence.mjs +0 -394
  101. package/dist/chunks/wire-persistence.mjs.map +0 -1
  102. package/dist/shared/attaform.01iKS_lz.cjs.map +0 -1
  103. package/dist/shared/attaform.AyujQoHp.cjs.map +0 -1
  104. package/dist/shared/attaform.BKFwekY2.mjs.map +0 -1
  105. package/dist/shared/attaform.C-RtnCJM.cjs.map +0 -1
  106. package/dist/shared/attaform.CjMcwV7W.cjs.map +0 -1
  107. package/dist/shared/attaform.CsB-iKbU.mjs.map +0 -1
  108. package/dist/shared/attaform.DCjgGir_.mjs.map +0 -1
  109. package/dist/shared/attaform.DNuiFCXG.mjs.map +0 -1
  110. package/dist/shared/attaform.DgCfLqay.mjs.map +0 -1
  111. package/dist/shared/attaform.Q3eAD2wD.cjs.map +0 -1
  112. package/dist/shared/attaform.nf83TIR5.d.cts +0 -35
  113. package/dist/shared/attaform.nf83TIR5.d.mts +0 -35
  114. package/dist/shared/attaform.nf83TIR5.d.ts +0 -35
@@ -1,4 +1,4 @@
1
- import { F as FormKey, a5 as PathKey, p as DisplayCtx, d as GetDisplayState, q as DisplayMachine, a4 as Path, ap as SlimPrimitiveKind, C as CoercionEntry, j as CoercionRegistry, G as GenericForm, V as ValidationError, a as AbstractSchema, ay as WriteMeta, m as DeepPartial, az as WriteShape, aG as TransformAbortHolder, at as ValidateOn, $ as OnChangeSource, Z as OnChangeHandler, _ as OnChangeOptions, aH as PersistOptInRegistry, A as AttaformDefaults, b as UseFormReturnType, c as RegisterValue } from './attaform.DvUH4a3o.mjs';
1
+ import { F as FormKey, W as PathKey, m as DisplayCtx, d as GetDisplayState, n as DisplayMachine, V as Path, aa as SlimPrimitiveKind, C as CoercionEntry, g as CoercionRegistry, G as GenericForm, ag as ValidationError, a as AbstractSchema, ak as WriteMeta, j as DeepPartial, al as WriteShape, as as TransformAbortHolder, ae as ValidateOn, A as AttaformDefaults, b as UseFormReturnType, c as RegisterValue } from './attaform.GJbSmwLB.mjs';
2
2
  import { Ref, ComputedRef, App, InjectionKey } from 'vue';
3
3
 
4
4
  /**
@@ -643,12 +643,12 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
643
643
  * Schema-driven errors. Written ONLY by the schema validation pipeline:
644
644
  * `scheduleFieldValidation`, `handleSubmit`, the construction-time seed,
645
645
  * history restore, and hydration. Cleared by `reset` / `resetField` and by
646
- * a successful submit. `setFieldErrors*` APIs do NOT touch this Map.
646
+ * a successful submit. `setErrors` / `clearErrors` do NOT touch this Map.
647
647
  */
648
648
  readonly schemaErrors: Map<PathKey, ValidationError[]>;
649
649
  /**
650
- * User-injected errors. Written ONLY by the `setFieldErrors*` API surfaces
651
- * (and history / hydration replay). Survives schema revalidation and
650
+ * User-injected errors. Written ONLY by the `setErrors` / `clearErrors`
651
+ * API surface (and history / hydration replay). Survives schema revalidation and
652
652
  * successful submits — the consumer owns its lifetime explicitly.
653
653
  */
654
654
  readonly userErrors: Map<PathKey, ValidationError[]>;
@@ -967,17 +967,13 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
967
967
  /**
968
968
  * Replace the form value wholesale. Optional `meta` is forwarded to
969
969
  * every `onFormChange` listener so they can decide whether THIS write
970
- * is one they care about most importantly, the persistence layer
971
- * only writes when `meta?.persist === true`. Internal callers that
972
- * don't pass meta default to no-persist.
970
+ * is one they care about (e.g. history tagging a hydration replay).
973
971
  */
974
972
  applyFormReplacement(next: F, meta?: WriteMeta): void;
975
973
  /**
976
974
  * Set a single path's value. `meta` is forwarded to listeners via
977
- * `applyFormReplacement` (see above). The directive's input handler
978
- * computes `meta.persist` from the per-element opt-in registry; other
979
- * internal call sites pass `meta.persist = hasAnyOptInForPath(path)`.
980
- * Public `form.setValue` passes no meta.
975
+ * `applyFormReplacement` (see above). Public `form.setValue` passes no
976
+ * meta.
981
977
  *
982
978
  * Returns `false` when the slim-primitive gate rejects the write
983
979
  * (the value's primitive shape doesn't match the schema's slim
@@ -1009,7 +1005,7 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
1009
1005
  */
1010
1006
  applySchemaErrorsForSubtree(path: Path, errors: ValidationError[]): void;
1011
1007
  setAllUserErrors(errors: readonly ValidationError[]): void;
1012
- addUserErrors(errors: readonly ValidationError[]): void;
1008
+ setUserErrorsForPath(path: Path, errors: readonly ValidationError[]): void;
1013
1009
  clearUserErrors(path?: Path): void;
1014
1010
  /**
1015
1011
  * Merged read — returns `[...schemaErrors[path], ...userErrors[path]]`.
@@ -1191,28 +1187,17 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
1191
1187
  /**
1192
1188
  * Subscribe to every `applyFormReplacement`. Fires synchronously
1193
1189
  * after `form.value` has been swapped to `next` and all field /
1194
- * originals bookkeeping has run. Used by persistence + undo/redo
1195
- * to hook the single mutation funnel. The optional `meta` carries
1196
- * the originating call site's intent the persistence subscription
1197
- * filters on `meta?.persist === true`; subscribers that don't care
1198
- * about meta can ignore the parameter. Returns an unsubscribe
1199
- * function.
1190
+ * originals bookkeeping has run. Used by undo/redo to hook the single
1191
+ * mutation funnel. The optional `meta` carries the originating call
1192
+ * site's intent; subscribers that don't care about meta can ignore the
1193
+ * parameter. Returns an unsubscribe function.
1200
1194
  */
1201
1195
  onFormChange(listener: (next: F, meta?: WriteMeta) => void): () => void;
1202
- /**
1203
- * Register a `form.onChange` side-channel handler. `source === undefined`
1204
- * is the whole form (root); `getForm` lazily resolves the public form
1205
- * handle for `ctx.form`. Returns an idempotent `stop()`. A no-op on SSR.
1206
- * The public `form.onChange` overloads and `useForm({ onChange })` wire
1207
- * through here; dispatch happens in `commitWritePatches`.
1208
- */
1209
- registerOnChange(source: OnChangeSource | undefined, handler: OnChangeHandler, options: OnChangeOptions | undefined, getForm: () => unknown): () => void;
1210
1196
  /**
1211
1197
  * Subscribe to successful submissions. Fires after the consumer's
1212
1198
  * `onSubmit` callback has resolved — not on validation failure,
1213
- * not on callback throw. Used by persistence's `clearOnSubmitSuccess`
1214
- * to drop the stored payload once the form is safely through the
1215
- * server round-trip. Returns an unsubscribe function.
1199
+ * not on callback throw. The DevTools panel rides this to surface a
1200
+ * submit event. Returns an unsubscribe function.
1216
1201
  */
1217
1202
  onSubmitSuccess(listener: () => void): () => void;
1218
1203
  /**
@@ -1258,58 +1243,6 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
1258
1243
  * owned by the caller (e.g. `'history'`).
1259
1244
  */
1260
1245
  readonly modules: Map<string, unknown>;
1261
- /**
1262
- * Per-element persistence opt-in tracker. Empty by default; the
1263
- * `v-register` directive populates entries on `mount` for each binding
1264
- * that passed `register('foo', { persist: true })` and clears them on
1265
- * `beforeUnmount`. Two SFCs sharing a key share this registry — opt-ins
1266
- * are per-DOM-element, not per-component. Internal to the persistence
1267
- * subsystem; not part of the consumer API surface.
1268
- */
1269
- readonly persistOptIns: PersistOptInRegistry;
1270
- /**
1271
- * Resolved sensitive-path predicate for THIS form. Honors the
1272
- * cascade (`useForm({ sensitiveNames })` > global default >
1273
- * library `DEFAULT_SENSITIVE_NAMES`). Used by:
1274
- * - the persistence opt-in gate (`allowSensitivePersist`);
1275
- * - the multi-tab sync module (outbound strip + inbound reject);
1276
- * - DevTools edit rejection;
1277
- * - any future surface that needs to flag "this path holds
1278
- * sensitive data."
1279
- *
1280
- * Frozen at FormStore construction. Two callsites sharing a key
1281
- * share the predicate — consistent with the rest of the per-form
1282
- * resolved-config surface.
1283
- */
1284
- readonly isSensitivePath: (path: Path | PathKey | string) => boolean;
1285
- /**
1286
- * Canonical path keys explicitly opted OUT of multi-tab sync by
1287
- * `register(path, { multiTab: false })`. The sync module's outbound
1288
- * broadcaster strips patches at these paths AND the inbound listener
1289
- * rejects them — symmetric tab-local behaviour for selected fields.
1290
- *
1291
- * Read-only Set view; mutate via `incrementNoSyncOptOut` /
1292
- * `decrementNoSyncOptOut` which maintain a per-path ref count so
1293
- * multiple bindings on the same path balance correctly across
1294
- * dynamic conditional renders. Empty by default.
1295
- */
1296
- readonly noSyncPaths: ReadonlySet<PathKey>;
1297
- /**
1298
- * Ref-counted "this path is tab-local" registration. Called by
1299
- * `v-register`'s `created` hook for any binding that declared
1300
- * `register('x', { multiTab: false })`. The first call for a given
1301
- * path adds it to `noSyncPaths`; subsequent calls just bump the
1302
- * ref count. Pair with `decrementNoSyncOptOut`.
1303
- */
1304
- incrementNoSyncOptOut(path: PathKey): void;
1305
- /**
1306
- * Symmetric companion to `incrementNoSyncOptOut`. Called by
1307
- * `v-register`'s `beforeUnmount` hook. When the ref count for a
1308
- * path drops to zero, the path is removed from `noSyncPaths` —
1309
- * dynamic toggling (the binding rendered conditionally) restores
1310
- * full sync to the path when the last opt-out unmounts.
1311
- */
1312
- decrementNoSyncOptOut(path: PathKey): void;
1313
1246
  /**
1314
1247
  * Resolved schema-coercion index — the merged config from
1315
1248
  * `createAttaform({ defaults: { coerce } })` ∪ `useForm({ coerce })`,
@@ -1378,9 +1311,8 @@ type SerializedFormData = {
1378
1311
  */
1379
1312
  readonly schemaErrors: ReadonlyArray<readonly [string, unknown]>;
1380
1313
  /**
1381
- * Errors set explicitly via `setFieldErrors` / `addFieldErrors`
1382
- * (typically from a server response parsed via `parseApiErrors`)
1383
- * at snapshot time. Replayed at hydration; persists across
1314
+ * Errors set explicitly via `setErrors` (typically a server
1315
+ * response) at snapshot time. Replayed at hydration; persists across
1384
1316
  * client-side re-validation.
1385
1317
  */
1386
1318
  readonly userErrors: ReadonlyArray<readonly [string, unknown]>;
@@ -1808,9 +1740,9 @@ declare function lazy<Ctx = WizardCtx>(resolve: (ctx: Ctx) => AnyForm | string |
1808
1740
  * `issue.code` (e.g. `zod:too_small`). No enum here because
1809
1741
  * Zod's code list evolves.
1810
1742
  * - consumer-defined — anything the consumer's backend / app stamps
1811
- * onto a `ValidationError` (via the `parseApiErrors` wire payload
1812
- * or `setFieldErrors` directly). Pick a scope (`api:`, `auth:`,
1813
- * etc.) and stay consistent.
1743
+ * onto a `ValidationError` (a server response handed to `setErrors`,
1744
+ * or a code passed inline). Pick a scope (`api:`, `auth:`, etc.) and
1745
+ * stay consistent.
1814
1746
  *
1815
1747
  * Use these constants in tests and error-routing UI:
1816
1748
  *
@@ -1854,6 +1786,14 @@ declare const AttaformErrorCode: {
1854
1786
  * `form.hydrateError` for retry UX.
1855
1787
  */
1856
1788
  readonly ActivationFailed: "atta:activation-failed";
1789
+ /**
1790
+ * Default code stamped on a manual error set through `form.setErrors`
1791
+ * when the caller omits an explicit `code`. The `setErrors` input is
1792
+ * lenient (`code` optional), so this is the fallback that keeps every
1793
+ * produced `ValidationError` carrying a stable, branchable identifier.
1794
+ * Override it per error by passing your own `code` (`api:…`, `auth:…`).
1795
+ */
1796
+ readonly UserError: "atta:user-error";
1857
1797
  };
1858
1798
  type AttaformErrorCode = (typeof AttaformErrorCode)[keyof typeof AttaformErrorCode];
1859
1799
 
@@ -4,9 +4,6 @@ const vue = require('vue');
4
4
 
5
5
  const __DEV__ = (typeof process !== "undefined" ? process.env.NODE_ENV : "production") !== "production";
6
6
 
7
- var __defProp = Object.defineProperty;
8
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
10
7
  class AttaformError extends Error {
11
8
  constructor(message, options) {
12
9
  super(message, options);
@@ -50,24 +47,6 @@ class ReservedFormKeyError extends AttaformError {
50
47
  );
51
48
  }
52
49
  }
53
- class AnonPersistError extends AttaformError {
54
- constructor(opts) {
55
- super(formatAnonPersistMessage(opts));
56
- __publicField(this, "schemaFields");
57
- __publicField(this, "callSite");
58
- __publicField(this, "cause");
59
- this.schemaFields = opts.schemaFields;
60
- this.callSite = opts.callSite;
61
- this.cause = opts.cause;
62
- }
63
- }
64
- function formatAnonPersistMessage(opts) {
65
- const head = opts.cause === "no-key" ? `useForm({ persist: ... }) requires an explicit \`key:\`. Anonymous synthetic keys (\`__atta:anon:*\`) drift across mounts and can collide between unrelated forms \u2014 refusing to persist to a non-deterministic location.` : `register(_, { persist: true }) declared on a form whose useForm() options have no \`persist:\` configured. The opt-in is recorded but nothing would ever land in storage.`;
66
- const fields = opts.schemaFields !== void 0 && opts.schemaFields.length > 0 ? ` Form fields: { ${opts.schemaFields.join(", ")} }.` : "";
67
- const fix = opts.cause === "no-key" ? ` Fix: add \`key: '<stable-id>'\` to useForm().` : ` Fix: add \`persist: 'session'\` (or 'local') and \`key:\` to useForm(), or remove \`{ persist: true }\` from this register() call.`;
68
- const where = opts.callSite !== void 0 ? ` ${opts.callSite}` : "";
69
- return `[attaform] ${head}${fields}${fix}${where}`;
70
- }
71
50
 
72
51
  function detectSSR(options = {}) {
73
52
  if (options.ssr !== void 0) return options.ssr;
@@ -619,21 +598,6 @@ function readFilesFromInput(el) {
619
598
  if (files === null || files.length === 0) return null;
620
599
  return files.item(0);
621
600
  }
622
- const warnedPersistedFileForms = __DEV__ ? /* @__PURE__ */ new WeakMap() : null;
623
- function maybeWarnPersistedFile(value) {
624
- if (!__DEV__ || warnedPersistedFileForms === null) return;
625
- if (value.persist !== true) return;
626
- let warnedPaths = warnedPersistedFileForms.get(value.persistOptIns);
627
- if (warnedPaths === void 0) {
628
- warnedPaths = /* @__PURE__ */ new Set();
629
- warnedPersistedFileForms.set(value.persistOptIns, warnedPaths);
630
- }
631
- if (warnedPaths.has(value.path)) return;
632
- warnedPaths.add(value.path);
633
- vue.warn(
634
- `[attaform] register('${value.path}', { persist: true }) on <input type="file"> \u2014 files can't ride a refresh (browsers block programmatic writes to <input type="file">), so this path won't be saved. For long-lived flows, upload on selection and persist the resulting URL or ID in a sibling string field.`
635
- );
636
- }
637
601
  const fileScopeKey = Symbol.for("attaform:file-scope");
638
602
  const vRegisterFile = {
639
603
  created(el, { value }, vnode) {
@@ -641,7 +605,6 @@ const vRegisterFile = {
641
605
  const input = el;
642
606
  value.registerElement(input);
643
607
  setAssignFunction(input, vnode, value);
644
- maybeWarnPersistedFile(value);
645
608
  const currentRaw = value.innerRef.value;
646
609
  if (isBlankFileValue(currentRaw)) {
647
610
  const blankShape = isMultipleInput(input, vnode) ? [] : null;
@@ -691,250 +654,11 @@ const vRegisterFile = {
691
654
  }
692
655
  };
693
656
 
694
- const idGenerator = /* @__PURE__ */ (() => {
695
- let counter = 0;
696
- return () => `el-${++counter}`;
697
- })();
698
- const elementIds = /* @__PURE__ */ new WeakMap();
699
- function getOrAssignElementId(el) {
700
- let id = elementIds.get(el);
701
- if (id === void 0) {
702
- id = idGenerator();
703
- elementIds.set(el, id);
704
- }
705
- return id;
706
- }
707
- function createPersistOptInRegistry() {
708
- const byPath = /* @__PURE__ */ new Map();
709
- function add(elementId, path) {
710
- const existing = byPath.get(path);
711
- if (existing === void 0) {
712
- byPath.set(path, /* @__PURE__ */ new Set([elementId]));
713
- return;
714
- }
715
- existing.add(elementId);
716
- }
717
- function remove(elementId, path) {
718
- const existing = byPath.get(path);
719
- if (existing === void 0) return;
720
- existing.delete(elementId);
721
- if (existing.size === 0) byPath.delete(path);
722
- }
723
- function removeAllFor(elementId) {
724
- for (const [path, ids] of byPath) {
725
- if (!ids.delete(elementId)) continue;
726
- if (ids.size === 0) byPath.delete(path);
727
- }
728
- }
729
- function hasOptIn(elementId, path) {
730
- return byPath.get(path)?.has(elementId) ?? false;
731
- }
732
- function hasAnyOptInForPath(path) {
733
- const ids = byPath.get(path);
734
- return ids !== void 0 && ids.size > 0;
735
- }
736
- function optedInPaths() {
737
- return byPath.keys();
738
- }
739
- function isEmpty() {
740
- return byPath.size === 0;
741
- }
742
- function clear() {
743
- byPath.clear();
744
- }
745
- return {
746
- add,
747
- remove,
748
- removeAllFor,
749
- hasOptIn,
750
- hasAnyOptInForPath,
751
- optedInPaths,
752
- isEmpty,
753
- clear
754
- };
755
- }
756
-
757
- const DEFAULT_SENSITIVE_NAMES = Object.freeze([
758
- // Passwords + PIN-like
759
- "password",
760
- "passwd",
761
- "pwd",
762
- "pin",
763
- // Card / payment
764
- "cvv",
765
- "cvc",
766
- "card_number",
767
- "card_num",
768
- "card",
769
- "iban",
770
- "routing_number",
771
- "account_number",
772
- // Government / identity
773
- "ssn",
774
- "social_security",
775
- "dob",
776
- "date_of_birth",
777
- "passport",
778
- "driver_license",
779
- // Tax IDs
780
- "tin",
781
- "ein",
782
- "itin",
783
- "tax_id",
784
- // Tokens / secrets / API auth
785
- "token",
786
- "tokens",
787
- "secret",
788
- "secrets",
789
- "api_key",
790
- "api_secret",
791
- "api_token",
792
- "private_key",
793
- "bearer",
794
- "oauth",
795
- "auth_token",
796
- "access_token",
797
- "refresh_token",
798
- "session_id",
799
- "session_key",
800
- "session_token",
801
- // MFA / OTP
802
- "otp",
803
- "one_time_password",
804
- "one_time_code",
805
- "mfa_secret",
806
- "mfa_seed",
807
- "mfa_code",
808
- "mfa_token",
809
- "two_factor_code",
810
- "two_factor_token",
811
- "2fa",
812
- "2fa_code",
813
- "2fa_token",
814
- "recovery_code",
815
- "backup_code"
816
- ]);
817
- const WORD_BOUNDARY_THRESHOLD = 5;
818
- function escapeRegex(s) {
819
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
820
- }
821
- function nameToRegex(name) {
822
- const parts = name.split(/[_\s-]/).filter((p) => p.length > 0);
823
- if (parts.length === 0) {
824
- return /(?!)/;
825
- }
826
- const escaped = parts.map(escapeRegex).join("[_\\s-]?");
827
- const compactLength = parts.reduce((sum, p) => sum + p.length, 0);
828
- const useBoundary = compactLength <= WORD_BOUNDARY_THRESHOLD;
829
- const source = useBoundary ? `\\b${escaped}\\b` : escaped;
830
- return new RegExp(source, "i");
831
- }
832
- function namesToPatterns(names) {
833
- const patterns = [];
834
- for (const name of names) {
835
- if (typeof name !== "string" || name.length === 0) continue;
836
- patterns.push(nameToRegex(name));
837
- }
838
- return patterns;
839
- }
840
- const DEFAULT_PATTERNS = namesToPatterns(DEFAULT_SENSITIVE_NAMES);
841
- function createSegmentMatchesSensitive(names = DEFAULT_SENSITIVE_NAMES) {
842
- const patterns = names === DEFAULT_SENSITIVE_NAMES ? DEFAULT_PATTERNS : namesToPatterns(names);
843
- return (segment) => {
844
- if (typeof segment !== "string") return false;
845
- for (const p of patterns) {
846
- if (p.test(segment)) return true;
847
- }
848
- return false;
849
- };
850
- }
851
- function createIsSensitivePath(names = DEFAULT_SENSITIVE_NAMES) {
852
- const segmentMatches = createSegmentMatchesSensitive(names);
853
- return (path) => {
854
- if (typeof path !== "string") {
855
- for (const segment of path) {
856
- if (segmentMatches(segment)) return true;
857
- }
858
- return false;
859
- }
860
- if (path.startsWith("[")) {
861
- try {
862
- const parsed = JSON.parse(path);
863
- if (Array.isArray(parsed)) {
864
- for (const segment of parsed) {
865
- if (segmentMatches(segment)) return true;
866
- }
867
- return false;
868
- }
869
- } catch {
870
- }
871
- }
872
- for (const segment of path.split(".")) {
873
- if (segmentMatches(segment)) return true;
874
- }
875
- return false;
876
- };
877
- }
878
- const defaultIsSensitivePath = createIsSensitivePath();
879
- function isSensitivePath(path) {
880
- return defaultIsSensitivePath(path);
881
- }
882
- const warnedSensitivePersist = __DEV__ ? /* @__PURE__ */ new Set() : null;
883
- function allowSensitivePersist(path, acknowledged, isSensitive = defaultIsSensitivePath) {
884
- if (acknowledged) return true;
885
- if (!isSensitive(path)) return true;
886
- if (warnedSensitivePersist !== null) {
887
- const display = Array.isArray(path) ? path.join(".") : String(path);
888
- if (!warnedSensitivePersist.has(display)) {
889
- warnedSensitivePersist.add(display);
890
- console.warn(
891
- `[attaform] Not persisting "${display}" \u2014 it matches a sensitive-name pattern (password / cvv / ssn / token / etc.) and was opted into persistence without \`acknowledgeSensitive: true\`. Storing sensitive data in client-side storage is a compliance risk (PII / PCI-DSS / HIPAA / SOC2). Persist it server-side, or pass \`acknowledgeSensitive: true\` to register() / form.persist() if this is intentional.`
892
- );
893
- }
894
- }
895
- return false;
896
- }
897
-
898
- function syncPersistOptIn(el, value, oldValue, vnodeType) {
899
- const wasOptedIn = isRegisterValue(oldValue) && oldValue.persist === true;
900
- const isFileInput = el.tagName === "INPUT" && (vnodeType === "file" || el.type === "file");
901
- const wantsOptIn = !isFileInput && isRegisterValue(value) && value.persist === true;
902
- if (!wasOptedIn && !wantsOptIn) return;
903
- const elementId = getOrAssignElementId(el);
904
- if (wasOptedIn) {
905
- const old = oldValue;
906
- const samePathAndRegistry = wantsOptIn && value.path === old.path && value.persistOptIns === old.persistOptIns;
907
- if (!samePathAndRegistry) {
908
- old.persistOptIns.remove(elementId, old.path);
909
- }
910
- }
911
- if (wantsOptIn) {
912
- const v = value;
913
- if (allowSensitivePersist(v.path, v.acknowledgeSensitive, v.isSensitivePath)) {
914
- v.persistOptIns.add(elementId, v.path);
915
- }
916
- }
917
- }
918
- function syncMultiTabOptOut(value, oldValue) {
919
- const wasOptedOut = isRegisterValue(oldValue) && oldValue.unmarkNoSync !== void 0;
920
- const wantsOptOut = isRegisterValue(value) && value.markNoSync !== void 0;
921
- if (!wasOptedOut && !wantsOptOut) return;
922
- if (wasOptedOut) {
923
- const old = oldValue;
924
- const samePath = wantsOptOut && value.path === old.path;
925
- if (!samePath) old.unmarkNoSync?.();
926
- }
927
- if (wantsOptOut) {
928
- const v = value;
929
- const samePathOld = wasOptedOut && oldValue.path === v.path;
930
- if (!samePathOld) v.markNoSync?.();
931
- }
932
- }
933
657
  function syncElementRegistration(el, value, oldValue) {
934
658
  const wasRegistered = isRegisterValue(oldValue);
935
659
  const isRegistered = isRegisterValue(value);
936
660
  if (!wasRegistered && !isRegistered) return;
937
- const samePathAndStore = wasRegistered && isRegistered && oldValue.path === value.path && oldValue.persistOptIns === value.persistOptIns;
661
+ const samePathAndStore = wasRegistered && isRegistered && oldValue.path === value.path && oldValue.formKey === value.formKey;
938
662
  if (wasRegistered && !samePathAndStore) {
939
663
  oldValue.deregisterElement(el);
940
664
  }
@@ -1455,8 +1179,6 @@ function getCheckboxValue(el, checked) {
1455
1179
  const warnedUnsupportedElements = __DEV__ ? /* @__PURE__ */ new WeakSet() : null;
1456
1180
  const vRegisterDynamic = {
1457
1181
  created(el, binding, vnode) {
1458
- syncPersistOptIn(el, binding.value, void 0, vnode.props?.["type"]);
1459
- syncMultiTabOptOut(binding.value, void 0);
1460
1182
  callModelHook(el, binding, vnode, null, "created");
1461
1183
  if (isRegisterValue(binding.value)) setupAria(el, binding.value, vnode);
1462
1184
  },
@@ -1478,8 +1200,6 @@ const vRegisterDynamic = {
1478
1200
  }
1479
1201
  },
1480
1202
  beforeUpdate(el, binding, vnode, prevVNode) {
1481
- syncPersistOptIn(el, binding.value, binding.oldValue, vnode.props?.["type"]);
1482
- syncMultiTabOptOut(binding.value, binding.oldValue);
1483
1203
  syncElementRegistration(el, binding.value, binding.oldValue);
1484
1204
  callModelHook(el, binding, vnode, prevVNode, "beforeUpdate");
1485
1205
  const ariaEl = el;
@@ -1505,10 +1225,6 @@ const vRegisterDynamic = {
1505
1225
  removeTrackedListeners(el);
1506
1226
  teardownAria(el);
1507
1227
  teardownValueSync(el);
1508
- if (isRegisterValue(value)) {
1509
- value.persistOptIns.removeAllFor(getOrAssignElementId(el));
1510
- value.unmarkNoSync?.();
1511
- }
1512
1228
  if (!isRegisterValue(value)) return;
1513
1229
  value.deregisterElement(el);
1514
1230
  delete el.composing;
@@ -1713,8 +1429,6 @@ function coerceToPathKey(input) {
1713
1429
  }
1714
1430
  const ROOT_PATH = Object.freeze([]);
1715
1431
  const ROOT_PATH_KEY = "[]";
1716
- const FORM_ERRORS_PATH = Object.freeze([""]);
1717
- const FORM_ERRORS_PATH_KEY = '[""]';
1718
1432
  function isPathPrefix(prefix, path) {
1719
1433
  if (path.length < prefix.length) return false;
1720
1434
  for (let i = 0; i < prefix.length; i++) {
@@ -1730,11 +1444,7 @@ function pathsEqual(a, b) {
1730
1444
  return true;
1731
1445
  }
1732
1446
 
1733
- exports.AnonPersistError = AnonPersistError;
1734
1447
  exports.AttaformError = AttaformError;
1735
- exports.DEFAULT_SENSITIVE_NAMES = DEFAULT_SENSITIVE_NAMES;
1736
- exports.FORM_ERRORS_PATH = FORM_ERRORS_PATH;
1737
- exports.FORM_ERRORS_PATH_KEY = FORM_ERRORS_PATH_KEY;
1738
1448
  exports.INTERACTIVE_TAG_NAMES = INTERACTIVE_TAG_NAMES;
1739
1449
  exports.InvalidPathError = InvalidPathError;
1740
1450
  exports.InvalidUseFormConfigError = InvalidUseFormConfigError;
@@ -1747,20 +1457,15 @@ exports.ReservedFormKeyError = ReservedFormKeyError;
1747
1457
  exports.SubmitErrorHandlerError = SubmitErrorHandlerError;
1748
1458
  exports.V_REGISTER_MARKER = V_REGISTER_MARKER;
1749
1459
  exports.__DEV__ = __DEV__;
1750
- exports.allowSensitivePersist = allowSensitivePersist;
1751
1460
  exports.assignKey = assignKey;
1752
1461
  exports.canonicalizePath = canonicalizePath;
1753
1462
  exports.coerceToPathKey = coerceToPathKey;
1754
1463
  exports.createAttaform = createAttaform;
1755
- exports.createIsSensitivePath = createIsSensitivePath;
1756
- exports.createPersistOptInRegistry = createPersistOptInRegistry;
1757
1464
  exports.createRegistry = createRegistry;
1758
1465
  exports.ensureAttaformInstalled = ensureAttaformInstalled;
1759
- exports.getOrAssignElementId = getOrAssignElementId;
1760
1466
  exports.getRegistryFromApp = getRegistryFromApp;
1761
1467
  exports.isPathPrefix = isPathPrefix;
1762
1468
  exports.isRegisterValue = isRegisterValue;
1763
- exports.isSensitivePath = isSensitivePath;
1764
1469
  exports.kAttaformAncestorWizard = kAttaformAncestorWizard;
1765
1470
  exports.kAttaformRegistry = kAttaformRegistry;
1766
1471
  exports.kAttaformWizardActiveStepResolver = kAttaformWizardActiveStepResolver;
@@ -1771,8 +1476,7 @@ exports.parseDottedPath = parseDottedPath;
1771
1476
  exports.pathKeyToDotted = pathKeyToDotted;
1772
1477
  exports.pathsEqual = pathsEqual;
1773
1478
  exports.segmentsForPathKey = segmentsForPathKey;
1774
- exports.segmentsToDotted = segmentsToDotted;
1775
1479
  exports.toError = toError;
1776
1480
  exports.useRegistry = useRegistry;
1777
1481
  exports.vRegister = vRegister;
1778
- //# sourceMappingURL=attaform.01iKS_lz.cjs.map
1482
+ //# sourceMappingURL=attaform.DwkU0oY9.cjs.map