@useinvio/nfse-sdk 3.1.0 → 3.2.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 (95) hide show
  1. package/CHANGELOG.md +176 -0
  2. package/README.en.md +146 -0
  3. package/README.md +76 -576
  4. package/dist/agent.d.ts +46 -1
  5. package/dist/agent.js +320 -4
  6. package/dist/agent.js.map +1 -1
  7. package/dist/cli.d.ts +2 -0
  8. package/dist/cli.js +520 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/cliBin.d.ts +2 -0
  11. package/dist/cliBin.js +6 -0
  12. package/dist/cliBin.js.map +1 -0
  13. package/dist/cliExample.d.ts +6 -0
  14. package/dist/cliExample.js +29 -0
  15. package/dist/cliExample.js.map +1 -0
  16. package/dist/client.d.ts +47 -2
  17. package/dist/client.js +36 -6
  18. package/dist/client.js.map +1 -1
  19. package/dist/config.d.ts +3 -0
  20. package/dist/config.js +8 -0
  21. package/dist/config.js.map +1 -1
  22. package/dist/consultas.d.ts +34 -0
  23. package/dist/consultas.js +61 -0
  24. package/dist/consultas.js.map +1 -0
  25. package/dist/dpsJson.js +1 -41
  26. package/dist/dpsJson.js.map +1 -1
  27. package/dist/emissaoNota.d.ts +8 -3
  28. package/dist/emissaoNota.js +6 -3
  29. package/dist/emissaoNota.js.map +1 -1
  30. package/dist/eventoJson.d.ts +76 -0
  31. package/dist/eventoJson.js +128 -0
  32. package/dist/eventoJson.js.map +1 -0
  33. package/dist/eventosNfse.d.ts +38 -0
  34. package/dist/eventosNfse.js +73 -0
  35. package/dist/eventosNfse.js.map +1 -0
  36. package/dist/gzipB64.d.ts +5 -0
  37. package/dist/gzipB64.js +12 -0
  38. package/dist/gzipB64.js.map +1 -1
  39. package/dist/index.d.ts +17 -7
  40. package/dist/index.js +9 -4
  41. package/dist/index.js.map +1 -1
  42. package/dist/mcpCli.d.ts +2 -0
  43. package/dist/mcpCli.js +7 -0
  44. package/dist/mcpCli.js.map +1 -0
  45. package/dist/mcpServer.d.ts +49 -0
  46. package/dist/mcpServer.js +159 -0
  47. package/dist/mcpServer.js.map +1 -0
  48. package/dist/nfseXml.d.ts +48 -0
  49. package/dist/nfseXml.js +86 -0
  50. package/dist/nfseXml.js.map +1 -0
  51. package/dist/rejeicoes.d.ts +50 -0
  52. package/dist/rejeicoes.js +62 -0
  53. package/dist/rejeicoes.js.map +1 -0
  54. package/dist/rejeicoesCatalog.d.ts +10 -0
  55. package/dist/rejeicoesCatalog.js +4449 -0
  56. package/dist/rejeicoesCatalog.js.map +1 -0
  57. package/dist/sefinClient.d.ts +100 -6
  58. package/dist/sefinClient.js +211 -19
  59. package/dist/sefinClient.js.map +1 -1
  60. package/dist/signXml.js +9 -1
  61. package/dist/signXml.js.map +1 -1
  62. package/dist/testing.d.ts +80 -0
  63. package/dist/testing.js +285 -0
  64. package/dist/testing.js.map +1 -0
  65. package/dist/xmlBuild.d.ts +11 -0
  66. package/dist/xmlBuild.js +44 -0
  67. package/dist/xmlBuild.js.map +1 -0
  68. package/dist/xmlInspection.d.ts +1 -1
  69. package/dist/xmlInspection.js.map +1 -1
  70. package/dist/xsdValidation.d.ts +7 -0
  71. package/dist/xsdValidation.js +37 -15
  72. package/dist/xsdValidation.js.map +1 -1
  73. package/docs/README.md +47 -0
  74. package/docs/REGRAS_NEGOCIO_EMISSAO.md +8 -8
  75. package/docs/conceitos/como-funciona.md +87 -0
  76. package/docs/guias/adn.md +51 -0
  77. package/docs/guias/agentes-ia.md +111 -0
  78. package/docs/guias/cancelar.md +70 -0
  79. package/docs/guias/certificado.md +88 -0
  80. package/docs/guias/cli.md +68 -0
  81. package/docs/guias/consultar.md +54 -0
  82. package/docs/guias/emitir.md +172 -0
  83. package/docs/guias/recuperar-emissao.md +33 -0
  84. package/docs/guias/rejeicoes.md +70 -0
  85. package/docs/guias/testes.md +79 -0
  86. package/docs/guias/timeouts.md +33 -0
  87. package/docs/referencia/ambientes.md +35 -0
  88. package/docs/referencia/api.md +137 -0
  89. package/docs/referencia/erros.md +55 -0
  90. package/docs/tutoriais/primeira-nfse.md +130 -0
  91. package/examples/README.md +2 -0
  92. package/examples/cancel-nfse.ts +29 -0
  93. package/examples/recover-emission.ts +29 -0
  94. package/llms.txt +97 -92
  95. package/package.json +23 -3
