@12-apps/forms-core 1.19.1 → 1.19.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,10 +1,13 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
1
4
  // src/validators.ts
2
5
  var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
3
- var required = (message = "This field is required") => (value) => value.trim().length === 0 ? message : void 0;
4
- var email = (message = "Enter a valid email address") => (value) => EMAIL_PATTERN.test(value) ? void 0 : message;
5
- var minLength = (length, message = `Must be at least ${length} characters`) => (value) => value.length < length ? message : void 0;
6
+ var required = /* @__PURE__ */ __name((message = "This field is required") => (value) => value.trim().length === 0 ? message : void 0, "required");
7
+ var email = /* @__PURE__ */ __name((message = "Enter a valid email address") => (value) => EMAIL_PATTERN.test(value) ? void 0 : message, "email");
8
+ var minLength = /* @__PURE__ */ __name((length, message = `Must be at least ${length} characters`) => (value) => value.length < length ? message : void 0, "minLength");
6
9
  var min = minLength;
7
- var firstFieldError = (validators, value) => {
10
+ var firstFieldError = /* @__PURE__ */ __name((validators, value) => {
8
11
  for (const validate of validators) {
9
12
  const error = validate(value);
10
13
  if (error !== void 0) {
@@ -12,8 +15,8 @@ var firstFieldError = (validators, value) => {
12
15
  }
13
16
  }
14
17
  return void 0;
15
- };
16
- var validateFields = (values, schema) => {
18
+ }, "firstFieldError");
19
+ var validateFields = /* @__PURE__ */ __name((values, schema) => {
17
20
  const errors = {};
18
21
  for (const field of Object.keys(schema)) {
19
22
  const validators = schema[field];
@@ -26,15 +29,18 @@ var validateFields = (values, schema) => {
26
29
  }
27
30
  }
28
31
  return errors;
29
- };
32
+ }, "validateFields");
30
33
 
31
34
  // src/result.ts
32
- var ok = (data) => ({ ok: true, data });
33
- var err = (error, fieldErrors) => fieldErrors ? { ok: false, error, fieldErrors } : { ok: false, error };
35
+ var ok = /* @__PURE__ */ __name((data) => ({ ok: true, data }), "ok");
36
+ var err = /* @__PURE__ */ __name((error, fieldErrors) => fieldErrors ? { ok: false, error, fieldErrors } : { ok: false, error }, "err");
34
37
 
35
38
  // src/serverAction.ts
36
39
  var GENERIC_ERROR = "Something went wrong. Please try again.";
37
40
  var ActionError = class extends Error {
41
+ static {
42
+ __name(this, "ActionError");
43
+ }
38
44
  /**
39
45
  * The form field this failure is attributable to (e.g. `"name"` for a
40
46
  * duplicate-name conflict). When set, {@link createServerAction} surfaces it
@@ -55,7 +61,7 @@ var ActionError = class extends Error {
55
61
  this.fieldErrors = fieldErrors;
56
62
  }
57
63
  };
58
- var createServerAction = (schema, handler) => {
64
+ var createServerAction = /* @__PURE__ */ __name((schema, handler) => {
59
65
  return async (input) => {
60
66
  const errors = validateFields(input, schema);
61
67
  const firstField = Object.keys(errors).find(
@@ -76,7 +82,7 @@ var createServerAction = (schema, handler) => {
76
82
  return err(GENERIC_ERROR);
77
83
  }
78
84
  };
79
- };
85
+ }, "createServerAction");
80
86
 
81
87
  // src/br.ts
82
88
  var UF_LIST = [
@@ -111,23 +117,28 @@ var UF_LIST = [
111
117
  function isUf(value) {
112
118
  return UF_LIST.includes(value);
113
119
  }
120
+ __name(isUf, "isUf");
114
121
  var CEP_PATTERN = /^\d{5}-\d{3}$/;
115
122
  function cepDigits(raw) {
116
123
  return raw.replace(/\D/g, "").slice(0, 8);
117
124
  }
125
+ __name(cepDigits, "cepDigits");
118
126
  function formatCep(raw) {
119
127
  const digits = cepDigits(raw);
120
128
  return digits.length > 5 ? `${digits.slice(0, 5)}-${digits.slice(5)}` : digits;
121
129
  }
130
+ __name(formatCep, "formatCep");
122
131
  function isValidCep(raw) {
123
132
  return CEP_PATTERN.test(formatCep(raw));
124
133
  }
125
- var cep = (message = "CEP inv\xE1lido \u2014 use o formato 00000-000.") => (value) => value.trim() === "" || isValidCep(value) ? void 0 : message;
134
+ __name(isValidCep, "isValidCep");
135
+ var cep = /* @__PURE__ */ __name((message = "CEP inv\xE1lido \u2014 use o formato 00000-000.") => (value) => value.trim() === "" || isValidCep(value) ? void 0 : message, "cep");
126
136
  var CNPJ_PATTERN = /^[0-9A-Z]{2}\.[0-9A-Z]{3}\.[0-9A-Z]{3}\/[0-9A-Z]{4}-\d{2}$/;
127
137
  var CNPJ_LENGTH = 14;
128
138
  function cnpjChars(raw) {
129
139
  return raw.toUpperCase().replace(/[^0-9A-Z]/g, "").slice(0, CNPJ_LENGTH);
130
140
  }
141
+ __name(cnpjChars, "cnpjChars");
131
142
  function formatCnpj(raw) {
132
143
  const chars = cnpjChars(raw);
133
144
  const parts = [
@@ -145,16 +156,19 @@ function formatCnpj(raw) {
145
156
  if (chars.length > 12) masked += `-${parts[4]}`;
146
157
  return masked;
147
158
  }
159
+ __name(formatCnpj, "formatCnpj");
148
160
  var CNPJ_WEIGHTS = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
149
161
  function cnpjValue(char) {
150
162
  return char.charCodeAt(0) - 48;
151
163
  }
164
+ __name(cnpjValue, "cnpjValue");
152
165
  function cnpjCheckDigit(base) {
153
166
  const weights = CNPJ_WEIGHTS.slice(-base.length);
154
167
  const sum = [...base].reduce((acc, char, i) => acc + cnpjValue(char) * weights[i], 0);
155
168
  const remainder = sum % 11;
156
169
  return remainder < 2 ? 0 : 11 - remainder;
157
170
  }
171
+ __name(cnpjCheckDigit, "cnpjCheckDigit");
158
172
  function isValidCnpj(raw) {
159
173
  const chars = cnpjChars(raw);
160
174
  if (chars.length !== CNPJ_LENGTH) return false;
@@ -165,7 +179,8 @@ function isValidCnpj(raw) {
165
179
  if (first !== Number(chars[12])) return false;
166
180
  return cnpjCheckDigit(`${base}${first}`) === Number(chars[13]);
167
181
  }
168
- var cnpj = (message = "CNPJ inv\xE1lido \u2014 confira os d\xEDgitos.") => (value) => value.trim() === "" || isValidCnpj(value) ? void 0 : message;
182
+ __name(isValidCnpj, "isValidCnpj");
183
+ var cnpj = /* @__PURE__ */ __name((message = "CNPJ inv\xE1lido \u2014 confira os d\xEDgitos.") => (value) => value.trim() === "" || isValidCnpj(value) ? void 0 : message, "cnpj");
169
184
  function formatBrPhone(raw) {
170
185
  const trimmed = raw?.trim();
171
186
  if (!trimmed) return null;
@@ -176,6 +191,7 @@ function formatBrPhone(raw) {
176
191
  const split = subscriber.length - 4;
177
192
  return `(${ddd}) ${subscriber.slice(0, split)}-${subscriber.slice(split)}`;
178
193
  }
194
+ __name(formatBrPhone, "formatBrPhone");
179
195
  export {
180
196
  ActionError,
181
197
  CEP_PATTERN,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/validators.ts","../src/result.ts","../src/serverAction.ts","../src/br.ts"],"sourcesContent":["/**\n * Field-level form validators\n *\n * Pure, framework-agnostic validators — NO zod, NO react-hook-form. Each\n * validator is curried and returns a `string` error message for invalid input\n * or `undefined` when the value is valid.\n *\n * @module forms-core/validators\n */\n\n/** A field validator: returns an error message, or `undefined` when valid. */\nexport type Validator = (value: string) => string | undefined;\n\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n/**\n * Requires a non-empty value (after trimming whitespace).\n *\n * @param message - Custom error message for empty input.\n * @returns A validator returning the message for empty input, else `undefined`.\n */\nexport const required =\n (message = 'This field is required'): Validator =>\n (value) =>\n value.trim().length === 0 ? message : undefined;\n\n/**\n * Validates that the value is a well-formed email address.\n *\n * @param message - Custom error message for malformed input.\n * @returns A validator returning the message for invalid input, else `undefined`.\n */\nexport const email =\n (message = 'Enter a valid email address'): Validator =>\n (value) =>\n EMAIL_PATTERN.test(value) ? undefined : message;\n\n/**\n * Validates that the value has at least `length` characters.\n *\n * @param length - The minimum number of characters required.\n * @param message - Custom error message for too-short input.\n * @returns A validator returning the message for short input, else `undefined`.\n */\nexport const minLength =\n (length: number, message = `Must be at least ${length} characters`): Validator =>\n (value) =>\n value.length < length ? message : undefined;\n\n/** Alias of {@link minLength}. */\nexport const min = minLength;\n\n/** A map of field names to the list of validators applied to that field. */\nexport type ValidatorSchema<T> = {\n [K in keyof T]?: Validator[];\n};\n\n/** A map of field names to the first error message produced for that field. */\nexport type FieldErrors<T> = {\n [K in keyof T]?: string;\n};\n\n/**\n * The first error message a field's validators produce, or `undefined` when\n * every validator passes. Short-circuits on the first failure.\n */\nconst firstFieldError = (validators: Validator[], value: string): string | undefined => {\n for (const validate of validators) {\n const error = validate(value);\n if (error !== undefined) {\n return error;\n }\n }\n return undefined;\n};\n\n/**\n * Runs each field's validators against `values`, short-circuiting on the first\n * failing validator per field.\n *\n * @param values - The field values to validate (keyed by field name).\n * @param schema - Validators to apply per field.\n * @returns A record containing one entry per failing field; `{}` when all valid.\n */\nexport const validateFields = <T extends Record<string, string>>(\n values: T,\n schema: ValidatorSchema<T>,\n): FieldErrors<T> => {\n const errors: FieldErrors<T> = {};\n\n for (const field of Object.keys(schema) as (keyof T)[]) {\n const validators = schema[field];\n if (!validators) {\n continue;\n }\n const error = firstFieldError(validators, values[field] ?? '');\n if (error !== undefined) {\n errors[field] = error;\n }\n }\n\n return errors;\n};\n","/**\n * Discriminated-union result type for operations that can fail.\n *\n * Pure and framework-agnostic. The `ok` discriminant narrows the union so\n * consumers can safely read `data` on success or `error` on failure.\n *\n * @typeParam T - The success payload type.\n * @module forms-core/result\n */\nexport type Result<T> =\n | { ok: true; data: T }\n | {\n ok: false;\n error: string;\n /**\n * Per-field error messages, keyed by form field name, when the failure is\n * attributable to specific input(s). Lets a form highlight the exact\n * offending field(s) instead of only showing the summary `error`.\n */\n fieldErrors?: Record<string, string>;\n };\n\n/**\n * Builds a successful {@link Result} wrapping `data`.\n *\n * @typeParam T - The success payload type.\n * @param data - The value to wrap.\n * @returns `{ ok: true, data }`.\n */\nexport const ok = <T>(data: T): Result<T> => ({ ok: true, data });\n\n/**\n * Builds a failed {@link Result} wrapping an error `message`.\n *\n * @param error - A user-safe error message (never an internal/stack detail).\n * @param fieldErrors - Optional per-field messages so a form can highlight the\n * exact offending field(s). Omitted when the failure isn't field-specific.\n * @returns `{ ok: false, error, fieldErrors? }`.\n */\nexport const err = (\n error: string,\n fieldErrors?: Record<string, string>,\n): Result<never> =>\n fieldErrors ? { ok: false, error, fieldErrors } : { ok: false, error };\n","import { err, ok, type Result } from './result';\nimport { validateFields, type ValidatorSchema } from './validators';\n\n/** Generic, user-safe message returned when a handler throws. */\nconst GENERIC_ERROR = 'Something went wrong. Please try again.';\n\n/**\n * An error whose `message` is safe to show to the end user.\n *\n * Handlers throw this to surface a *specific, actionable* failure (e.g. \"a\n * product with this name already exists\") through {@link createServerAction}\n * instead of collapsing into the {@link GENERIC_ERROR}. Any error that is NOT\n * an `ActionError` is treated as unexpected: it is logged server-side and the\n * caller receives the generic message so internal details never leak.\n */\nexport class ActionError extends Error {\n /**\n * The form field this failure is attributable to (e.g. `\"name\"` for a\n * duplicate-name conflict). When set, {@link createServerAction} surfaces it\n * as `fieldErrors` so the form can highlight that exact field.\n */\n readonly field?: string;\n\n /**\n * Per-field messages when a single failure attributes to MORE than one field\n * (e.g. several duplicate SKUs across a product's variation rows). Takes\n * precedence over {@link field}; when set, {@link createServerAction} passes\n * this map straight through as `fieldErrors`.\n */\n readonly fieldErrors?: Record<string, string>;\n\n constructor(message: string, field?: string, fieldErrors?: Record<string, string>) {\n super(message);\n this.name = 'ActionError';\n this.field = field;\n this.fieldErrors = fieldErrors;\n }\n}\n\n/**\n * Wraps a handler-agnostic server action with validate-first semantics.\n *\n * The returned action:\n * 1. Runs {@link validateFields} against `input` using `schema`. On the first\n * field error it returns `err(message)` **without invoking `handler`**.\n * 2. Otherwise invokes `handler(input)` and returns `ok` with its resolved\n * value.\n * 3. Passes through the message of an {@link ActionError} thrown by `handler`\n * (a deliberate, user-safe failure), and maps any *other* exception to a\n * generic `err` message — logging the real cause server-side so production\n * failures stay diagnosable without leaking internals to the client.\n *\n * @typeParam I - The validated input shape (string fields keyed by name).\n * @typeParam O - The handler's success payload type.\n * @param schema - Per-field validators applied before the handler runs.\n * @param handler - The business logic, run only when input is valid.\n * @returns An async action that resolves to a {@link Result}.\n */\nexport const createServerAction = <I extends Record<string, string>, O>(\n schema: ValidatorSchema<I>,\n handler: (input: I) => Promise<O> | O,\n): ((input: I) => Promise<Result<O>>) => {\n return async (input: I): Promise<Result<O>> => {\n const errors = validateFields(input, schema);\n // Surface the first failing field by name so the form highlights it.\n const firstField = (Object.keys(errors) as (keyof I)[]).find(\n (field) => typeof errors[field] === 'string',\n );\n if (firstField !== undefined) {\n const message = errors[firstField] as string;\n return err(message, { [String(firstField)]: message });\n }\n\n try {\n return ok(await handler(input));\n } catch (error) {\n if (error instanceof ActionError) {\n // A multi-field map (fieldErrors) wins over the single-field shorthand so\n // one failure can highlight several inputs (e.g. duplicate variation SKUs).\n const fieldErrors =\n error.fieldErrors ?? (error.field ? { [error.field]: error.message } : undefined);\n return err(error.message, fieldErrors);\n }\n // Unexpected: log the real cause server-side (never sent to the client)\n // so prod failures are diagnosable, and return a safe generic message.\n console.error('[serverAction] handler threw an unexpected error:', error);\n return err(GENERIC_ERROR);\n }\n };\n};\n","/**\n * Brazilian document + address primitives (FUT-306).\n *\n * Masks, shape checks and check-digit validation for the two fields every\n * pt-BR form asks for — CEP and CNPJ — plus the UF list. Pure and dependency\n * free like the rest of `forms-core`, so the SAME rules run in the browser\n * (input mask + inline validation), in a route handler (before hitting a\n * lookup provider) and in a test.\n *\n * @module forms-core/br\n */\n\nimport type { Validator } from './validators';\n\n/** Brazilian federative units, for UF selects and client-side validation. */\nexport const UF_LIST = [\n 'AC', 'AL', 'AP', 'AM', 'BA', 'CE', 'DF', 'ES', 'GO',\n 'MA', 'MT', 'MS', 'MG', 'PA', 'PB', 'PR', 'PE', 'PI',\n 'RJ', 'RN', 'RS', 'RO', 'RR', 'SC', 'SP', 'SE', 'TO',\n] as const;\n\n/** A Brazilian federative unit. */\nexport type Uf = (typeof UF_LIST)[number];\n\n/** True when `value` is one of the 27 {@link UF_LIST} entries (case-sensitive). */\nexport function isUf(value: string): value is Uf {\n return (UF_LIST as readonly string[]).includes(value);\n}\n\n// ---------------------------------------------------------------------------\n// CEP\n// ---------------------------------------------------------------------------\n\n/** Canonical CEP shape after masking/normalization: `01310-100`. */\nexport const CEP_PATTERN = /^\\d{5}-\\d{3}$/;\n\n/** The bare digits of a CEP, capped at the 8 a CEP has. */\nexport function cepDigits(raw: string): string {\n return raw.replace(/\\D/g, '').slice(0, 8);\n}\n\n/**\n * Mask raw CEP input to `#####-###`: strips non-digits, caps at 8 digits and\n * inserts the hyphen once the sixth digit arrives. Pure — safe to run on every\n * keystroke and to normalize before matching {@link CEP_PATTERN}.\n */\nexport function formatCep(raw: string): string {\n const digits = cepDigits(raw);\n return digits.length > 5 ? `${digits.slice(0, 5)}-${digits.slice(5)}` : digits;\n}\n\n/**\n * True when `raw` holds a complete, well-formed CEP.\n *\n * Shape only: a CEP is a postal RANGE allocated by the Correios, so there is no\n * check digit to verify. Whether it actually EXISTS is answered by a lookup,\n * not by this function.\n */\nexport function isValidCep(raw: string): boolean {\n return CEP_PATTERN.test(formatCep(raw));\n}\n\n/** Empty ⇒ valid (optional field); otherwise the value must be a full CEP. */\nexport const cep =\n (message = 'CEP inválido — use o formato 00000-000.'): Validator =>\n (value) =>\n value.trim() === '' || isValidCep(value) ? undefined : message;\n\n// ---------------------------------------------------------------------------\n// CNPJ\n// ---------------------------------------------------------------------------\n\n/** Canonical CNPJ shape after masking: `12.ABC.345/01DE-35`. */\nexport const CNPJ_PATTERN = /^[0-9A-Z]{2}\\.[0-9A-Z]{3}\\.[0-9A-Z]{3}\\/[0-9A-Z]{4}-\\d{2}$/;\n\n/** How many characters a CNPJ has, check digits included. */\nconst CNPJ_LENGTH = 14;\n\n/**\n * Strip a CNPJ to its 14 significant characters, uppercased.\n *\n * Alphanumeric-aware (Receita Federal IN 2.229/2024, live in production since\n * 2026-07-06): the first 12 positions may be letters OR digits, so only\n * punctuation is removed — never letters.\n */\nexport function cnpjChars(raw: string): string {\n return raw.toUpperCase().replace(/[^0-9A-Z]/g, '').slice(0, CNPJ_LENGTH);\n}\n\n/**\n * Mask raw CNPJ input to `##.###.###/####-##`, accepting letters in the first\n * twelve positions and digits in the two check positions.\n */\nexport function formatCnpj(raw: string): string {\n const chars = cnpjChars(raw);\n const parts = [\n chars.slice(0, 2),\n chars.slice(2, 5),\n chars.slice(5, 8),\n chars.slice(8, 12),\n // The check digits are always numeric, even on an alphanumeric CNPJ.\n chars.slice(12, 14).replace(/\\D/g, ''),\n ];\n let masked = parts[0] as string;\n if (chars.length > 2) masked += `.${parts[1]}`;\n if (chars.length > 5) masked += `.${parts[2]}`;\n if (chars.length > 8) masked += `/${parts[3]}`;\n if (chars.length > 12) masked += `-${parts[4]}`;\n return masked;\n}\n\n/**\n * The mod-11 weights, right-to-left cycling 2…9. `slice(-n)` takes the tail so\n * the same table serves the 12-char first pass and the 13-char second.\n */\nconst CNPJ_WEIGHTS = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] as const;\n\n/**\n * A character's numeric contribution: its ASCII code minus 48. Digits `0`–`9`\n * map to 0–9 (identical to the legacy rule, so existing CNPJs keep validating)\n * and letters `A`–`Z` map to 17–42.\n */\nfunction cnpjValue(char: string): number {\n return char.charCodeAt(0) - 48;\n}\n\n/** One mod-11 check digit over the first `base.length` characters. */\nfunction cnpjCheckDigit(base: string): number {\n const weights = CNPJ_WEIGHTS.slice(-base.length);\n const sum = [...base].reduce((acc, char, i) => acc + cnpjValue(char) * (weights[i] as number), 0);\n const remainder = sum % 11;\n return remainder < 2 ? 0 : 11 - remainder;\n}\n\n/**\n * Validate a CNPJ's check digits (mod 11), alphanumeric-aware.\n *\n * Rejects the repeated-character sequences (`00000000000000`, `AAAAAAAAAAAA35`)\n * that satisfy the arithmetic but are never issued. Returns false for anything\n * that is not exactly 14 characters with numeric check digits.\n */\nexport function isValidCnpj(raw: string): boolean {\n const chars = cnpjChars(raw);\n if (chars.length !== CNPJ_LENGTH) return false;\n // Only the 12-character root/establishment may be alphanumeric; the two check\n // digits stay numeric.\n if (!/^\\d{2}$/.test(chars.slice(12))) return false;\n if (new Set(chars).size === 1) return false;\n\n const base = chars.slice(0, 12);\n const first = cnpjCheckDigit(base);\n if (first !== Number(chars[12])) return false;\n return cnpjCheckDigit(`${base}${first}`) === Number(chars[13]);\n}\n\n/** Empty ⇒ valid (optional field); otherwise the check digits must match. */\nexport const cnpj =\n (message = 'CNPJ inválido — confira os dígitos.'): Validator =>\n (value) =>\n value.trim() === '' || isValidCnpj(value) ? undefined : message;\n\n// ---------------------------------------------------------------------------\n// Telefone\n// ---------------------------------------------------------------------------\n\n/**\n * Format a Brazilian phone as `(11) 3214-5600` / `(11) 91234-5678`.\n *\n * Both sources that hand us a phone give it as bare concatenated digits — the\n * Receita Federal's `ddd_telefone_1` and an NF-e's `<fone>` — so the same\n * formatting rule serves the CNPJ lookup and the nota importer.\n *\n * Anything that is not a 10- or 11-digit national number is returned trimmed\n * but otherwise untouched: an unrecognized phone (a foreign issuer, an extension\n * appended by the emitter's software) is still better dropped into the field\n * than discarded.\n *\n * @param raw - Digits as the source supplies them, e.g. `1132145600`.\n * @returns The formatted phone, or `null` when there is nothing to format.\n */\nexport function formatBrPhone(raw: string | null | undefined): string | null {\n const trimmed = raw?.trim();\n if (!trimmed) return null;\n const digits = trimmed.replace(/\\D/g, '');\n if (digits.length !== 10 && digits.length !== 11) return trimmed;\n const ddd = digits.slice(0, 2);\n const subscriber = digits.slice(2);\n const split = subscriber.length - 4;\n return `(${ddd}) ${subscriber.slice(0, split)}-${subscriber.slice(split)}`;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/validators.ts","../src/result.ts","../src/serverAction.ts","../src/br.ts"],"sourcesContent":["/**\n * Field-level form validators\n *\n * Pure, framework-agnostic validators — NO zod, NO react-hook-form. Each\n * validator is curried and returns a `string` error message for invalid input\n * or `undefined` when the value is valid.\n *\n * @module forms-core/validators\n */\n\n/** A field validator: returns an error message, or `undefined` when valid. */\nexport type Validator = (value: string) => string | undefined;\n\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n/**\n * Requires a non-empty value (after trimming whitespace).\n *\n * @param message - Custom error message for empty input.\n * @returns A validator returning the message for empty input, else `undefined`.\n */\nexport const required =\n (message = 'This field is required'): Validator =>\n (value) =>\n value.trim().length === 0 ? message : undefined;\n\n/**\n * Validates that the value is a well-formed email address.\n *\n * @param message - Custom error message for malformed input.\n * @returns A validator returning the message for invalid input, else `undefined`.\n */\nexport const email =\n (message = 'Enter a valid email address'): Validator =>\n (value) =>\n EMAIL_PATTERN.test(value) ? undefined : message;\n\n/**\n * Validates that the value has at least `length` characters.\n *\n * @param length - The minimum number of characters required.\n * @param message - Custom error message for too-short input.\n * @returns A validator returning the message for short input, else `undefined`.\n */\nexport const minLength =\n (length: number, message = `Must be at least ${length} characters`): Validator =>\n (value) =>\n value.length < length ? message : undefined;\n\n/** Alias of {@link minLength}. */\nexport const min = minLength;\n\n/** A map of field names to the list of validators applied to that field. */\nexport type ValidatorSchema<T> = {\n [K in keyof T]?: Validator[];\n};\n\n/** A map of field names to the first error message produced for that field. */\nexport type FieldErrors<T> = {\n [K in keyof T]?: string;\n};\n\n/**\n * The first error message a field's validators produce, or `undefined` when\n * every validator passes. Short-circuits on the first failure.\n */\nconst firstFieldError = (validators: Validator[], value: string): string | undefined => {\n for (const validate of validators) {\n const error = validate(value);\n if (error !== undefined) {\n return error;\n }\n }\n return undefined;\n};\n\n/**\n * Runs each field's validators against `values`, short-circuiting on the first\n * failing validator per field.\n *\n * @param values - The field values to validate (keyed by field name).\n * @param schema - Validators to apply per field.\n * @returns A record containing one entry per failing field; `{}` when all valid.\n */\nexport const validateFields = <T extends Record<string, string>>(\n values: T,\n schema: ValidatorSchema<T>,\n): FieldErrors<T> => {\n const errors: FieldErrors<T> = {};\n\n for (const field of Object.keys(schema) as (keyof T)[]) {\n const validators = schema[field];\n if (!validators) {\n continue;\n }\n const error = firstFieldError(validators, values[field] ?? '');\n if (error !== undefined) {\n errors[field] = error;\n }\n }\n\n return errors;\n};\n","/**\n * Discriminated-union result type for operations that can fail.\n *\n * Pure and framework-agnostic. The `ok` discriminant narrows the union so\n * consumers can safely read `data` on success or `error` on failure.\n *\n * @typeParam T - The success payload type.\n * @module forms-core/result\n */\nexport type Result<T> =\n | { ok: true; data: T }\n | {\n ok: false;\n error: string;\n /**\n * Per-field error messages, keyed by form field name, when the failure is\n * attributable to specific input(s). Lets a form highlight the exact\n * offending field(s) instead of only showing the summary `error`.\n */\n fieldErrors?: Record<string, string>;\n };\n\n/**\n * Builds a successful {@link Result} wrapping `data`.\n *\n * @typeParam T - The success payload type.\n * @param data - The value to wrap.\n * @returns `{ ok: true, data }`.\n */\nexport const ok = <T>(data: T): Result<T> => ({ ok: true, data });\n\n/**\n * Builds a failed {@link Result} wrapping an error `message`.\n *\n * @param error - A user-safe error message (never an internal/stack detail).\n * @param fieldErrors - Optional per-field messages so a form can highlight the\n * exact offending field(s). Omitted when the failure isn't field-specific.\n * @returns `{ ok: false, error, fieldErrors? }`.\n */\nexport const err = (\n error: string,\n fieldErrors?: Record<string, string>,\n): Result<never> =>\n fieldErrors ? { ok: false, error, fieldErrors } : { ok: false, error };\n","import { err, ok, type Result } from './result';\nimport { validateFields, type ValidatorSchema } from './validators';\n\n/** Generic, user-safe message returned when a handler throws. */\nconst GENERIC_ERROR = 'Something went wrong. Please try again.';\n\n/**\n * An error whose `message` is safe to show to the end user.\n *\n * Handlers throw this to surface a *specific, actionable* failure (e.g. \"a\n * product with this name already exists\") through {@link createServerAction}\n * instead of collapsing into the {@link GENERIC_ERROR}. Any error that is NOT\n * an `ActionError` is treated as unexpected: it is logged server-side and the\n * caller receives the generic message so internal details never leak.\n */\nexport class ActionError extends Error {\n /**\n * The form field this failure is attributable to (e.g. `\"name\"` for a\n * duplicate-name conflict). When set, {@link createServerAction} surfaces it\n * as `fieldErrors` so the form can highlight that exact field.\n */\n readonly field?: string;\n\n /**\n * Per-field messages when a single failure attributes to MORE than one field\n * (e.g. several duplicate SKUs across a product's variation rows). Takes\n * precedence over {@link field}; when set, {@link createServerAction} passes\n * this map straight through as `fieldErrors`.\n */\n readonly fieldErrors?: Record<string, string>;\n\n constructor(message: string, field?: string, fieldErrors?: Record<string, string>) {\n super(message);\n this.name = 'ActionError';\n this.field = field;\n this.fieldErrors = fieldErrors;\n }\n}\n\n/**\n * Wraps a handler-agnostic server action with validate-first semantics.\n *\n * The returned action:\n * 1. Runs {@link validateFields} against `input` using `schema`. On the first\n * field error it returns `err(message)` **without invoking `handler`**.\n * 2. Otherwise invokes `handler(input)` and returns `ok` with its resolved\n * value.\n * 3. Passes through the message of an {@link ActionError} thrown by `handler`\n * (a deliberate, user-safe failure), and maps any *other* exception to a\n * generic `err` message — logging the real cause server-side so production\n * failures stay diagnosable without leaking internals to the client.\n *\n * @typeParam I - The validated input shape (string fields keyed by name).\n * @typeParam O - The handler's success payload type.\n * @param schema - Per-field validators applied before the handler runs.\n * @param handler - The business logic, run only when input is valid.\n * @returns An async action that resolves to a {@link Result}.\n */\nexport const createServerAction = <I extends Record<string, string>, O>(\n schema: ValidatorSchema<I>,\n handler: (input: I) => Promise<O> | O,\n): ((input: I) => Promise<Result<O>>) => {\n return async (input: I): Promise<Result<O>> => {\n const errors = validateFields(input, schema);\n // Surface the first failing field by name so the form highlights it.\n const firstField = (Object.keys(errors) as (keyof I)[]).find(\n (field) => typeof errors[field] === 'string',\n );\n if (firstField !== undefined) {\n const message = errors[firstField] as string;\n return err(message, { [String(firstField)]: message });\n }\n\n try {\n return ok(await handler(input));\n } catch (error) {\n if (error instanceof ActionError) {\n // A multi-field map (fieldErrors) wins over the single-field shorthand so\n // one failure can highlight several inputs (e.g. duplicate variation SKUs).\n const fieldErrors =\n error.fieldErrors ?? (error.field ? { [error.field]: error.message } : undefined);\n return err(error.message, fieldErrors);\n }\n // Unexpected: log the real cause server-side (never sent to the client)\n // so prod failures are diagnosable, and return a safe generic message.\n console.error('[serverAction] handler threw an unexpected error:', error);\n return err(GENERIC_ERROR);\n }\n };\n};\n","/**\n * Brazilian document + address primitives (FUT-306).\n *\n * Masks, shape checks and check-digit validation for the two fields every\n * pt-BR form asks for — CEP and CNPJ — plus the UF list. Pure and dependency\n * free like the rest of `forms-core`, so the SAME rules run in the browser\n * (input mask + inline validation), in a route handler (before hitting a\n * lookup provider) and in a test.\n *\n * @module forms-core/br\n */\n\nimport type { Validator } from './validators';\n\n/** Brazilian federative units, for UF selects and client-side validation. */\nexport const UF_LIST = [\n 'AC', 'AL', 'AP', 'AM', 'BA', 'CE', 'DF', 'ES', 'GO',\n 'MA', 'MT', 'MS', 'MG', 'PA', 'PB', 'PR', 'PE', 'PI',\n 'RJ', 'RN', 'RS', 'RO', 'RR', 'SC', 'SP', 'SE', 'TO',\n] as const;\n\n/** A Brazilian federative unit. */\nexport type Uf = (typeof UF_LIST)[number];\n\n/** True when `value` is one of the 27 {@link UF_LIST} entries (case-sensitive). */\nexport function isUf(value: string): value is Uf {\n return (UF_LIST as readonly string[]).includes(value);\n}\n\n// ---------------------------------------------------------------------------\n// CEP\n// ---------------------------------------------------------------------------\n\n/** Canonical CEP shape after masking/normalization: `01310-100`. */\nexport const CEP_PATTERN = /^\\d{5}-\\d{3}$/;\n\n/** The bare digits of a CEP, capped at the 8 a CEP has. */\nexport function cepDigits(raw: string): string {\n return raw.replace(/\\D/g, '').slice(0, 8);\n}\n\n/**\n * Mask raw CEP input to `#####-###`: strips non-digits, caps at 8 digits and\n * inserts the hyphen once the sixth digit arrives. Pure — safe to run on every\n * keystroke and to normalize before matching {@link CEP_PATTERN}.\n */\nexport function formatCep(raw: string): string {\n const digits = cepDigits(raw);\n return digits.length > 5 ? `${digits.slice(0, 5)}-${digits.slice(5)}` : digits;\n}\n\n/**\n * True when `raw` holds a complete, well-formed CEP.\n *\n * Shape only: a CEP is a postal RANGE allocated by the Correios, so there is no\n * check digit to verify. Whether it actually EXISTS is answered by a lookup,\n * not by this function.\n */\nexport function isValidCep(raw: string): boolean {\n return CEP_PATTERN.test(formatCep(raw));\n}\n\n/** Empty ⇒ valid (optional field); otherwise the value must be a full CEP. */\nexport const cep =\n (message = 'CEP inválido — use o formato 00000-000.'): Validator =>\n (value) =>\n value.trim() === '' || isValidCep(value) ? undefined : message;\n\n// ---------------------------------------------------------------------------\n// CNPJ\n// ---------------------------------------------------------------------------\n\n/** Canonical CNPJ shape after masking: `12.ABC.345/01DE-35`. */\nexport const CNPJ_PATTERN = /^[0-9A-Z]{2}\\.[0-9A-Z]{3}\\.[0-9A-Z]{3}\\/[0-9A-Z]{4}-\\d{2}$/;\n\n/** How many characters a CNPJ has, check digits included. */\nconst CNPJ_LENGTH = 14;\n\n/**\n * Strip a CNPJ to its 14 significant characters, uppercased.\n *\n * Alphanumeric-aware (Receita Federal IN 2.229/2024, live in production since\n * 2026-07-06): the first 12 positions may be letters OR digits, so only\n * punctuation is removed — never letters.\n */\nexport function cnpjChars(raw: string): string {\n return raw.toUpperCase().replace(/[^0-9A-Z]/g, '').slice(0, CNPJ_LENGTH);\n}\n\n/**\n * Mask raw CNPJ input to `##.###.###/####-##`, accepting letters in the first\n * twelve positions and digits in the two check positions.\n */\nexport function formatCnpj(raw: string): string {\n const chars = cnpjChars(raw);\n const parts = [\n chars.slice(0, 2),\n chars.slice(2, 5),\n chars.slice(5, 8),\n chars.slice(8, 12),\n // The check digits are always numeric, even on an alphanumeric CNPJ.\n chars.slice(12, 14).replace(/\\D/g, ''),\n ];\n let masked = parts[0] as string;\n if (chars.length > 2) masked += `.${parts[1]}`;\n if (chars.length > 5) masked += `.${parts[2]}`;\n if (chars.length > 8) masked += `/${parts[3]}`;\n if (chars.length > 12) masked += `-${parts[4]}`;\n return masked;\n}\n\n/**\n * The mod-11 weights, right-to-left cycling 2…9. `slice(-n)` takes the tail so\n * the same table serves the 12-char first pass and the 13-char second.\n */\nconst CNPJ_WEIGHTS = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] as const;\n\n/**\n * A character's numeric contribution: its ASCII code minus 48. Digits `0`–`9`\n * map to 0–9 (identical to the legacy rule, so existing CNPJs keep validating)\n * and letters `A`–`Z` map to 17–42.\n */\nfunction cnpjValue(char: string): number {\n return char.charCodeAt(0) - 48;\n}\n\n/** One mod-11 check digit over the first `base.length` characters. */\nfunction cnpjCheckDigit(base: string): number {\n const weights = CNPJ_WEIGHTS.slice(-base.length);\n const sum = [...base].reduce((acc, char, i) => acc + cnpjValue(char) * (weights[i] as number), 0);\n const remainder = sum % 11;\n return remainder < 2 ? 0 : 11 - remainder;\n}\n\n/**\n * Validate a CNPJ's check digits (mod 11), alphanumeric-aware.\n *\n * Rejects the repeated-character sequences (`00000000000000`, `AAAAAAAAAAAA35`)\n * that satisfy the arithmetic but are never issued. Returns false for anything\n * that is not exactly 14 characters with numeric check digits.\n */\nexport function isValidCnpj(raw: string): boolean {\n const chars = cnpjChars(raw);\n if (chars.length !== CNPJ_LENGTH) return false;\n // Only the 12-character root/establishment may be alphanumeric; the two check\n // digits stay numeric.\n if (!/^\\d{2}$/.test(chars.slice(12))) return false;\n if (new Set(chars).size === 1) return false;\n\n const base = chars.slice(0, 12);\n const first = cnpjCheckDigit(base);\n if (first !== Number(chars[12])) return false;\n return cnpjCheckDigit(`${base}${first}`) === Number(chars[13]);\n}\n\n/** Empty ⇒ valid (optional field); otherwise the check digits must match. */\nexport const cnpj =\n (message = 'CNPJ inválido — confira os dígitos.'): Validator =>\n (value) =>\n value.trim() === '' || isValidCnpj(value) ? undefined : message;\n\n// ---------------------------------------------------------------------------\n// Telefone\n// ---------------------------------------------------------------------------\n\n/**\n * Format a Brazilian phone as `(11) 3214-5600` / `(11) 91234-5678`.\n *\n * Both sources that hand us a phone give it as bare concatenated digits — the\n * Receita Federal's `ddd_telefone_1` and an NF-e's `<fone>` — so the same\n * formatting rule serves the CNPJ lookup and the nota importer.\n *\n * Anything that is not a 10- or 11-digit national number is returned trimmed\n * but otherwise untouched: an unrecognized phone (a foreign issuer, an extension\n * appended by the emitter's software) is still better dropped into the field\n * than discarded.\n *\n * @param raw - Digits as the source supplies them, e.g. `1132145600`.\n * @returns The formatted phone, or `null` when there is nothing to format.\n */\nexport function formatBrPhone(raw: string | null | undefined): string | null {\n const trimmed = raw?.trim();\n if (!trimmed) return null;\n const digits = trimmed.replace(/\\D/g, '');\n if (digits.length !== 10 && digits.length !== 11) return trimmed;\n const ddd = digits.slice(0, 2);\n const subscriber = digits.slice(2);\n const split = subscriber.length - 4;\n return `(${ddd}) ${subscriber.slice(0, split)}-${subscriber.slice(split)}`;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/forms-core",
3
- "version": "1.19.1",
3
+ "version": "1.19.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Pure, framework-agnostic form primitives — field validators, the Result type, and createServerAction. Zero dependencies, shipped compiled so a Node consumer can import it (Node cannot strip types under node_modules).",