@br-validators/express 1.6.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 BR Validators contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # @br-validators/express
2
+
3
+ Express and Fastify middleware for Brazilian document validation — delegates to [`@br-validators/core`](../br-validators) `validate*` functions (BR-GENERATE-001 / BR-VALIDATE parity).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @br-validators/express @br-validators/core express
9
+ ```
10
+
11
+ **Peer dependencies:** `express` `^4.21.0 || ^5.0.0`, `@br-validators/core`
12
+
13
+ ## Express
14
+
15
+ ```typescript
16
+ import express from 'express';
17
+ import { brValidate } from '@br-validators/express';
18
+
19
+ const app = express();
20
+ app.use(express.json());
21
+
22
+ app.post(
23
+ '/cliente',
24
+ brValidate({
25
+ body: { cpf: 'cpf', cnpj: 'cnpj', cep: 'cep' },
26
+ uf: { from: 'body', field: 'uf' },
27
+ }),
28
+ (req, res) => {
29
+ res.json({ ok: true });
30
+ },
31
+ );
32
+ ```
33
+
34
+ Invalid input returns HTTP **400** with a structured body:
35
+
36
+ ```json
37
+ {
38
+ "ok": false,
39
+ "field": "cpf",
40
+ "code": "INVALID_CHECK_DIGIT",
41
+ "message": "..."
42
+ }
43
+ ```
44
+
45
+ ## Fastify
46
+
47
+ ```typescript
48
+ import Fastify from 'fastify';
49
+ import { brValidateFastify } from '@br-validators/express/fastify';
50
+
51
+ const app = Fastify();
52
+
53
+ app.post(
54
+ '/cliente',
55
+ {
56
+ preHandler: brValidateFastify({
57
+ body: { cpf: 'cpf', ie: 'inscricao-estadual' },
58
+ uf: { from: 'body', field: 'uf' },
59
+ }),
60
+ },
61
+ async () => ({ ok: true }),
62
+ );
63
+ ```
64
+
65
+ ## Schema
66
+
67
+ | Option | Description |
68
+ |--------|-------------|
69
+ | `body` | Map field names → core validator type id |
70
+ | `query` | Same for `req.query` |
71
+ | `params` | Same for `req.params` |
72
+ | `uf` | `{ from: 'body' \| 'query' \| 'params', field: 'uf' }` or `{ value: 'SP' }` — required for IE and RG |
73
+
74
+ ### Supported type ids (18)
75
+
76
+ `cpf`, `cnpj`, `cep`, `placa`, `pis-pasep`, `pix`, `telefone`, `boleto`, `cartao-credito`, `cnh`, `renavam`, `nfe-chave`, `titulo-eleitor`, `processo-judicial`, `inscricao-estadual`, `inscricao-estadual-produtor-rural`, `brcode`, `rg`
77
+
78
+ Official algorithm sources: [docs/OFFICIAL-SOURCES.md](../../docs/OFFICIAL-SOURCES.md).
79
+
80
+ ## License
81
+
82
+ MIT
@@ -0,0 +1,41 @@
1
+ import { UfCode, ValidationErrorCode } from '@br-validators/core';
2
+
3
+ /** Core validator type ids supported by `brValidate()`. */
4
+ type BrValidatorTypeId = 'cpf' | 'cnpj' | 'cep' | 'placa' | 'pis-pasep' | 'pix' | 'telefone' | 'boleto' | 'cartao-credito' | 'cnh' | 'renavam' | 'nfe-chave' | 'titulo-eleitor' | 'processo-judicial' | 'inscricao-estadual' | 'inscricao-estadual-produtor-rural' | 'brcode' | 'rg';
5
+ declare const BR_VALIDATOR_TYPE_IDS: readonly ["cpf", "cnpj", "cep", "placa", "pis-pasep", "pix", "telefone", "boleto", "cartao-credito", "cnh", "renavam", "nfe-chave", "titulo-eleitor", "processo-judicial", "inscricao-estadual", "inscricao-estadual-produtor-rural", "brcode", "rg"];
6
+ type BrValidateLocation = 'body' | 'query' | 'params';
7
+ type BrValidateFieldSchema = Record<string, BrValidatorTypeId>;
8
+ type BrValidateUfSource = {
9
+ from: BrValidateLocation;
10
+ field: string;
11
+ } | {
12
+ value: UfCode;
13
+ };
14
+ type BrValidateOptions = {
15
+ body?: BrValidateFieldSchema;
16
+ query?: BrValidateFieldSchema;
17
+ params?: BrValidateFieldSchema;
18
+ /** Required for `inscricao-estadual`, `inscricao-estadual-produtor-rural`, and `rg`. */
19
+ uf?: BrValidateUfSource;
20
+ };
21
+ type BrValidationErrorResponse = {
22
+ ok: false;
23
+ field: string;
24
+ code: ValidationErrorCode;
25
+ message: string;
26
+ };
27
+ type BrValidateRequest = {
28
+ body?: object;
29
+ query?: object;
30
+ params?: object;
31
+ };
32
+ type BrValidateResponse = {
33
+ status(code: number): BrValidateResponse;
34
+ json(body: BrValidationErrorResponse): void;
35
+ };
36
+ type BrValidateNext = () => void;
37
+ declare function isBrValidatorTypeId(value: string): value is BrValidatorTypeId;
38
+
39
+ declare function createBrValidateHandler(options: BrValidateOptions): (req: BrValidateRequest, res: BrValidateResponse, next: BrValidateNext) => void;
40
+
41
+ export { type BrValidateOptions as B, type BrValidateRequest as a, type BrValidationErrorResponse as b, type BrValidatorTypeId as c, createBrValidateHandler as d, BR_VALIDATOR_TYPE_IDS as e, type BrValidateFieldSchema as f, type BrValidateLocation as g, type BrValidateUfSource as h, isBrValidatorTypeId as i };
@@ -0,0 +1,158 @@
1
+ import { validateBrCode, validateProcessoJudicial, validateTituloEleitor, validateNfeChave, validateRenavam, validateCnh, validateCartaoCredito, validateBoleto, validateTelefone, validatePixKey, validatePisPasep, validatePlaca, validateCep, validateCnpj, validateCpf, validateRg, validateIeProdutorRural, validateInscricaoEstadual, RG_SUPPORTED_UFS } from '@br-validators/core';
2
+
3
+ // src/validator-registry.ts
4
+ var UF_REQUIRED_TYPES = /* @__PURE__ */ new Set([
5
+ "inscricao-estadual",
6
+ "inscricao-estadual-produtor-rural",
7
+ "rg"
8
+ ]);
9
+ function requiresUf(typeId) {
10
+ return UF_REQUIRED_TYPES.has(typeId);
11
+ }
12
+ function missingUfFailure() {
13
+ return {
14
+ ok: false,
15
+ code: "UNSUPPORTED_FORMAT",
16
+ message: "UF is required for this field \u2014 configure brValidate({ uf: { from, field } }) or { value }"
17
+ };
18
+ }
19
+ function runWithUf(context, validate) {
20
+ return (value, ctx) => {
21
+ const uf = ctx.uf ?? context.uf;
22
+ if (!uf) {
23
+ return missingUfFailure();
24
+ }
25
+ return validate(value, uf);
26
+ };
27
+ }
28
+ function isRgUf(uf) {
29
+ return RG_SUPPORTED_UFS.includes(uf);
30
+ }
31
+ var VALIDATORS = {
32
+ cpf: (value) => validateCpf(value),
33
+ cnpj: (value) => validateCnpj(value),
34
+ cep: (value) => validateCep(value),
35
+ placa: (value) => validatePlaca(value),
36
+ "pis-pasep": (value) => validatePisPasep(value),
37
+ pix: (value) => validatePixKey(value),
38
+ telefone: (value) => validateTelefone(value),
39
+ boleto: (value) => validateBoleto(value),
40
+ "cartao-credito": (value) => validateCartaoCredito(value),
41
+ cnh: (value) => validateCnh(value),
42
+ renavam: (value) => validateRenavam(value),
43
+ "nfe-chave": (value) => validateNfeChave(value),
44
+ "titulo-eleitor": (value) => validateTituloEleitor(value),
45
+ "processo-judicial": (value) => validateProcessoJudicial(value),
46
+ brcode: (value) => validateBrCode(value),
47
+ "inscricao-estadual": runWithUf({}, (value, uf) => validateInscricaoEstadual(value, { uf })),
48
+ "inscricao-estadual-produtor-rural": runWithUf({}, (value, uf) => validateIeProdutorRural(uf, value)),
49
+ rg: runWithUf({}, (value, uf) => {
50
+ if (!isRgUf(uf)) {
51
+ return {
52
+ ok: false,
53
+ code: "UF_NOT_IMPLEMENTED",
54
+ message: `UF ${uf} is not implemented for RG validation`
55
+ };
56
+ }
57
+ return validateRg(value, { uf });
58
+ })
59
+ };
60
+ function runBrValidator(typeId, value, context) {
61
+ return VALIDATORS[typeId](value, context);
62
+ }
63
+
64
+ // src/br-validate.ts
65
+ function readRecordField(record, field) {
66
+ if (!record) {
67
+ return void 0;
68
+ }
69
+ return Object.prototype.hasOwnProperty.call(record, field) ? record[field] : void 0;
70
+ }
71
+ function collectFieldRefs(location, schema) {
72
+ if (!schema) {
73
+ return [];
74
+ }
75
+ return Object.entries(schema).map(([field, typeId]) => ({
76
+ location,
77
+ field,
78
+ typeId
79
+ }));
80
+ }
81
+ function listBrValidateFields(options) {
82
+ return [
83
+ ...collectFieldRefs("body", options.body),
84
+ ...collectFieldRefs("query", options.query),
85
+ ...collectFieldRefs("params", options.params)
86
+ ];
87
+ }
88
+ function readLocationRecord(req, location) {
89
+ switch (location) {
90
+ case "body":
91
+ return req.body;
92
+ case "query":
93
+ return req.query;
94
+ case "params":
95
+ return req.params;
96
+ }
97
+ }
98
+ function resolveBrValidateUf(source, req) {
99
+ if (!source) {
100
+ return void 0;
101
+ }
102
+ if ("value" in source) {
103
+ return source.value;
104
+ }
105
+ const raw = readRecordField(readLocationRecord(req, source.from), source.field);
106
+ if (typeof raw !== "string" || raw.trim() === "") {
107
+ return void 0;
108
+ }
109
+ return raw.trim().toUpperCase();
110
+ }
111
+ function validationError(field, code, message) {
112
+ return { ok: false, field, code, message };
113
+ }
114
+ function respondValidationError(res, error) {
115
+ res.status(400).json(error);
116
+ }
117
+ function createBrValidateHandler(options) {
118
+ const fields = listBrValidateFields(options);
119
+ return (req, res, next) => {
120
+ const uf = resolveBrValidateUf(options.uf, req);
121
+ for (const { location, field, typeId } of fields) {
122
+ if (requiresUf(typeId) && !uf) {
123
+ respondValidationError(
124
+ res,
125
+ validationError(
126
+ field,
127
+ "UNSUPPORTED_FORMAT",
128
+ "UF is required for this field \u2014 configure brValidate({ uf: { from, field } }) or { value }"
129
+ )
130
+ );
131
+ return;
132
+ }
133
+ const raw = readRecordField(readLocationRecord(req, location), field);
134
+ if (raw === void 0 || raw === null) {
135
+ respondValidationError(res, validationError(field, "EMPTY_INPUT", "Field is required"));
136
+ return;
137
+ }
138
+ if (typeof raw !== "string") {
139
+ respondValidationError(res, validationError(field, "UNSUPPORTED_FORMAT", "Value must be a string"));
140
+ return;
141
+ }
142
+ if (raw.trim() === "") {
143
+ respondValidationError(res, validationError(field, "EMPTY_INPUT", "Field must not be empty"));
144
+ return;
145
+ }
146
+ const result = runBrValidator(typeId, raw, { uf });
147
+ if (!result.ok) {
148
+ respondValidationError(res, validationError(field, result.code, result.message));
149
+ return;
150
+ }
151
+ }
152
+ next();
153
+ };
154
+ }
155
+
156
+ export { createBrValidateHandler, requiresUf };
157
+ //# sourceMappingURL=chunk-OKPS2N5C.js.map
158
+ //# sourceMappingURL=chunk-OKPS2N5C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/validator-registry.ts","../src/br-validate.ts"],"names":[],"mappings":"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","file":"chunk-OKPS2N5C.js","sourcesContent":["import {\n validateBoleto,\n validateBrCode,\n validateCartaoCredito,\n validateCep,\n validateCnh,\n validateCnpj,\n validateCpf,\n validateIeProdutorRural,\n validateInscricaoEstadual,\n validateNfeChave,\n validatePisPasep,\n validatePixKey,\n validatePlaca,\n validateProcessoJudicial,\n validateRenavam,\n validateRg,\n validateTelefone,\n validateTituloEleitor,\n RG_SUPPORTED_UFS,\n type RgUfCode,\n type UfCode,\n type ValidationErrorCode,\n} from '@br-validators/core';\nimport type { BrValidatorTypeId } from './types.js';\n\nexport type ValidatorContext = {\n uf?: UfCode;\n};\n\nexport type ValidatorOutcome =\n | { ok: true }\n | { ok: false; code: ValidationErrorCode; message: string };\n\nexport type ValidatorRunner = (value: string, context: ValidatorContext) => ValidatorOutcome;\n\nconst UF_REQUIRED_TYPES = new Set<BrValidatorTypeId>([\n 'inscricao-estadual',\n 'inscricao-estadual-produtor-rural',\n 'rg',\n]);\n\nexport function requiresUf(typeId: BrValidatorTypeId): boolean {\n return UF_REQUIRED_TYPES.has(typeId);\n}\n\nfunction missingUfFailure(): ValidatorOutcome {\n return {\n ok: false,\n code: 'UNSUPPORTED_FORMAT',\n message: 'UF is required for this field — configure brValidate({ uf: { from, field } }) or { value }',\n };\n}\n\nfunction runWithUf(\n context: ValidatorContext,\n validate: (value: string, uf: UfCode) => ValidatorOutcome,\n): (value: string, ctx: ValidatorContext) => ValidatorOutcome {\n return (value, ctx) => {\n const uf = ctx.uf ?? context.uf;\n if (!uf) {\n return missingUfFailure();\n }\n return validate(value, uf);\n };\n}\n\nfunction isRgUf(uf: UfCode): uf is RgUfCode {\n return (RG_SUPPORTED_UFS as readonly string[]).includes(uf);\n}\n\nconst VALIDATORS: Record<BrValidatorTypeId, ValidatorRunner> = {\n cpf: (value) => validateCpf(value),\n cnpj: (value) => validateCnpj(value),\n cep: (value) => validateCep(value),\n placa: (value) => validatePlaca(value),\n 'pis-pasep': (value) => validatePisPasep(value),\n pix: (value) => validatePixKey(value),\n telefone: (value) => validateTelefone(value),\n boleto: (value) => validateBoleto(value),\n 'cartao-credito': (value) => validateCartaoCredito(value),\n cnh: (value) => validateCnh(value),\n renavam: (value) => validateRenavam(value),\n 'nfe-chave': (value) => validateNfeChave(value),\n 'titulo-eleitor': (value) => validateTituloEleitor(value),\n 'processo-judicial': (value) => validateProcessoJudicial(value),\n brcode: (value) => validateBrCode(value),\n 'inscricao-estadual': runWithUf({}, (value, uf) => validateInscricaoEstadual(value, { uf })),\n 'inscricao-estadual-produtor-rural': runWithUf({}, (value, uf) => validateIeProdutorRural(uf, value)),\n rg: runWithUf({}, (value, uf) => {\n if (!isRgUf(uf)) {\n return {\n ok: false,\n code: 'UF_NOT_IMPLEMENTED',\n message: `UF ${uf} is not implemented for RG validation`,\n };\n }\n return validateRg(value, { uf });\n }),\n};\n\nexport function runBrValidator(\n typeId: BrValidatorTypeId,\n value: string,\n context: ValidatorContext,\n): ValidatorOutcome {\n return VALIDATORS[typeId](value, context);\n}\n","import type {\n BrValidateFieldRef,\n BrValidateLocation,\n BrValidateNext,\n BrValidateOptions,\n BrValidateRequest,\n BrValidateResponse,\n BrValidateUfSource,\n BrValidationErrorResponse,\n} from './types.js';\nimport type { UfCode } from '@br-validators/core';\nimport { requiresUf, runBrValidator } from './validator-registry.js';\n\nfunction readRecordField(record: object | undefined, field: string): unknown {\n if (!record) {\n return undefined;\n }\n return Object.prototype.hasOwnProperty.call(record, field)\n ? record[field as keyof typeof record]\n : undefined;\n}\n\nfunction collectFieldRefs(\n location: BrValidateLocation,\n schema: Record<string, import('./types.js').BrValidatorTypeId> | undefined,\n): BrValidateFieldRef[] {\n if (!schema) {\n return [];\n }\n return Object.entries(schema).map(([field, typeId]) => ({\n location,\n field,\n typeId,\n }));\n}\n\nexport function listBrValidateFields(options: BrValidateOptions): BrValidateFieldRef[] {\n return [\n ...collectFieldRefs('body', options.body),\n ...collectFieldRefs('query', options.query),\n ...collectFieldRefs('params', options.params),\n ];\n}\n\nfunction readLocationRecord(req: BrValidateRequest, location: BrValidateLocation): object | undefined {\n switch (location) {\n case 'body':\n return req.body;\n case 'query':\n return req.query;\n case 'params':\n return req.params;\n }\n}\n\nexport function resolveBrValidateUf(\n source: BrValidateUfSource | undefined,\n req: BrValidateRequest,\n): UfCode | undefined {\n if (!source) {\n return undefined;\n }\n if ('value' in source) {\n return source.value;\n }\n const raw = readRecordField(readLocationRecord(req, source.from), source.field);\n if (typeof raw !== 'string' || raw.trim() === '') {\n return undefined;\n }\n return raw.trim().toUpperCase() as UfCode;\n}\n\nfunction validationError(\n field: string,\n code: BrValidationErrorResponse['code'],\n message: string,\n): BrValidationErrorResponse {\n return { ok: false, field, code, message };\n}\n\nfunction respondValidationError(res: BrValidateResponse, error: BrValidationErrorResponse): void {\n res.status(400).json(error);\n}\n\nexport function createBrValidateHandler(options: BrValidateOptions) {\n const fields = listBrValidateFields(options);\n\n return (req: BrValidateRequest, res: BrValidateResponse, next: BrValidateNext): void => {\n const uf = resolveBrValidateUf(options.uf, req);\n\n for (const { location, field, typeId } of fields) {\n if (requiresUf(typeId) && !uf) {\n respondValidationError(\n res,\n validationError(\n field,\n 'UNSUPPORTED_FORMAT',\n 'UF is required for this field — configure brValidate({ uf: { from, field } }) or { value }',\n ),\n );\n return;\n }\n\n const raw = readRecordField(readLocationRecord(req, location), field);\n\n if (raw === undefined || raw === null) {\n respondValidationError(res, validationError(field, 'EMPTY_INPUT', 'Field is required'));\n return;\n }\n\n if (typeof raw !== 'string') {\n respondValidationError(res, validationError(field, 'UNSUPPORTED_FORMAT', 'Value must be a string'));\n return;\n }\n\n if (raw.trim() === '') {\n respondValidationError(res, validationError(field, 'EMPTY_INPUT', 'Field must not be empty'));\n return;\n }\n\n const result = runBrValidator(typeId, raw, { uf });\n if (!result.ok) {\n respondValidationError(res, validationError(field, result.code, result.message));\n return;\n }\n }\n\n next();\n };\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import { B as BrValidateOptions, a as BrValidateRequest } from './br-validate-BOiTO6lR.js';
2
+ export { b as BrValidationErrorResponse, c as BrValidatorTypeId, d as createBrValidateHandler } from './br-validate-BOiTO6lR.js';
3
+ import '@br-validators/core';
4
+
5
+ type FastifyBrValidateReply = {
6
+ status(code: number): FastifyBrValidateReply;
7
+ send(body: object): unknown;
8
+ };
9
+ type FastifyLikeRequest = {
10
+ body?: unknown;
11
+ query?: unknown;
12
+ params?: unknown;
13
+ };
14
+ declare function toBrValidateRequest(request: FastifyLikeRequest): BrValidateRequest;
15
+ /**
16
+ * Fastify preHandler — same schema as Express `brValidate()`.
17
+ */
18
+ declare function brValidateFastify(options: BrValidateOptions): (request: FastifyLikeRequest, reply: FastifyBrValidateReply, done: () => void) => void;
19
+
20
+ export { BrValidateOptions, type FastifyBrValidateReply, brValidateFastify, toBrValidateRequest };
@@ -0,0 +1,38 @@
1
+ import { createBrValidateHandler } from './chunk-OKPS2N5C.js';
2
+ export { createBrValidateHandler } from './chunk-OKPS2N5C.js';
3
+
4
+ // src/fastify.ts
5
+ function asRequestObject(value) {
6
+ if (typeof value === "object" && value !== null) {
7
+ return value;
8
+ }
9
+ return void 0;
10
+ }
11
+ function toBrValidateRequest(request) {
12
+ return {
13
+ body: asRequestObject(request.body),
14
+ query: asRequestObject(request.query),
15
+ params: asRequestObject(request.params)
16
+ };
17
+ }
18
+ function brValidateFastify(options) {
19
+ const handler = createBrValidateHandler(options);
20
+ return (request, reply, done) => {
21
+ let statusCode = 200;
22
+ const adaptedReply = {
23
+ status(code) {
24
+ statusCode = code;
25
+ reply.status(code);
26
+ return adaptedReply;
27
+ },
28
+ json(body) {
29
+ void reply.status(statusCode).send(body);
30
+ }
31
+ };
32
+ handler(toBrValidateRequest(request), adaptedReply, done);
33
+ };
34
+ }
35
+
36
+ export { brValidateFastify, toBrValidateRequest };
37
+ //# sourceMappingURL=fastify.js.map
38
+ //# sourceMappingURL=fastify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/fastify.ts"],"names":[],"mappings":";;;;AAcA,SAAS,gBAAgB,KAAA,EAAoC;AAC3D,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA,EAAM;AAC/C,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,oBAAoB,OAAA,EAAgD;AAClF,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,eAAA,CAAgB,OAAA,CAAQ,IAAI,CAAA;AAAA,IAClC,KAAA,EAAO,eAAA,CAAgB,OAAA,CAAQ,KAAK,CAAA;AAAA,IACpC,MAAA,EAAQ,eAAA,CAAgB,OAAA,CAAQ,MAAM;AAAA,GACxC;AACF;AAKO,SAAS,kBAAkB,OAAA,EAA4B;AAC5D,EAAA,MAAM,OAAA,GAAU,wBAAwB,OAAO,CAAA;AAC/C,EAAA,OAAO,CAAC,OAAA,EAA6B,KAAA,EAA+B,IAAA,KAA2B;AAC7F,IAAA,IAAI,UAAA,GAAa,GAAA;AACjB,IAAA,MAAM,YAAA,GAAe;AAAA,MACnB,OAAO,IAAA,EAAc;AACnB,QAAA,UAAA,GAAa,IAAA;AACb,QAAA,KAAA,CAAM,OAAO,IAAI,CAAA;AACjB,QAAA,OAAO,YAAA;AAAA,MACT,CAAA;AAAA,MACA,KAAK,IAAA,EAAc;AACjB,QAAA,KAAK,KAAA,CAAM,MAAA,CAAO,UAAU,CAAA,CAAE,KAAK,IAAI,CAAA;AAAA,MACzC;AAAA,KACF;AACA,IAAA,OAAA,CAAQ,mBAAA,CAAoB,OAAO,CAAA,EAAG,YAAA,EAAc,IAAI,CAAA;AAAA,EAC1D,CAAA;AACF","file":"fastify.js","sourcesContent":["import { createBrValidateHandler } from './br-validate.js';\nimport type { BrValidateOptions, BrValidateRequest } from './types.js';\n\nexport type FastifyBrValidateReply = {\n status(code: number): FastifyBrValidateReply;\n send(body: object): unknown;\n};\n\ntype FastifyLikeRequest = {\n body?: unknown;\n query?: unknown;\n params?: unknown;\n};\n\nfunction asRequestObject(value: unknown): object | undefined {\n if (typeof value === 'object' && value !== null) {\n return value;\n }\n return undefined;\n}\n\nexport function toBrValidateRequest(request: FastifyLikeRequest): BrValidateRequest {\n return {\n body: asRequestObject(request.body),\n query: asRequestObject(request.query),\n params: asRequestObject(request.params),\n };\n}\n\n/**\n * Fastify preHandler — same schema as Express `brValidate()`.\n */\nexport function brValidateFastify(options: BrValidateOptions) {\n const handler = createBrValidateHandler(options);\n return (request: FastifyLikeRequest, reply: FastifyBrValidateReply, done: () => void): void => {\n let statusCode = 200;\n const adaptedReply = {\n status(code: number) {\n statusCode = code;\n reply.status(code);\n return adaptedReply;\n },\n json(body: object) {\n void reply.status(statusCode).send(body);\n },\n };\n handler(toBrValidateRequest(request), adaptedReply, done);\n };\n}\n\nexport { createBrValidateHandler } from './br-validate.js';\nexport type { BrValidateOptions, BrValidationErrorResponse, BrValidatorTypeId } from './types.js';\n"]}
@@ -0,0 +1,14 @@
1
+ import { RequestHandler } from 'express';
2
+ import { c as BrValidatorTypeId, B as BrValidateOptions } from './br-validate-BOiTO6lR.js';
3
+ export { e as BR_VALIDATOR_TYPE_IDS, f as BrValidateFieldSchema, g as BrValidateLocation, h as BrValidateUfSource, b as BrValidationErrorResponse, d as createBrValidateHandler, i as isBrValidatorTypeId } from './br-validate-BOiTO6lR.js';
4
+ import '@br-validators/core';
5
+
6
+ declare function requiresUf(typeId: BrValidatorTypeId): boolean;
7
+
8
+ /**
9
+ * Express middleware factory — validates request fields with @br-validators/core.
10
+ * Invalid input responds with HTTP 400 and `{ ok: false, field, code, message }`.
11
+ */
12
+ declare function brValidate(options: BrValidateOptions): RequestHandler;
13
+
14
+ export { BrValidateOptions, BrValidatorTypeId, brValidate, requiresUf };
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ import { createBrValidateHandler } from './chunk-OKPS2N5C.js';
2
+ export { createBrValidateHandler, requiresUf } from './chunk-OKPS2N5C.js';
3
+
4
+ // src/types.ts
5
+ var BR_VALIDATOR_TYPE_IDS = [
6
+ "cpf",
7
+ "cnpj",
8
+ "cep",
9
+ "placa",
10
+ "pis-pasep",
11
+ "pix",
12
+ "telefone",
13
+ "boleto",
14
+ "cartao-credito",
15
+ "cnh",
16
+ "renavam",
17
+ "nfe-chave",
18
+ "titulo-eleitor",
19
+ "processo-judicial",
20
+ "inscricao-estadual",
21
+ "inscricao-estadual-produtor-rural",
22
+ "brcode",
23
+ "rg"
24
+ ];
25
+ function isBrValidatorTypeId(value) {
26
+ return BR_VALIDATOR_TYPE_IDS.includes(value);
27
+ }
28
+
29
+ // src/index.ts
30
+ function brValidate(options) {
31
+ const handler = createBrValidateHandler(options);
32
+ return (req, res, next) => {
33
+ handler(req, res, next);
34
+ };
35
+ }
36
+
37
+ export { BR_VALIDATOR_TYPE_IDS, brValidate, isBrValidatorTypeId };
38
+ //# sourceMappingURL=index.js.map
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/index.ts"],"names":[],"mappings":";;;;AAuBO,IAAM,qBAAA,GAAwB;AAAA,EACnC,KAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA,gBAAA;AAAA,EACA,KAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,gBAAA;AAAA,EACA,mBAAA;AAAA,EACA,oBAAA;AAAA,EACA,mCAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF;AAsCO,SAAS,oBAAoB,KAAA,EAA2C;AAC7E,EAAA,OAAQ,qBAAA,CAA4C,SAAS,KAAK,CAAA;AACpE;;;AC1EO,SAAS,WAAW,OAAA,EAA4C;AACrE,EAAA,MAAM,OAAA,GAAU,wBAAwB,OAAO,CAAA;AAC/C,EAAA,OAAO,CAAC,GAAA,EAAK,GAAA,EAAK,IAAA,KAAS;AACzB,IAAA,OAAA,CAAQ,GAAA,EAAK,KAAK,IAAI,CAAA;AAAA,EACxB,CAAA;AACF","file":"index.js","sourcesContent":["import type { UfCode, ValidationErrorCode } from '@br-validators/core';\n\n/** Core validator type ids supported by `brValidate()`. */\nexport type BrValidatorTypeId =\n | 'cpf'\n | 'cnpj'\n | 'cep'\n | 'placa'\n | 'pis-pasep'\n | 'pix'\n | 'telefone'\n | 'boleto'\n | 'cartao-credito'\n | 'cnh'\n | 'renavam'\n | 'nfe-chave'\n | 'titulo-eleitor'\n | 'processo-judicial'\n | 'inscricao-estadual'\n | 'inscricao-estadual-produtor-rural'\n | 'brcode'\n | 'rg';\n\nexport const BR_VALIDATOR_TYPE_IDS = [\n 'cpf',\n 'cnpj',\n 'cep',\n 'placa',\n 'pis-pasep',\n 'pix',\n 'telefone',\n 'boleto',\n 'cartao-credito',\n 'cnh',\n 'renavam',\n 'nfe-chave',\n 'titulo-eleitor',\n 'processo-judicial',\n 'inscricao-estadual',\n 'inscricao-estadual-produtor-rural',\n 'brcode',\n 'rg',\n] as const satisfies readonly BrValidatorTypeId[];\n\nexport type BrValidateLocation = 'body' | 'query' | 'params';\n\nexport type BrValidateFieldSchema = Record<string, BrValidatorTypeId>;\n\nexport type BrValidateUfSource =\n | { from: BrValidateLocation; field: string }\n | { value: UfCode };\n\nexport type BrValidateOptions = {\n body?: BrValidateFieldSchema;\n query?: BrValidateFieldSchema;\n params?: BrValidateFieldSchema;\n /** Required for `inscricao-estadual`, `inscricao-estadual-produtor-rural`, and `rg`. */\n uf?: BrValidateUfSource;\n};\n\nexport type BrValidationErrorResponse = {\n ok: false;\n field: string;\n code: ValidationErrorCode;\n message: string;\n};\n\nexport type BrValidateRequest = {\n body?: object;\n query?: object;\n params?: object;\n};\n\nexport type BrValidateResponse = {\n status(code: number): BrValidateResponse;\n json(body: BrValidationErrorResponse): void;\n};\n\nexport type BrValidateNext = () => void;\n\nexport function isBrValidatorTypeId(value: string): value is BrValidatorTypeId {\n return (BR_VALIDATOR_TYPE_IDS as readonly string[]).includes(value);\n}\n\nexport type BrValidateFieldRef = {\n location: BrValidateLocation;\n field: string;\n typeId: BrValidatorTypeId;\n};\n","import type { RequestHandler } from 'express';\nimport { createBrValidateHandler } from './br-validate.js';\nimport type { BrValidateOptions } from './types.js';\n\n/**\n * Express middleware factory — validates request fields with @br-validators/core.\n * Invalid input responds with HTTP 400 and `{ ok: false, field, code, message }`.\n */\nexport function brValidate(options: BrValidateOptions): RequestHandler {\n const handler = createBrValidateHandler(options);\n return (req, res, next) => {\n handler(req, res, next);\n };\n}\n\nexport { createBrValidateHandler } from './br-validate.js';\nexport {\n BR_VALIDATOR_TYPE_IDS,\n isBrValidatorTypeId,\n type BrValidateFieldSchema,\n type BrValidateLocation,\n type BrValidateOptions,\n type BrValidateUfSource,\n type BrValidationErrorResponse,\n type BrValidatorTypeId,\n} from './types.js';\nexport { requiresUf } from './validator-registry.js';\n"]}
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@br-validators/express",
3
+ "version": "1.6.0",
4
+ "description": "Express and Fastify middleware for Brazilian document validators — delegates to @br-validators/core",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/AlexandreZanata/br-validators.git",
10
+ "directory": "packages/br-validators-express"
11
+ },
12
+ "homepage": "https://github.com/AlexandreZanata/br-validators/tree/main/packages/br-validators-express#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/AlexandreZanata/br-validators/issues"
15
+ },
16
+ "keywords": [
17
+ "brazil",
18
+ "express",
19
+ "fastify",
20
+ "middleware",
21
+ "validator",
22
+ "cpf",
23
+ "cnpj"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public",
27
+ "tag": "alpha"
28
+ },
29
+ "main": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "import": "./dist/index.js"
35
+ },
36
+ "./fastify": {
37
+ "types": "./dist/fastify.d.ts",
38
+ "import": "./dist/fastify.js"
39
+ }
40
+ },
41
+ "files": [
42
+ "dist",
43
+ "README.md"
44
+ ],
45
+ "peerDependencies": {
46
+ "express": "^4.21.0 || ^5.0.0",
47
+ "@br-validators/core": "1.6.0"
48
+ },
49
+ "peerDependenciesMeta": {
50
+ "express": {
51
+ "optional": true
52
+ }
53
+ },
54
+ "dependencies": {
55
+ "@br-validators/core": "1.6.0"
56
+ },
57
+ "devDependencies": {
58
+ "@types/express": "^5.0.3",
59
+ "@types/node": "^22.15.21",
60
+ "@vitest/coverage-v8": "^3.2.4",
61
+ "express": "^5.1.0",
62
+ "fastify": "^5.4.0",
63
+ "tsup": "^8.5.0",
64
+ "typescript": "^5.8.3",
65
+ "vitest": "^3.2.4"
66
+ },
67
+ "scripts": {
68
+ "build": "tsup",
69
+ "pretypecheck": "pnpm --filter @br-validators/core build",
70
+ "pretest": "pnpm --filter @br-validators/core build",
71
+ "pretest:coverage": "pnpm --filter @br-validators/core build",
72
+ "test": "vitest run",
73
+ "test:coverage": "vitest run --coverage",
74
+ "typecheck": "tsc --noEmit",
75
+ "lint": "eslint src tests --max-warnings 0"
76
+ }
77
+ }