@@ -0,0 +1,137 @@
1
+ # Referência da API
2
+
3
+ Tudo é importado da raiz do pacote, exceto as ferramentas de agente
4
+ (`@useinvio/nfse-sdk/agent`). `certificado` é um `NfseCertificate` (ou o legado
5
+ `PfxMaterial`); `ambiente` é `'restrita' | 'producao'` e o padrão é `restrita`;
6
+ `options` é [`SefinRequestOptions`](../guias/timeouts.md).
7
+
8
+ ## Cliente
9
+
10
+ | API | Descrição |
11
+ |---|---|
12
+ | `new NfseClient({ environment?, certificate, defaults?, request? })` | Configura certificado, ambiente, defaults do JSON e opções de transporte uma vez. |
13
+ | `client.invoices.create(input)` / `.buildDpsJson(input)` | Emite, ou só combina o JSON com os defaults. |
14
+ | `client.invoices.retrieve(chave)` / `.get(chave)` | Consulta tipada / crua. |
15
+ | `client.invoices.getByDpsId(dpsId)` / `.recover(dpsId)` | Consulta pela DPS / recuperação após timeout. |
16
+ | `client.invoices.cancel(input)` / `.cancelBySubstitution(input)` | Eventos e101101 / e105102. |
17
+ | `client.invoices.danfse(chave)` | PDF do DANFSe. |
18
+ | `client.events.get(chave, tpEvento, nSeq?)` / `.listByAccessKey(chave)` | Eventos (SEFIN / ADN). |
19
+ | `client.distribution.byNsu(nsu, opts?)` | Distribuição por NSU (ADN). |
20
+ | `client.municipalParameters.agreement/rate/rateHistory/specialRegimes/withholdings/benefit` | Parâmetros municipais (ADN). |
21
+
22
+ ## Emissão
23
+
24
+ | Função | Descrição |
25
+ |---|---|
26
+ | `emitirNfse(input, certificado, options?)` | Emite a partir de XML ou JSON. Retorna `ResultadoEmissaoNota`. |
27
+ | `prepararNota(input, certificado, options?)` | Valida, assina e verifica a assinatura, sem enviar. Retorna `NotaPreparada`. |
28
+ | `transmitirNotaPreparada(nota, certificado, options?)` | Envia uma `NotaPreparada`. |
29
+ | `buildDpsFromJson(nota)` / `buildDpsId(...)` | Monta o XML não assinado / o Id de 45 caracteres. |
30
+ | `validateDpsJsonRequest(nota)` / `assertValidDpsJsonRequest(nota)` | Valida o JSON, sem lançar / lançando `DpsFiscalValidationError`. |
31
+ | `validateDpsXmlAgainstXsd(xml)` | Valida a DPS contra o XSD oficial v1.01. |
32
+ | `DPS_JSON_REQUEST_SCHEMA` | JSON Schema 2020-12 do `DpsJsonRequest`. |
33
+
34
+ ## Consulta
35
+
36
+ | Função | Descrição |
37
+ |---|---|
38
+ | `obterNfse(chave, certificado, ambiente?, options?)` | `GET /nfse/{chave}` decodificado: `{ chaveAcesso, nfseXml, resumo }`. |
39
+ | `recuperarNfsePorDps(dpsId, certificado, ambiente?, options?)` | `GET /dps/{id}` + `GET /nfse/{chave}`; `null` se a DPS não existe. |
40
+ | `lerNfse(xml)` | Lê um XML de NFS-e autorizada em `NfseResumo`. |
41
+ | `decodificarRespostaNfse(status, body)` | Decodifica uma resposta crua de `GET /nfse/{chave}`. |
42
+ | `consultarNfse(...)` / `consultarDps(...)` | Respostas cruas `{ status, body }`. |
43
+ | `baixarDanfse(chave, certificado, ambiente?, options?)` | PDF do DANFSe (ADN). |
44
+
45
+ ## Eventos
46
+
47
+ | Função | Descrição |
48
+ |---|---|
49
+ | `cancelarNfse(input, certificado, options?)` | Cancelamento e101101. |
50
+ | `cancelarNfsePorSubstituicao(input, certificado, options?)` | Cancelamento por substituição e105102. |
51
+ | `buildCancelamentoFromJson(input)` / `buildCancelamentoPorSubstituicaoFromJson(input)` | Monta o pedido sem assinar. |
52
+ | `registrarEvento(built, certificado, options?)` | Valida, assina e envia um pedido montado. |
53
+ | `validatePedRegEventoXmlAgainstXsd(xml)` | Valida um pedido de evento contra o XSD. |
54
+ | `consultarEvento(chave, tpEvento, certificado, ambiente?, { nSeqEvento? })` | Consulta um evento (SEFIN). |
55
+ | `enviarEvento(xmlGZipB64, certificado, chave, ambiente?)` | Envia um pedido já assinado e compactado. |
56
+ | `TP_EVENTO`, `MOTIVO_CANCELAMENTO`, `MOTIVO_SUBSTITUICAO` | Códigos com nomes legíveis. |
57
+
58
+ ## ADN
59
+
60
+ `distribuirDfePorNsu`, `consultarEventosPorChaveAdn`, `consultarConvenio`,
61
+ `consultarAliquota`, `consultarHistoricoAliquotas`, `consultarRegimesEspeciais`,
62
+ `consultarRetencoes`, `consultarBeneficio`. Assinaturas e endpoints em
63
+ [Distribuição e parâmetros municipais](../guias/adn.md).
64
+
65
+ ## Linha de comando
66
+
67
+ `nfse` (bin): `init`, `doctor`, `cert`, `validate`, `xml`, `emit`, `get`, `danfse`,
68
+ `cancel`, `recover`, `explain`, `mcp`. Veja [Usar pelo terminal](../guias/cli.md).
69
+
70
+ ## Rejeições
71
+
72
+ | Função | Descrição |
73
+ |---|---|
74
+ | `explicarRejeicao(codigoOuErro)` | Mensagem, regra, campo e nível oficiais de um código, ou `conhecida: false`. |
75
+ | `explicarErros(erros)` | Explica todos os erros de uma rejeição. |
76
+ | `buscarRejeicao(codigo)` / `listarRejeicoes()` | Acesso direto ao catálogo oficial. |
77
+ | `REJEICOES_FONTES` | Anexos oficiais usados no catálogo, com URL. |
78
+
79
+ Uma página por código: [docs/rejeicoes](../rejeicoes/README.md).
80
+
81
+ ## Testes (`@useinvio/nfse-sdk/testing`)
82
+
83
+ | Função | Descrição |
84
+ |---|---|
85
+ | `createTestCertificate(opts?)` | Certificado A1 de teste com CNPJ/CPF nos campos ICP-Brasil. |
86
+ | `installMockSefin(opts?)` | SEFIN e ADN simulados no processo; `rejectNext`, `failNext`, `dropResponseNext`, `route`, `restore`. |
87
+
88
+ Guia: [Testar sem certificado](../guias/testes.md).
89
+
90
+ ## Agentes e MCP
91
+
92
+ | API | Descrição |
93
+ |---|---|
94
+ | `nfseAgentTools` (`/agent`) | Ferramentas só de leitura. |
95
+ | `createNfseAgentToolkit({ allowWrite?, confirmationTtlMs? })` (`/agent`) | Leitura + emissão e cancelamento em duas etapas. |
96
+ | `toAgentIssues(error)` (`/agent`) | Converte erros do SDK em issues para o modelo. |
97
+ | `createNfseMcpServer(opts)` / `runNfseMcpStdio(opts?)` (`/mcp`) | Servidor MCP sem dependências. |
98
+ | `nfse-mcp` (bin) | `npx -y @useinvio/nfse-mcp` ou `npx -y -p @useinvio/nfse-sdk nfse-mcp`. |
99
+
100
+ Guia: [Agentes de IA e MCP](../guias/agentes-ia.md).
101
+
102
+ ## Certificado
103
+
104
+ | API | Descrição |
105
+ |---|---|
106
+ | `NfseCertificate.fromEnv/fromFile/fromBase64/fromPfx/fromPem` | Carrega o A1 sem expor a chave privada. |
107
+ | `certificado.cnpj`, `.cpf`, `.notBefore`, `.notAfter`, `.fingerprintSha256` | Metadados públicos. |
108
+ | `certificado.isValidAt(data?)`, `.daysUntilExpiry()`, `.destroy()` | Vigência e descarte do agente mTLS. |
109
+ | `assertCertificateValidity(certificado, now?)` | Vigência; aplicada antes de assinar e de enviar. |
110
+ | `assertCertificateForProvider(certificado, documento, now?)` | Vigência e titular. |
111
+ | `NFSE_CERT_ENV` | Nomes das variáveis de ambiente lidas por `fromEnv`. |
112
+ | `loadPfx`, `loadPfxFromBuffer` | Legado: retornam a chave em PEM. |
113
+
114
+ ## Baixo nível
115
+
116
+ | Função | Descrição |
117
+ |---|---|
118
+ | `signDps(xml, dpsId, certificado)` / `signEnveloped(xml, id, elemento, certificado)` | Assinatura XMLDSIG. |
119
+ | `verifyDps(xml, certPem)` | Verifica uma assinatura. |
120
+ | `gzipBase64(xml)` / `gunzipBase64(b64)` / `gunzipBase64Flexivel(b64)` | Compactação. |
121
+ | `transmitirDpsCompactada(b64, certificado, ambiente?, options?)` | `POST /nfse` cru. |
122
+ | `extrairErros(body)` | Normaliza erros da SEFIN. |
123
+ | `assertChaveAcesso(chave)` / `assertDpsId(id)` | Validação de identificadores. |
124
+ | `resolveSefinBaseUrl(ambiente)` / `resolveAdnBaseUrl(ambiente)` | URLs base. |
125
+ | `setSefinRequestObserver(fn)` / `createSefinLatencyTracker(opts?)` | Métricas de latência ([METRICS.md](../METRICS.md)). |
126
+
127
+ ## Constantes
128
+
129
+ `SEFIN_BASE_URL`, `ADN_BASE_URL`, `TP_AMB`, `DEFAULT_AMBIENTE`, `DPS_SCHEMA_VERSION`.
130
+
131
+ ## Tipos
132
+
133
+ Os tipos públicos estão em [`index.ts`](../../index.ts). Os principais:
134
+ `DpsJsonRequest`, `ResultadoEmissaoNota`, `NotaPreparada`, `NfseConsultada`,
135
+ `NfseResumo`, `ResultadoEvento`, `CancelamentoNfseInput`,
136
+ `CancelamentoPorSubstituicaoInput`, `SefinRequestOptions`, `SefinResposta`,
137
+ `SefinErro`, `CertificateInput`, `NfseClientOptions`.
@@ -0,0 +1,55 @@
1
+ # Erros
2
+
3
+ Todos os erros estendem `Error` e têm `name` igual ao nome da classe. Como
4
+ tratar cada um: [Tratar rejeições e erros](../guias/rejeicoes.md).
5
+
6
+ ## Antes de enviar (nada chegou à SEFIN)
7
+
8
+ | Classe | Campos | Quando |
9
+ |---|---|---|
10
+ | `DpsFiscalValidationError` | `issues`, `report` | O JSON da DPS é inválido. Cada issue tem `code`, `path`, `severity`, `source`, `message`, `suggestion?`. |
11
+ | `DpsXsdValidationError` | `details` | O XML da DPS viola o XSD oficial v1.01. |
12
+ | `PedRegEventoXsdValidationError` | `details` | O pedido de evento viola o XSD oficial. |
13
+ | `EventoInvalidoError` | `code = 'EVENTO_INVALID'`, `field` | Entrada de evento inválida (chave, motivo, autor). |
14
+ | `CertificateValidationError` | `code` | Problema no A1; códigos abaixo. |
15
+ | `ChaveAcessoInvalidaError` | `code = 'CHAVE_ACESSO_INVALID_FORMAT'`, `chaveAcesso` | Chave sem exatamente 50 dígitos. |
16
+ | `SefinParametroInvalidoError` | `code = 'SEFIN_PARAMETER_INVALID'`, `field`, `value` | Id da DPS, tipo de evento, NSU, município ou outro parâmetro de caminho com formato errado. |
17
+ | `XsdEngineUnavailableError` | `cause` | O motor XSD (WebAssembly) falhou. Infraestrutura, não rejeição fiscal. |
18
+
19
+ ### Códigos de `CertificateValidationError`
20
+
21
+ | `code` | Quando |
22
+ |---|---|
23
+ | `CERTIFICATE_INVALID_PASSWORD` | Senha incorreta. |
24
+ | `CERTIFICATE_UNREADABLE` | O conteúdo não é um PFX/PEM válido. |
25
+ | `CERTIFICATE_MISSING` | `fromEnv` sem `NFSE_CERT_PATH` nem `NFSE_CERT_BASE64`. |
26
+ | `CERTIFICATE_PASSWORD_MISSING` | `fromEnv` sem `NFSE_CERT_PASSWORD` nem `NFSE_CERT_PASSWORD_FILE`. |
27
+ | `CERTIFICATE_NOT_YET_VALID` | Antes de `notBefore`. |
28
+ | `CERTIFICATE_EXPIRED` | Depois de `notAfter`. |
29
+ | `CERTIFICATE_HOLDER_MISMATCH` | O titular não é o CPF/CNPJ informado. |
30
+
31
+ ## Depois de enviar (a SEFIN respondeu)
32
+
33
+ | Classe | Campos | Quando |
34
+ |---|---|---|
35
+ | `EmitirNotaError` | `status`, `erros`, `dpsId`, `body` | Emissão rejeitada, ou HTTP 2xx sem XML autorizado (`INVALID_AUTHORIZATION_RESPONSE`). |
36
+ | `RegistrarEventoError` | `status`, `erros`, `pedRegEventoId`, `body` | Evento rejeitado. |
37
+ | `ConsultaNfseError` | `status`, `erros`, `body`, `notFound` | Consulta falhou; `notFound` para HTTP 404. |
38
+
39
+ `erros` é uma lista de `SefinErro` (`Codigo`, `Descricao`, `Complemento?`) com o
40
+ código oficial da SEFIN preservado.
41
+
42
+ ## Erros de rede
43
+
44
+ Timeouts e falhas de conexão chegam como o `Error` original do Node (por exemplo
45
+ `ECONNRESET` ou `SEFIN request timed out after 60000ms`). Depois de um desses
46
+ numa emissão, o resultado é incerto: [recupere pela DPS](../guias/recuperar-emissao.md).
47
+
48
+ ## Ferramentas de agente
49
+
50
+ `toAgentIssues(error)` converte os erros acima em issues com `code`, `path`,
51
+ `severity`, `source` e `suggestion`. Códigos próprios das ferramentas:
52
+ `UNSUPPORTED_FIELD`, `AMBIENTE_NOT_ALLOWED`, `CERTIFICATE_REQUIRED`,
53
+ `XSD_INVALID` e `SEFIN_REJECTED`. As ferramentas de escrita acrescentam
54
+ `CONFIRMATION_NOT_FOUND` (id desconhecido, usado ou expirado) e
55
+ `TRANSMISSION_UNCERTAIN` (falha de rede no envio; repita o confirm).
@@ -0,0 +1,130 @@
1
+ # Tutorial: sua primeira NFS-e na produção restrita
2
+
3
+ Neste tutorial você emite, consulta, baixa o DANFSe e cancela uma NFS-e na
4
+ produção restrita, o ambiente oficial de testes. Nada aqui tem validade jurídica.
5
+ Leva uns 15 minutos.
6
+
7
+ **Você vai precisar de:**
8
+
9
+ - Node.js 20.6 ou mais recente (para `--env-file`);
10
+ - um certificado A1 (`.pfx`) ICP-Brasil do prestador e a senha;
11
+ - o prestador habilitado no Emissor Nacional, com o município conveniado.
12
+
13
+ ## 1. Crie o projeto
14
+
15
+ ```bash
16
+ mkdir minha-nfse && cd minha-nfse
17
+ npm init -y && npm pkg set type=module
18
+ npm install @useinvio/nfse-sdk
19
+ ```
20
+
21
+ ## 2. Configure o certificado
22
+
23
+ Copie o `.pfx` para a pasta e crie um `.env` (não versione nenhum dos dois):
24
+
25
+ ```bash
26
+ NFSE_CERT_PATH=./certificado.pfx
27
+ NFSE_CERT_PASSWORD=sua-senha
28
+ ```
29
+
30
+ Confira se o SDK lê o certificado:
31
+
32
+ ```bash
33
+ node --env-file=.env -e "import('@useinvio/nfse-sdk').then(({ NfseCertificate }) => console.log(NfseCertificate.fromEnv()))"
34
+ ```
35
+
36
+ A saída mostra só o CNPJ, a validade e o fingerprint, como
37
+ `NfseCertificate { cnpj=12345678000195, notAfter=..., fingerprintSha256=... }`.
38
+ Se aparecer `CERTIFICATE_INVALID_PASSWORD`, revise a senha.
39
+
40
+ ## 3. Emita a nota
41
+
42
+ Crie `emitir.mjs`. Troque o CNPJ, os municípios (código IBGE) e os códigos de
43
+ serviço pelos do seu prestador; os valores abaixo são ilustrativos.
44
+
45
+ ```js
46
+ import { emitirNfse, EmitirNotaError, NfseCertificate } from '@useinvio/nfse-sdk';
47
+
48
+ const certificado = NfseCertificate.fromEnv();
49
+
50
+ const nota = {
51
+ ambiente: 'restrita',
52
+ prestador: {
53
+ cnpj: '12345678000195', // o CNPJ do certificado: certificado.cnpj
54
+ cLocEmi: '4106902',
55
+ serie: '1601',
56
+ opSimpNac: '1',
57
+ regEspTrib: '0',
58
+ },
59
+ servico: {
60
+ cTribNac: '010201',
61
+ xDescServ: 'Desenvolvimento de software',
62
+ cLocPrestacao: '4106902',
63
+ },
64
+ emissao: {
65
+ nDPS: '1',
66
+ valores: { vServ: '10.00' },
67
+ tributacaoMunicipal: { tribISSQN: '1', tpRetISSQN: '1' },
68
+ tributacaoFederal: { piscofins: { CST: '07' } },
69
+ totTrib: { pTotTribFed: '0.00', pTotTribEst: '0.00', pTotTribMun: '5.00' },
70
+ },
71
+ };
72
+
73
+ try {
74
+ const resultado = await emitirNfse(nota, certificado);
75
+ console.log('Chave de acesso:', resultado.chaveAcesso);
76
+ } catch (error) {
77
+ if (!(error instanceof EmitirNotaError)) throw error;
78
+ for (const rejeicao of error.erros) console.error(rejeicao.Codigo, rejeicao.Descricao);
79
+ }
80
+ ```
81
+
82
+ ```bash
83
+ node --env-file=.env emitir.mjs
84
+ ```
85
+
86
+ Se a SEFIN rejeitar, a mensagem traz o código oficial da rejeição.
87
+ Corrija o campo indicado e rode de novo. Depois de uma emissão autorizada,
88
+ **incremente `nDPS`** para a próxima nota: cada número de DPS gera uma nota só.
89
+
90
+ ## 4. Consulte e baixe o DANFSe
91
+
92
+ Crie `consultar.mjs` e passe a chave de acesso como argumento:
93
+
94
+ ```js
95
+ import { writeFile } from 'node:fs/promises';
96
+ import { baixarDanfse, NfseCertificate, obterNfse } from '@useinvio/nfse-sdk';
97
+
98
+ const certificado = NfseCertificate.fromEnv();
99
+ const chave = process.argv[2];
100
+
101
+ const nota = await obterNfse(chave, certificado, 'restrita');
102
+ console.log(nota.resumo.nNFSe, nota.resumo.cStat, nota.resumo.valores.vLiq);
103
+
104
+ const danfse = await baixarDanfse(chave, certificado, 'restrita');
105
+ if (danfse.pdf) await writeFile('danfse.pdf', danfse.pdf);
106
+ ```
107
+
108
+ ```bash
109
+ node --env-file=.env consultar.mjs <chave-de-acesso>
110
+ ```
111
+
112
+ ## 5. Cancele
113
+
114
+ ```js
115
+ import { cancelarNfse, NfseCertificate } from '@useinvio/nfse-sdk';
116
+
117
+ const evento = await cancelarNfse(
118
+ { ambiente: 'restrita', chaveAcesso: process.argv[2], cMotivo: '1', xMotivo: 'Teste de integracao do SDK' },
119
+ NfseCertificate.fromEnv(),
120
+ );
121
+ console.log('Cancelada:', evento.pedRegEventoId);
122
+ ```
123
+
124
+ ## Próximos passos
125
+
126
+ - Leve o fluxo para a sua aplicação: [Emitir uma NFS-e](../guias/emitir.md).
127
+ - Proteja-se de timeouts: [Recuperar uma emissão](../guias/recuperar-emissao.md).
128
+ - Entenda o que acontece por baixo: [Como o SDK funciona](../conceitos/como-funciona.md).
129
+ - Antes de ir para `producao`, revise a [matriz fiscal](../FISCAL_MATRIX.md) com
130
+ quem cuida da parte tributária.
@@ -11,5 +11,7 @@ The payloads in `payloads.ts` are shared by these examples and exercised by the
11
11
  - [`emit-homologation.ts`](./emit-homologation.ts): emit in the restricted/sandbox SEFIN environment.
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
+ - [`cancel-nfse.ts`](./cancel-nfse.ts): download the DANFSe PDF and cancel an NFS-e (event e101101).
15
+ - [`recover-emission.ts`](./recover-emission.ts): recover an emission after a timeout with `GET /dps/{id}` instead of resending.
14
16
 
