@useinvio/nfse-sdk 3.0.0 → 3.1.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 (50) hide show
  1. package/README.md +115 -56
  2. package/dist/agent.d.ts +86 -0
  3. package/dist/agent.js +235 -0
  4. package/dist/agent.js.map +1 -0
  5. package/dist/certificate.d.ts +96 -0
  6. package/dist/certificate.js +218 -0
  7. package/dist/certificate.js.map +1 -0
  8. package/dist/certificateValidation.d.ts +11 -6
  9. package/dist/certificateValidation.js +23 -12
  10. package/dist/certificateValidation.js.map +1 -1
  11. package/dist/client.d.ts +4 -2
  12. package/dist/client.js +5 -4
  13. package/dist/client.js.map +1 -1
  14. package/dist/dpsJsonSchema.d.ts +17 -0
  15. package/dist/dpsJsonSchema.js +184 -0
  16. package/dist/dpsJsonSchema.js.map +1 -0
  17. package/dist/emissaoNota.d.ts +4 -4
  18. package/dist/emissaoNota.js +4 -3
  19. package/dist/emissaoNota.js.map +1 -1
  20. package/dist/fiscalDomains.d.ts +22 -0
  21. package/dist/fiscalDomains.js +99 -0
  22. package/dist/fiscalDomains.js.map +1 -0
  23. package/dist/fiscalValidation.js +21 -53
  24. package/dist/fiscalValidation.js.map +1 -1
  25. package/dist/index.d.ts +7 -2
  26. package/dist/index.js +4 -2
  27. package/dist/index.js.map +1 -1
  28. package/dist/jsonSchemaCheck.d.ts +12 -0
  29. package/dist/jsonSchemaCheck.js +70 -0
  30. package/dist/jsonSchemaCheck.js.map +1 -0
  31. package/dist/loadPfx.d.ts +2 -0
  32. package/dist/loadPfx.js +2 -1
  33. package/dist/loadPfx.js.map +1 -1
  34. package/dist/sefinClient.d.ts +10 -4
  35. package/dist/sefinClient.js +22 -4
  36. package/dist/sefinClient.js.map +1 -1
  37. package/dist/signXml.d.ts +3 -3
  38. package/dist/signXml.js +8 -6
  39. package/dist/signXml.js.map +1 -1
  40. package/dist/xmlInspection.js +10 -9
  41. package/dist/xmlInspection.js.map +1 -1
  42. package/dist/xsdValidation.d.ts +17 -5
  43. package/dist/xsdValidation.js +75 -67
  44. package/dist/xsdValidation.js.map +1 -1
  45. package/examples/README.md +1 -1
  46. package/examples/client-resource.ts +3 -5
  47. package/examples/emit-homologation.ts +3 -4
  48. package/examples/handle-errors.ts +3 -3
  49. package/llms.txt +15 -5
  50. package/package.json +9 -4