15
17
  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.
@@ -0,0 +1,29 @@
1
+ import { writeFile } from 'node:fs/promises';
2
+ import { NfseCertificate, NfseClient, RegistrarEventoError } from '@useinvio/nfse-sdk';
3
+
4
+ async function archiveAndCancel(chaveAcesso: string) {
5
+ const client = new NfseClient({
6
+ environment: 'sandbox',
7
+ certificate: NfseCertificate.fromEnv(), // NFSE_CERT_PATH + NFSE_CERT_PASSWORD
8
+ request: { timeoutMs: 30_000, retries: 2 }, // retries apply to GETs only
9
+ });
10
+
11
+ // Keep the official DANFSe PDF before cancelling.
12
+ const danfse = await client.invoices.danfse(chaveAcesso);
13
+ if (danfse.pdf) await writeFile(`danfse-${chaveAcesso}.pdf`, danfse.pdf);
14
+
15
+ try {
16
+ // `autor` defaults to the certificate holder's CNPJ/CPF.
17
+ const evento = await client.invoices.cancel({
18
+ chaveAcesso,
19
+ cMotivo: '1', // 1 = erro na emissao, 2 = servico nao prestado, 9 = outros
20
+ xMotivo: 'Nota emitida com valor incorreto',
21
+ });
22
+ console.log('Evento registrado:', evento.pedRegEventoId);
23
+ } catch (error) {
24
+ if (!(error instanceof RegistrarEventoError)) throw error;
25
+ console.error('Cancelamento rejeitado:', error.status, error.erros);
26
+ }
27
+ }
28
+
29
+ void archiveAndCancel(process.argv[2] ?? '0'.repeat(50));
@@ -0,0 +1,29 @@
1
+ import {
2
+ NfseCertificate,
3
+ prepararNota,
4
+ recuperarNfsePorDps,
5
+ transmitirNotaPreparada,
6
+ type DpsJsonRequest,
7
+ } from '@useinvio/nfse-sdk';
8
+ import { nationalInvoice } from './payloads.js';
9
+
10
+ /**
11
+ * Safe emission: persist the signed DPS before sending, and after a timeout ask
12
+ * SEFIN whether the DPS was processed instead of sending it again.
13
+ */
14
+ async function emitIdempotently(nota: DpsJsonRequest) {
15
+ const certificate = NfseCertificate.fromEnv();
16
+ const prepared = prepararNota(nota, certificate);
17
+ // await db.save(prepared.dpsId, prepared.signedXml);
18
+
19
+ try {
20
+ return await transmitirNotaPreparada(prepared, certificate, { timeoutMs: 30_000 });
21
+ } catch (error) {
22
+ if (error instanceof Error && error.name === 'EmitirNotaError') throw error; // SEFIN answered: a real rejection
23
+ const existing = await recuperarNfsePorDps(prepared.dpsId, certificate, prepared.ambiente, { retries: 3 });
24
+ if (existing) return existing; // authorized before the connection dropped
25
+ return transmitirNotaPreparada(prepared, certificate); // never reached SEFIN: same DPS, same Id
26
+ }
27
+ }
28
+
29
+ void emitIdempotently(nationalInvoice);
package/llms.txt CHANGED
@@ -1,95 +1,100 @@
1
- # @useinvio/nfse-sdk LLM Guide
2
-
3
- This is a TypeScript SDK for Brazil's NFS-e Nacional (SEFIN). It handles the protocol layer for issuing and querying national service invoices: DPS JSON/XML generation, XMLDSIG signing, GZip/Base64 compression, mTLS transport, and structured SEFIN rejection extraction.
4
-
5
- It is not a fiscal decision engine. Do not infer tax codes, accounting rules, tenant state, invoice numbering policy, or legal advice from this SDK.
6
-
7
- ## Start Here
8
-
9
- - `README.md`: primary Portuguese documentation and examples.
10
- - `ENGLISH.md`: English documentation with the same conceptual flow.
11
- - `docs/METRICS.md`: detailed SEFIN latency metrics guide, including the `NFSE_SEFIN_LATENCY_METRICS` env switch, observer setup, optional P99 snapshots, and export guidance.
12
- - `index.ts`: public exports. Treat this as the supported API surface.
13
- - `examples/`: runnable usage examples.
14
- - `JSON_MAPPING.md`: mapping notes for the declarative JSON input.
15
- - `test/`: behavior examples and regression coverage.
16
-
17
- ## Public Entry Points
18
-
19
- - `NfseClient`: resource-oriented client. Configure certificate, environment, and defaults once, then use `client.invoices.create(...)`, `client.invoices.buildDpsJson(...)`, and `client.invoices.get(...)`.
20
- - `emitirNfse(input, pfx, options?)`: issue an invoice from a DPS XML string or `DpsJsonRequest`.
21
- - `buildDpsFromJson(input)`: build unsigned DPS XML from declarative JSON.
22
- - `buildDpsId(prestador, nDPS, serie?)`: derive the 45-character DPS Id.
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`.
25
- - `consultarNfse(...)`, `enviarEvento(...)`, `extrairErros(...)`: lower-level SEFIN helpers.
26
- - `setSefinRequestObserver(...)` and `createSefinLatencyTracker(...)`: observe SEFIN round-trip latency when `NFSE_SEFIN_LATENCY_METRICS` is enabled; percentiles require `includePercentiles: true`.
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.
30
-
31
- ## File Map
32
-
33
- - `client.ts`: friendly client API and default merging.
34
- - `emissaoNota.ts`: central issue flow: prepare input, sign DPS, gzip/base64, transmit, unzip authorized XML, normalize errors.
35
- - `dpsJson.ts`: JSON-to-DPS XML builder, XML escaping, DPS Id generation, value formatting, and XML block assembly.
36
- - `fiscalValidation.ts`: structural and layout-oriented validation for the JSON input. This intentionally rejects unsupported or ambiguous fiscal shapes.
37
- - `sefinClient.ts`: HTTPS mTLS requests to SEFIN, latency observation, response parsing, error normalization, invoice query, issue transport, and event transport.
38
- - `config.ts`: SEFIN base URLs, environment names, and `tpAmb` mapping.
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.
42
- - `signXml.ts`: XMLDSIG signing and verification helpers.
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.
48
-
49
- ## Core Data Shape
50
-
51
- Declarative issuing uses `DpsJsonRequest`:
52
-
53
- - `ambiente`: optional, `restrita` or `producao`; defaults to `restrita`.
54
- - `prestador`: issuer profile such as `cnpj`, `cLocEmi`, `serie`, `opSimpNac`, and `regEspTrib`.
55
- - `servico`: service defaults such as `cTribNac`, `xDescServ`, `cLocPrestacao`, and optional `cNBS`.
56
- - `emissao`: invoice-specific data such as `nDPS`, dates, `valores`, optional parties, municipal/federal taxation blocks, and `totTrib`.
57
-
58
- Keep values as strings when they represent fiscal codes, identifiers, decimals, or exact XML values. Many fields are numeric-looking but must preserve leading zeroes.
59
-
60
- ## Important Invariants
61
-
62
- - Node.js >= 20 and ESM are expected.
63
- - Public imports should come from the package root (`index.ts` exports), not internal files, unless you are editing the SDK itself.
64
- - `DEFAULT_AMBIENTE` is `restrita`; `NfseClient` also accepts `sandbox` and `production` aliases.
65
- - `buildDpsFromJson` validates first via `validateDpsJsonRequest`.
66
- - The SDK intentionally avoids silent fiscal defaults for required tax fields such as `tributacaoMunicipal` and `totTrib`.
67
- - The JSON validator restricts `totTrib` by regime: non-Simples requires all three percentage totals; MEI requires `indTotTrib="0"`; ME/EPP requires `pTotTribSN`. Value totals remain typed but are rejected by the current regime matrix.
68
- - `buildDpsId` must return a 45-character Id beginning with `DPS`.
69
- - `emitirNfse` checks certificate validity before signing and again before transmission. Holder matching is an explicit `assertCertificateForProvider` call, not an automatic requirement.
70
- - JSON environment precedence is options > request > restricted; external XML derives its environment from `tpAmb` and rejects explicit conflicts.
71
- - `client.invoices.get(key, { ambiente })` supports an explicit environment; otherwise defaults.ambiente > constructor. It does not remember the last emission.
72
- - Currency discrepancies are warnings; explicit values retain priority. Service amounts must remain positive after rounding; all foreign amounts are serialized with two decimals.
73
- - `validateDpsJsonRequest` returns independent normalized data, errors in `issues`, and non-blocking `warnings`.
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.
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`.
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.
78
-
79
- ## Change Guidance for LLMs
80
-
81
- - Preserve the public API names exported by `index.ts` unless the task explicitly asks for a breaking change.
82
- - Prefer adding or adjusting focused tests in `test/` when changing XML generation, validation, signing, transport parsing, or client defaults.
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.
84
- - Do not add fiscal assumptions to make examples pass. Required fiscal choices should stay explicit in user input.
85
- - Be careful with XML ordering. The generated order should follow the SEFIN schema, and tests may compare XML snippets.
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.
87
- - Network calls to SEFIN should stay isolated in `sefinClient.ts` so tests can mock transport boundaries.
88
-
89
- ## Useful Commands
1
+ # @useinvio/nfse-sdk
2
+
3
+ > TypeScript SDK for Brazil's NFS-e Nacional (SEFIN/ADN). It issues, queries and cancels national service invoices: builds the DPS from JSON, validates it against the official XSD, signs it (XMLDSIG), sends it over mTLS with an ICP-Brasil A1 certificate, and returns SEFIN's answer as typed results and typed errors. It is not a tax engine: service codes, regime, tax blocks and DPS numbering always come from the user.
4
+
5
+ This file is for AI assistants writing code that uses the package. To change the SDK itself, read `AGENTS.md` in the repository.
6
+
7
+ ## Install and certificate
90
8
 
91
9
  ```bash
92
- npm run build
93
- npm run typecheck
94
- npm test
10
+ npm install @useinvio/nfse-sdk # Node.js >= 20, ESM, no native binaries
11
+ ```
12
+
13
+ ```ts
14
+ import { NfseCertificate } from '@useinvio/nfse-sdk';
15
+ const certificado = NfseCertificate.fromEnv(); // NFSE_CERT_PATH or NFSE_CERT_BASE64, plus NFSE_CERT_PASSWORD or NFSE_CERT_PASSWORD_FILE
16
+ ```
17
+
18
+ `NfseCertificate` keeps the private key out of the object; `console.log` and `JSON.stringify` show only CNPJ/CPF, validity and fingerprint. Never log, commit or ask for the `.pfx` or its password. Other loaders: `fromFile(path, pwd)`, `fromBase64(b64, pwd)`, `fromPfx(buffer, pwd)`, `fromPem({ key, cert })`. Errors: `CertificateValidationError` with `code` (`CERTIFICATE_INVALID_PASSWORD`, `CERTIFICATE_EXPIRED`, ...).
19
+
20
+ ## Issue
21
+
22
+ ```ts
23
+ import { emitirNfse, EmitirNotaError, explicarErros, type DpsJsonRequest } from '@useinvio/nfse-sdk';
24
+
25
+ const nota: DpsJsonRequest = {
26
+ ambiente: 'restrita', // official sandbox; 'producao' is legally valid
27
+ prestador: { cnpj, cLocEmi, serie, opSimpNac, regEspTrib },
28
+ servico: { cTribNac, xDescServ, cLocPrestacao },
29
+ emissao: { nDPS, valores: { vServ: '1500.00' }, tributacaoMunicipal, tributacaoFederal, totTrib },
30
+ };
31
+ try {
32
+ const { chaveAcesso, dpsId, nfseXml } = await emitirNfse(nota, certificado);
33
+ } catch (error) {
34
+ if (error instanceof EmitirNotaError) console.table(explicarErros(error.erros)); // official rule per code
35
+ else throw error; // network/timeout: the outcome is unknown, see "Recover"
36
+ }
37
+ ```
38
+
39
+ - Keep fiscal codes and amounts as strings (leading zeros matter). Do not invent `cTribNac`, IBGE codes, regime or tax blocks; ask the user. Field reference: `JSON_MAPPING.md`.
40
+ - Validate without sending: `validateDpsJsonRequest(nota)` returns `{ valid, issues, warnings }`; `buildDpsFromJson(nota)` returns `{ id, xml }`.
41
+ - Persist before sending: `const p = prepararNota(nota, cert)` then `transmitirNotaPreparada(p, cert)`.
42
+ - Each `nDPS` (with `serie`) produces one invoice; increment it after a successful emission.
43
+
44
+ ## Recover after a timeout (never resend blindly)
45
+
46
+ ```ts
47
+ const existing = await recuperarNfsePorDps(p.dpsId, certificado, p.ambiente, { retries: 3 });
48
+ // existing !== null: it was issued. null: SEFIN never got it; resend the SAME prepared DPS.
49
+ ```
50
+
51
+ POST requests (emission, events) are never retried by the SDK. `{ timeoutMs, retries, signal }` works on every call; `retries` applies to GETs only.
52
+
53
+ ## Query, PDF, cancel
54
+
55
+ ```ts
56
+ const { nfseXml, resumo } = await obterNfse(chaveAcesso, certificado); // ConsultaNfseError, .notFound on 404
57
+ const { pdf } = await baixarDanfse(chaveAcesso, certificado);
58
+ await cancelarNfse({ chaveAcesso, cMotivo: '1', xMotivo: 'Nota emitida com valor incorreto' }, certificado); // RegistrarEventoError
59
+ await cancelarNfsePorSubstituicao({ chaveAcesso, chaveSubstituta, cMotivo: '01' }, certificado);
95
60
  ```