@@ -1,8 +1,7 @@
1
- import { execFileSync } from 'node:child_process';
2
- import { cpSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
3
- import { tmpdir } from 'node:os';
1
+ import { readdirSync, readFileSync } from 'node:fs';
4
2
  import { join } from 'node:path';
5
3
  import { fileURLToPath } from 'node:url';
4
+ import { ParseOption, XmlBufferInputProvider, XmlDocument, XmlParseError, XmlValidateError, XsdValidator, xmlRegisterInputProvider, } from 'libxml2-wasm';
6
5
  /** The DPS XML violates the NFS-e v1.01 XSD. This is a fiscal payload problem. */
7
6
  export class DpsXsdValidationError extends Error {
8
7
  details;
@@ -13,87 +12,96 @@ export class DpsXsdValidationError extends Error {
13
12
  }
14
13
  }
15
14
  /**
16
- * `xmllint` could not be run to completion (missing binary, spawn failure, or
17
- * an unexpected crash without stderr). This is an infrastructure problem, not
18
- * proof that the XML is fiscally invalid, and callers must not treat it as a
15
+ * The embedded XSD engine (libxml2 compiled to WebAssembly) could not load the
16
+ * official schemas or crashed. This is an infrastructure problem, not proof
17
+ * that the XML is fiscally invalid, and callers must not treat it as a
19
18
  * permanent rejection.
20
19
  */
21
- export class XmllintUnavailableError extends Error {
20
+ export class XsdEngineUnavailableError extends Error {
22
21
  cause;
23
22
  constructor(message, cause) {
24
23
  super(message);
25
24
  this.cause = cause;
26
- this.name = 'XmllintUnavailableError';
25
+ this.name = 'XsdEngineUnavailableError';
27
26
  }
28
27
  }
29
- function isExecFileSyncFailure(error) {
30
- return typeof error === 'object' && error !== null;
28
+ /**
29
+ * @deprecated Since 3.1.0 the SDK no longer runs the `xmllint` binary.
30
+ * Kept as an alias so existing `instanceof XmllintUnavailableError` checks still work.
31
+ */
32
+ export const XmllintUnavailableError = XsdEngineUnavailableError;
33
+ /** Virtual URL scheme for the bundled schemas, so includes never touch disk or network. */
34
+ const SCHEMA_URL_PREFIX = 'nfse-sdk-xsd://v1.01/';
35
+ const ENTRY_SCHEMA = 'DPS_v1.01.xsd';
36
+ /** Never load DTDs, external entities or network resources while parsing. */
37
+ export const SAFE_PARSE_OPTIONS = ParseOption.XML_PARSE_NONET | ParseOption.XML_PARSE_NO_XXE;
38
+ let compiledValidator;
39
+ function schemaSourceDir() {
40
+ return fileURLToPath(new URL('../schemas/nfse/v1.01/Schemas/1.01/', import.meta.url));
31
41
  }
32
- function toText(value) {
33
- if (value === null || value === undefined)
34
- return '';
35
- return Buffer.isBuffer(value) ? value.toString('utf8') : String(value);
42
+ function loadSchemaBuffers() {
43
+ const dir = schemaSourceDir();
44
+ const encoder = new TextEncoder();
45
+ const buffers = {};
46
+ for (const file of readdirSync(dir)) {
47
+ if (!file.endsWith('.xsd'))
48
+ continue;
49
+ let text = readFileSync(join(dir, file), 'utf8');
50
+ if (file === 'tiposSimples_v1.01.xsd') {
51
+ // libxml2 treats ^/$ literally in XSD regexes. The official package ships
52
+ // one JavaScript-style anchor, so normalize that expression in memory.
53
+ text = text.replace('<xs:pattern value="^0{0,4}\\d{1,5}$"/>', '<xs:pattern value="0{0,4}\\d{1,5}"/>');
54
+ }
55
+ buffers[`${SCHEMA_URL_PREFIX}${file}`] = encoder.encode(text);
56
+ }
57
+ return buffers;
36
58
  }
37
- function describeSpawnFailure(error) {
38
- const parts = [];
39
- if (error.message)
40
- parts.push(error.message);
41
- if (error.code)
42
- parts.push(`code=${error.code}`);
43
- if (error.path)
44
- parts.push(`path=${error.path}`);
45
- if (error.spawnargs?.length)
46
- parts.push(`spawnargs=${error.spawnargs.join(' ')}`);
47
- const stdout = toText(error.stdout).trim();
48
- if (stdout)
49
- parts.push(`stdout=${stdout}`);
50
- const stderr = toText(error.stderr).trim();
51
- if (stderr)
52
- parts.push(`stderr=${stderr}`);
53
- return parts.length ? parts.join(' | ') : 'Falha desconhecida ao executar xmllint.';
59
+ /** Compiles the official schemas once per process; later calls reuse the validator. */
60
+ function getValidator() {
61
+ if (compiledValidator)
62
+ return compiledValidator;
63
+ let schemaDoc;
64
+ try {
65
+ const buffers = loadSchemaBuffers();
66
+ const entry = buffers[`${SCHEMA_URL_PREFIX}${ENTRY_SCHEMA}`];
67
+ if (!entry)
68
+ throw new Error(`${ENTRY_SCHEMA} nao encontrado em ${schemaSourceDir()}`);
69
+ xmlRegisterInputProvider(new XmlBufferInputProvider(buffers));
70
+ schemaDoc = XmlDocument.fromBuffer(entry, { url: `${SCHEMA_URL_PREFIX}${ENTRY_SCHEMA}`, option: SAFE_PARSE_OPTIONS });
71
+ compiledValidator = XsdValidator.fromDoc(schemaDoc);
72
+ return compiledValidator;
73
+ }
74
+ catch (error) {
75
+ throw new XsdEngineUnavailableError(`Nao foi possivel carregar os XSD oficiais v1.01: ${error instanceof Error ? error.message : String(error)}`, error);
76
+ }
77
+ finally {
78
+ // The validator keeps its own compiled copy of the schema.
79
+ schemaDoc?.dispose();
80
+ }
54
81
  }
55
- function schemaSourceDir() {
56
- return fileURLToPath(new URL('../schemas/nfse/v1.01/Schemas/1.01/', import.meta.url));
82
+ function detailsOf(error) {
83
+ const details = error.details.map((detail) => detail.message.trim()).filter(Boolean);
84
+ return details.length ? details : [error.message.trim() || error.name];
57
85
  }
58
- /** Validates a generated DPS against the official v1.01 schema before signing. */
86
+ /**
87
+ * Validates a DPS against the official v1.01 schema before signing.
88
+ * Runs in-process (libxml2 in WebAssembly): no `xmllint`, no temp files, no network.
89
+ */
59
90
  export function validateDpsXmlAgainstXsd(xml) {
60
- const workDir = mkdtempSync(join(tmpdir(), 'nfse-sdk-xsd-'));
61
- const schemasDir = join(workDir, 'schemas');
91
+ const validator = getValidator();
92
+ let doc;
62
93
  try {
63
- cpSync(schemaSourceDir(), schemasDir, { recursive: true });
64
- // libxml2 treats ^/$ literally in XSD regexes. The official package ships
65
- // one JavaScript-style anchor, so normalize that expression in our copy.
66
- const simpleTypesPath = join(schemasDir, 'tiposSimples_v1.01.xsd');
67
- const simpleTypes = readFileSync(simpleTypesPath, 'utf8').replace('<xs:pattern value="^0{0,4}\\d{1,5}$"/>', '<xs:pattern value="0{0,4}\\d{1,5}"/>');
68
- writeFileSync(simpleTypesPath, simpleTypes);
69
- const xmlPath = join(workDir, 'dps.xml');
70
- writeFileSync(xmlPath, xml);
71
- try {
72
- execFileSync('xmllint', ['--noout', '--schema', join(schemasDir, 'DPS_v1.01.xsd'), xmlPath], {
73
- encoding: 'utf8',
74
- stdio: ['ignore', 'pipe', 'pipe'],
75
- });
76
- }
77
- catch (error) {
78
- if (!isExecFileSyncFailure(error)) {
79
- throw new XmllintUnavailableError(`Falha ao executar xmllint: ${String(error)}`, error);
80
- }
81
- if (error.code === 'ENOENT') {
82
- throw new XmllintUnavailableError(`xmllint nao encontrado no ambiente de execucao (path=${error.path ?? 'xmllint'}). ` +
83
- 'Instale o pacote libxml2/xmllint antes de validar o XSD.', error);
84
- }
85
- const stderrText = toText(error.stderr).trim();
86
- if (stderrText) {
87
- const details = stderrText.split('\n').map((line) => line.trim()).filter(Boolean);
88
- throw new DpsXsdValidationError(details.length ? details : [stderrText]);
89
- }
90
- // xmllint failed but produced no stderr: do not mask this as an XML
91
- // schema violation, since we have no evidence about the XML content.
92
- throw new XmllintUnavailableError(`xmllint falhou sem stderr: ${describeSpawnFailure(error)}`, error);
94
+ doc = XmlDocument.fromString(xml, { option: SAFE_PARSE_OPTIONS });
95
+ validator.validate(doc);
96
+ }
97
+ catch (error) {
98
+ if (error instanceof XmlValidateError || error instanceof XmlParseError) {
99
+ throw new DpsXsdValidationError(detailsOf(error));
93
100
  }
101
+ throw new XsdEngineUnavailableError(`Falha no motor de validacao XSD: ${error instanceof Error ? error.message : String(error)}`, error);
94
102
  }
95
103
  finally {
96
- rmSync(workDir, { recursive: true, force: true });
104
+ doc?.dispose();
97
105
  }
98
106
  }
99
107
  //# sourceMappingURL=xsdValidation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"xsdValidation.js","sourceRoot":"","sources":["../xsdValidation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,kFAAkF;AAClF,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAClB;IAA5B,YAA4B,OAAiB;QAC3C,KAAK,CAAC,yCAAyC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAD3C,YAAO,GAAP,OAAO,CAAU;QAE3C,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAG9B;IAFlB,YACE,OAAe,EACC,KAAc;QAE9B,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,UAAK,GAAL,KAAK,CAAS;QAG9B,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAWD,SAAS,qBAAqB,CAAC,KAAc;IAC3C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AACrD,CAAC;AAED,SAAS,MAAM,CAAC,KAAyC;IACvD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACrD,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,oBAAoB,CAAC,KAA0B;IACtD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,CAAC,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7C,IAAI,KAAK,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACjD,IAAI,KAAK,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACjD,IAAI,KAAK,CAAC,SAAS,EAAE,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,aAAa,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClF,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,IAAI,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,MAAM,EAAE,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,IAAI,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,MAAM,EAAE,CAAC,CAAC;IAC3C,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,yCAAyC,CAAC;AACtF,CAAC;AAED,SAAS,eAAe;IACtB,OAAO,aAAa,CAAC,IAAI,GAAG,CAAC,qCAAqC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACxF,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,wBAAwB,CAAC,GAAW;IAClD,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;IAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,CAAC,eAAe,EAAE,EAAE,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE3D,0EAA0E;QAC1E,yEAAyE;QACzE,MAAM,eAAe,GAAG,IAAI,CAAC,UAAU,EAAE,wBAAwB,CAAC,CAAC;QACnE,MAAM,WAAW,GAAG,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,OAAO,CAC/D,wCAAwC,EACxC,sCAAsC,CACvC,CAAC;QACF,aAAa,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;QAE5C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACzC,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC5B,IAAI,CAAC;YACH,YAAY,CAAC,SAAS,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,EAAE,OAAO,CAAC,EAAE;gBAC3F,QAAQ,EAAE,MAAM;gBAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;aAClC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAClC,MAAM,IAAI,uBAAuB,CAAC,8BAA8B,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC1F,CAAC;YAED,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC5B,MAAM,IAAI,uBAAuB,CAC/B,wDAAwD,KAAK,CAAC,IAAI,IAAI,SAAS,KAAK;oBAClF,0DAA0D,EAC5D,KAAK,CACN,CAAC;YACJ,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;YAC/C,IAAI,UAAU,EAAE,CAAC;gBACf,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAClF,MAAM,IAAI,qBAAqB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;YAC3E,CAAC;YAED,oEAAoE;YACpE,qEAAqE;YACrE,MAAM,IAAI,uBAAuB,CAAC,8BAA8B,oBAAoB,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACxG,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"xsdValidation.js","sourceRoot":"","sources":["../xsdValidation.ts"],"names":[],"mappings":"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"}
@@ -12,4 +12,4 @@ The payloads in `payloads.ts` are shared by these examples and exercised by the
12
12
  - [`client-resource.ts`](./client-resource.ts): use `NfseClient` with certificate and defaults configured once.
13
13
  - [`handle-errors.ts`](./handle-errors.ts): normalize SEFIN rejection details for your application.
14
14
 
15
- The examples assume Node.js 20+ and a valid A1/PFX certificate. They are intentionally explicit about fiscal fields; the SDK does not infer municipal taxation, withholding, CST or total tax burden.
15
+ The examples assume Node.js 20+ and a valid A1/PFX certificate, loaded with `NfseCertificate.fromEnv()` from `NFSE_CERT_PATH` (or `NFSE_CERT_BASE64`) and `NFSE_CERT_PASSWORD` (or `NFSE_CERT_PASSWORD_FILE`). They are intentionally explicit about fiscal fields; the SDK does not infer municipal taxation, withholding, CST or total tax burden.
@@ -1,12 +1,10 @@
1
- import { NfseClient } from '@useinvio/nfse-sdk';
1
+ import { NfseCertificate, NfseClient } from '@useinvio/nfse-sdk';
2
2
  import { nationalInvoice } from './payloads.js';
3
3
 
4
4
  const client = new NfseClient({
5
5
  environment: 'sandbox',
6
- certificate: {
7
- content: process.env.NFSE_CERTIFICATE_BASE64!,
8
- password: process.env.NFSE_CERTIFICATE_PASSWORD!,
9
- },
6
+ // NFSE_CERT_PATH or NFSE_CERT_BASE64, plus NFSE_CERT_PASSWORD or NFSE_CERT_PASSWORD_FILE
7
+ certificate: NfseCertificate.fromEnv(),
10
8
  defaults: { prestador: nationalInvoice.prestador, servico: nationalInvoice.servico },
11
9
  });
12
10
 
@@ -1,11 +1,10 @@
1
- import { EmitirNotaError, emitirNfse, loadPfx } from '@useinvio/nfse-sdk';
1
+ import { EmitirNotaError, emitirNfse, NfseCertificate } from '@useinvio/nfse-sdk';
2
2
  import { nationalInvoice } from './payloads.js';
3
3
 
4
- const pfx = loadPfx('./certificado.pfx', process.env.PFX_PASSWORD!);
5
-
4
+ const certificate = NfseCertificate.fromEnv(); // NFSE_CERT_PATH + NFSE_CERT_PASSWORD
6
5
 
7
6
  try {
8
- const resultado = await emitirNfse(nationalInvoice, pfx);
7
+ const resultado = await emitirNfse(nationalInvoice, certificate);
9
8
  console.log(resultado.chaveAcesso);
10
9
  console.log(resultado.nfseXml);
11
10
  } catch (error) {
@@ -1,11 +1,11 @@
1
- import { EmitirNotaError, emitirNfse, loadPfx, type DpsJsonRequest } from '@useinvio/nfse-sdk';
1
+ import { EmitirNotaError, emitirNfse, NfseCertificate, type DpsJsonRequest } from '@useinvio/nfse-sdk';
2
2
  import { nationalInvoice } from './payloads.js';
3
3
 
4
4
  async function emitWithStructuredErrors(nota: DpsJsonRequest) {
5
- const pfx = loadPfx('./certificado.pfx', process.env.PFX_PASSWORD!);
5
+ const certificate = NfseCertificate.fromEnv(); // NFSE_CERT_PATH + NFSE_CERT_PASSWORD
6
6
 
7
7
  try {
8
- return await emitirNfse(nota, pfx);
8
+ return await emitirNfse(nota, certificate);
9
9
  } catch (error) {
10
10
  if (!(error instanceof EmitirNotaError)) throw error;
11
11
 
package/llms.txt CHANGED
@@ -20,10 +20,13 @@ It is not a fiscal decision engine. Do not infer tax codes, accounting rules, te
20
20
  - `emitirNfse(input, pfx, options?)`: issue an invoice from a DPS XML string or `DpsJsonRequest`.
21
21
  - `buildDpsFromJson(input)`: build unsigned DPS XML from declarative JSON.
22
22
  - `buildDpsId(prestador, nDPS, serie?)`: derive the 45-character DPS Id.
23
- - `loadPfx(...)` and `loadPfxFromBuffer(...)`: extract key/certificate material from an A1/PFX certificate.
23
+ - `NfseCertificate`: opaque A1 certificate for signing and mTLS (`fromEnv`, `fromFile`, `fromBase64`, `fromPfx`, `fromPem`). Exposes only metadata (CNPJ/CPF, validity, fingerprint); the private key lives outside the object and never appears in logs or JSON. Env convention: `NFSE_CERT_PATH` or `NFSE_CERT_BASE64`, plus `NFSE_CERT_PASSWORD` or `NFSE_CERT_PASSWORD_FILE`.
24
+ - `loadPfx(...)` and `loadPfxFromBuffer(...)`: legacy loaders that return the key as PEM; prefer `NfseCertificate`.
24
25
  - `consultarNfse(...)`, `enviarEvento(...)`, `extrairErros(...)`: lower-level SEFIN helpers.
25
26
  - `setSefinRequestObserver(...)` and `createSefinLatencyTracker(...)`: observe SEFIN round-trip latency when `NFSE_SEFIN_LATENCY_METRICS` is enabled; percentiles require `includePercentiles: true`.
26
27
  - `gzipBase64(...)`, `gunzipBase64(...)`, `signDps(...)`, `verifyDps(...)`: protocol utilities for custom flows.
28
+ - `DPS_JSON_REQUEST_SCHEMA`: JSON Schema 2020-12 for the canonical `DpsJsonRequest` (formats and code domains; cross-field rules stay in `validateDpsJsonRequest`).
29
+ - `@useinvio/nfse-sdk/agent`: framework-neutral agent/MCP tools (`validate_dps`, `build_dps_xml`, `get_nfse`) and `toAgentIssues(error)`. Certificate and environment come from the host context, never from tool input.
27
30
 
28
31
  ## File Map
29
32
 
@@ -33,9 +36,15 @@ It is not a fiscal decision engine. Do not infer tax codes, accounting rules, te
33
36
  - `fiscalValidation.ts`: structural and layout-oriented validation for the JSON input. This intentionally rejects unsupported or ambiguous fiscal shapes.
34
37
  - `sefinClient.ts`: HTTPS mTLS requests to SEFIN, latency observation, response parsing, error normalization, invoice query, issue transport, and event transport.
35
38
  - `config.ts`: SEFIN base URLs, environment names, and `tpAmb` mapping.
36
- - `loadPfx.ts`: PFX/A1 certificate decoding with `node-forge`.
39
+ - `certificate.ts`: `NfseCertificate`, ICP-Brasil CNPJ/CPF extraction, env loading, per-certificate mTLS agent, and the internal `resolveCredentials` used by signing and transport.
40
+ - `loadPfx.ts`: PFX/A1 certificate decoding with `node-forge` (shared parser plus legacy loaders).
41
+ - `xsdValidation.ts`: in-process XSD validation with libxml2 compiled to WebAssembly; schemas compiled once per process.
37
42
  - `signXml.ts`: XMLDSIG signing and verification helpers.
38
43
  - `gzipB64.ts`: GZip/Base64 helpers.
44
+ - `fiscalDomains.ts`: code domains shared by the validator and the JSON Schema.
45
+ - `dpsJsonSchema.ts`: JSON Schema for `DpsJsonRequest`; `satisfies` checks fail the build when a type gains a field the schema does not describe.
46
+ - `jsonSchemaCheck.ts`: internal validator for the portable keyword subset the schema may use.
47
+ - `agent.ts`: agent tool definitions, unified `NfseAgentIssue` shape, and error mapping.
39
48
 
40
49
  ## Core Data Shape
41
50
 
@@ -63,17 +72,18 @@ Keep values as strings when they represent fiscal codes, identifiers, decimals,
63
72
  - Currency discrepancies are warnings; explicit values retain priority. Service amounts must remain positive after rounding; all foreign amounts are serialized with two decimals.
64
73
  - `validateDpsJsonRequest` returns independent normalized data, errors in `issues`, and non-blocking `warnings`.
65
74
  - `EmitirNotaError` covers SEFIN rejection and incomplete/invalid HTTP 2xx authorization responses, including missing/invalid/conflicting 50-digit access keys. Reconcile before retrying; the SDK never retries automatically.
66
- - `sefinClient.ts` uses PEM key/cert material for mTLS, not the raw PFX in the Node TLS handshake.
75
+ - `sefinClient.ts` uses a per-certificate `https.Agent` (from `NfseCertificate`) or PEM key/cert (legacy `PfxMaterial`) for mTLS, never the raw PFX in the Node TLS handshake. Access keys are validated as 50 digits before any request (`ChaveAcessoInvalidaError`).
76
+ - XSD validation needs no system `xmllint`; it runs in WebAssembly. `XmllintUnavailableError` is a deprecated alias of `XsdEngineUnavailableError`.
67
77
  - SEFIN latency metrics are off by default, enabled through `NFSE_SEFIN_LATENCY_METRICS`, and emitted for the external request only; keep them separate from API route latency when integrating observability.
68
78
 
69
79
  ## Change Guidance for LLMs
70
80
 
71
81
  - Preserve the public API names exported by `index.ts` unless the task explicitly asks for a breaking change.
72
82
  - Prefer adding or adjusting focused tests in `test/` when changing XML generation, validation, signing, transport parsing, or client defaults.
73
- - When adding support for a new NFS-e layout field, update the TypeScript interface, validation rules, builder output, docs/examples, and tests together.
83
+ - When adding support for a new NFS-e layout field, update the TypeScript interface, validation rules, JSON Schema (`dpsJsonSchema.ts`), builder output, docs/examples, and tests together.
74
84
  - Do not add fiscal assumptions to make examples pass. Required fiscal choices should stay explicit in user input.
75
85
  - Be careful with XML ordering. The generated order should follow the SEFIN schema, and tests may compare XML snippets.
76
- - Do not hand-wave certificate handling. PFX content may arrive as a `Buffer` or base64 string.
86
+ - Do not hand-wave certificate handling. Accept `CertificateInput` (`NfseCertificate | PfxMaterial`) and go through `resolveCredentials`; never log, serialize, or return key material, the PFX bytes, or the password.
77
87
  - Network calls to SEFIN should stay isolated in `sefinClient.ts` so tests can mock transport boundaries.
78
88
 
79
89
  ## Useful Commands
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useinvio/nfse-sdk",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "TypeScript SDK for Brazil's national NFS-e: JSON to DPS/XML, XMLDSIG, GZip/Base64, mTLS and SEFIN errors.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -10,6 +10,10 @@
10
10
  "types": "./dist/index.d.ts",
11
11
  "import": "./dist/index.js"
12
12
  },
13
+ "./agent": {
14
+ "types": "./dist/agent.d.ts",
15
+ "import": "./dist/agent.js"
16
+ },
13
17
  "./package.json": "./package.json"
14
18
  },
15
19
  "files": [
@@ -62,9 +66,10 @@
62
66
  "access": "public"
63
67
  },
64
68
  "dependencies": {
65
- "@xmldom/xmldom": "^0.8.13",
66
- "node-forge": "^1.3.1",
67
- "xml-crypto": "^6.0.0"
69
+ "@xmldom/xmldom": "^0.8.15",
70
+ "libxml2-wasm": "^0.7.2",
71
+ "node-forge": "^1.4.3",
72
+ "xml-crypto": "^6.4.0"
68
73
  },
69
74
  "devDependencies": {
70
75
  "@types/node": "^22.13.14",