61
+
62
+ `cMotivo` for cancellation: `1` issuing error, `2` service not provided, `9` other; `xMotivo` 15 to 255 characters. `lerNfse(xml)` reads an NFS-e XML you already have. ADN: `distribuirDfePorNsu`, `consultarConvenio`, `consultarAliquota`, `consultarRetencoes`.
63
+
64
+ ## Client
65
+
66
+ ```ts
67
+ const client = new NfseClient({ environment: 'sandbox', certificate: certificado, defaults: { prestador, servico }, request: { timeoutMs: 30_000, retries: 2 } });
68
+ await client.invoices.create({ emissao }); // also retrieve, recover, cancel, cancelBySubstitution, danfse
69
+ ```
70
+
71
+ ## Rejection codes
72
+
73
+ `explicarRejeicao('E0014')` returns the official message, rule and XML field from the gov.br annexes (Anexo I v1.01, Anexo II v1.01), `conhecida: false` for codes not in the catalog. `explicarErros(error.erros)` explains a whole rejection.
74
+
75
+ ## Tests without a certificate or network
76
+
77
+ ```ts
78
+ import { createTestCertificate, installMockSefin } from '@useinvio/nfse-sdk/testing';
79
+ const mock = installMockSefin(); // in-process SEFIN + ADN; validates XSD and signatures
80
+ const { certificate } = createTestCertificate({ cnpj: '12345678000195' });
81
+ // ... emitirNfse / obterNfse / cancelarNfse work as usual ...
82
+ mock.rejectNext('E0312'); mock.dropResponseNext(); // script rejections and dropped connections
83
+ mock.restore();
84
+ ```
85
+
86
+ ## Command line
87
+
88
+ `npx nfse init` (sample nota.json), `nfse doctor`, `nfse validate nota.json`, `nfse emit nota.json [--mock] [--producao] [--yes] [--json]`, `nfse get <chave>`, `nfse danfse <chave>`, `nfse cancel <chave> --motivo 1 --justificativa "..."`, `nfse recover <dpsId>`, `nfse explain E0014`. Exit codes: 0 ok, 1 error, 2 SEFIN rejection.
89
+
90
+ ## AI agents and MCP
91
+
92
+ - `npx -y @useinvio/nfse-mcp`: MCP stdio server. Env: certificate vars above, `NFSE_AMBIENTE`, `NFSE_MCP_ALLOW_WRITE=1` (emit/cancel), `NFSE_MCP_MOCK=1` (mock SEFIN).
93
+ - `@useinvio/nfse-sdk/agent`: `nfseAgentTools` (read-only: `validate_dps`, `build_dps_xml`, `get_nfse`, `recover_nfse_by_dps`, `explain_rejection`) and `createNfseAgentToolkit({ allowWrite })`, which adds `prepare_*`/`confirm_*` emission and cancellation. Certificate and environment are host context, never tool input. Only call `confirm_*` after the user approves the summary from `prepare_*`.
94
+ - Claude Code plugin: `/plugin install nfse-nacional --marketplace useinvio/nfse-sdk`.
95
+
96
+ ## Docs
97
+
98
+ - `docs/README.md` (pt-BR): tutorial, guides, API and error reference.
99
+ - `docs/referencia/erros.md`: every error class and code.
100
+ - `docs/referencia/ambientes.md`: SEFIN and ADN URLs and endpoints.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useinvio/nfse-sdk",
3
- "version": "3.1.0",
3
+ "version": "3.2.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",
@@ -14,6 +14,14 @@
14
14
  "types": "./dist/agent.d.ts",
15
15
  "import": "./dist/agent.js"
16
16
  },
17
+ "./testing": {
18
+ "types": "./dist/testing.d.ts",
19
+ "import": "./dist/testing.js"
20
+ },
21
+ "./mcp": {
22
+ "types": "./dist/mcpServer.d.ts",
23
+ "import": "./dist/mcpServer.js"
24
+ },
17
25
  "./package.json": "./package.json"
18
26
  },
19
27
  "files": [
@@ -21,10 +29,13 @@
21
29
  "dist/*.js",
22
30
  "dist/*.js.map",
23
31
  "dist/schemas/**/*.xsd",
24
- "docs/*.md",
32
+ "docs/**/*.md",
33
+ "!docs/rejeicoes/**",
25
34
  "examples/*.ts",
26
35
  "examples/README.md",
27
36
  "README.md",
37
+ "README.en.md",
38
+ "CHANGELOG.md",
28
39
  "JSON_MAPPING.md",
29
40
  "llms.txt",
30
41
  "LICENSE",
@@ -34,7 +45,10 @@
34
45
  "build": "tsc -p tsconfig.json",
35
46
  "prepare": "npm run build",
36
47
  "typecheck": "tsc -p tsconfig.json --noEmit",
37
- "test": "npm run build && tsc -p tsconfig.test.json && node --test dist-test/test/*.test.js"
48
+ "test": "npm run build && tsc -p tsconfig.test.json && node --test dist-test/test/*.test.js",
49
+ "typecheck:examples": "tsc -p tsconfig.examples.json",
50
+ "build:rejection-pages": "npm run build && node scripts/build-rejection-pages.mjs",
51
+ "build:playground": "node scripts/build-playground.mjs"
38
52
  },
39
53
  "keywords": [
40
54
  "nfse",
@@ -72,11 +86,17 @@
72
86
  "xml-crypto": "^6.4.0"
73
87
  },
74
88
  "devDependencies": {
89
+ "@modelcontextprotocol/sdk": "^1.32.2",
75
90
  "@types/node": "^22.13.14",
76
91
  "@types/node-forge": "^1.3.11",
92
+ "esbuild": "^0.28.2",
77
93
  "typescript": "^5.6.2"
78
94
  },
79
95
  "engines": {
80
96
  "node": ">=20"
97
+ },
98
+ "bin": {
99
+ "nfse": "dist/cliBin.js",
100
+ "nfse-mcp": "dist/mcpCli.js"
81
101
  }
82
102
  }