### Install open-nfse with yarn Source: https://fm-s.github.io/open-nfse/guide/getting-started Install the open-nfse package using yarn. ```bash yarn add open-nfse ``` -------------------------------- ### Install open-nfse with pnpm Source: https://fm-s.github.io/open-nfse/guide/getting-started Install the open-nfse package using pnpm. ```bash pnpm add open-nfse ``` -------------------------------- ### Install open-nfse Source: https://fm-s.github.io/open-nfse Install the open-nfse package using npm. Requires Node.js 20+ and a digital A1 certificate. ```bash npm install open-nfse ``` -------------------------------- ### Setup NfseClient Source: https://fm-s.github.io/open-nfse/guide/emitir Initialize the NfseClient with environment, certificate, and necessary stores for DPS counting and retry management. For production, use persistent implementations for `dpsCounter` and `retryStore`. ```typescript import { NfseClient, Ambiente, createInMemoryDpsCounter, createInMemoryRetryStore, } from 'open-nfse'; const cliente = new NfseClient({ ambiente: Ambiente.ProducaoRestrita, certificado: { pfx, password }, dpsCounter: createInMemoryDpsCounter(), // produção: UPDATE ... RETURNING retryStore: createInMemoryRetryStore(), // produção: tabela nfse_pending_events }); ``` -------------------------------- ### client.fetchDanfse(chave) - Online Only Source: https://fm-s.github.io/open-nfse/guide/danfse This method is used when you only have the access key and want to ensure you get the official PDF directly from the ADN service. It does not have a fallback mechanism and will throw errors for invalid keys, non-existent keys, or authorization issues. ```APIDOC ## `cliente.fetchDanfse(chave)` — só online When you only have the key (without the `NFSe` object), or want to guarantee the official PDF: ```typescript try { const pdf = await cliente.fetchDanfse('21113002200574753000100000000000146726037032711025'); await fs.writeFile('nfse.pdf', pdf); } catch (err) { if (err instanceof InvalidChaveAcessoError) console.error('Chave com formato inválido'); if (err instanceof NotFoundError) console.error('Chave não existe na Receita'); if (err instanceof ForbiddenError) console.error('CNPJ do cert não autorizado a consultar'); throw err; } ``` Without fallback — errors are thrown. Use when you want to fail loudly. **Upfront Validation:** `fetchDanfse` validates `/^\d{50}$/` before touching the network and throws `InvalidChaveAcessoError` if the key is out of format — same behavior as `fetchByChave`. Protects against wasted round-trips and input injection via URL. ``` -------------------------------- ### End-to-End Test for PedidoService Source: https://fm-s.github.io/open-nfse/guide/testing Use `NfseClientFake` to simulate NFSe client behavior in end-to-end tests. This example demonstrates emitting a note, handling rejections, and managing timeouts. ```typescript import { describe, it, expect, beforeEach } from 'vitest'; import { NfseClientFake } from 'open-nfse/testing'; import { PedidoService } from '../src/pedido-service.js'; describe('PedidoService', () => { let fake: NfseClientFake; let service: PedidoService; beforeEach(() => { fake = new NfseClientFake(); service = new PedidoService(fake); }); it('emite nota e guarda a chave no pedido', async () => { const pedido = { id: 1, valor: 100, cliente: {cnpj: '...' } }; const resultado = await service.emitirNota(pedido); expect(resultado.chaveAcesso).toMatch(/^\d{50}$/); expect(fake.emittedChaves).toHaveLength(1); }); it('marca pedido como rejeitado quando CNPJ é inválido', async () => { fake.failNextEmit({ kind: 'rejection', codigo: 'E401', descricao: 'CNPJ não autorizado', }); await expect(service.emitirNota({ id: 1, /* ... */ })) .rejects.toMatchObject({ name: 'ReceitaRejectionError', codigo: 'E401' }); }); it('retorna retry_pending e salva para replay quando há timeout', async () => { fake.failNextEmit({ kind: 'transient', message: 'mock timeout' }); const r = await fake.emitir({ /* params */ }); expect(r.status).toBe('retry_pending'); }); }); ``` -------------------------------- ### Ajuste de Timeout para o Cliente Nfse Source: https://fm-s.github.io/open-nfse/guide/ambientes Customize the request timeout for the `NfseClient` by setting the `timeoutMs` option. The default is 60 seconds; this example sets it to 2 minutes to accommodate potential delays during peak hours. ```typescript new NfseClient({ ambiente: Ambiente.Producao, certificado, timeoutMs: 120_000, // 2 min — SEFIN pode ser lento em horário de pico }); ``` -------------------------------- ### get() Method Source: https://fm-s.github.io/open-nfse/api/interfaces/ParametrosCache Retrieves a cached item by its key. Returns undefined if the item is not found or has expired. ```APIDOC ## get() ### Description Retrieves a cached item by its key. Returns `undefined` if the item is not found or has expired. ### Method Signature ```typescript get(key: string): Promise; ``` ### Type Parameters * `T`: The type of the cached value. ### Parameters * `key` (string): The key of the item to retrieve. ### Returns A promise that resolves to the cached value of type `T` or `undefined`. ``` -------------------------------- ### Constructor Source: https://fm-s.github.io/open-nfse/api/classes/NfseClient Initializes a new instance of the NfseClient class with the provided configuration. ```APIDOC ## Constructor ### Description Initializes a new instance of the NfseClient class. ### Parameters #### Parameters - **config** (NfseClientConfig) - Required - The configuration object for the NfseClient. ### Returns - `NfseClient` - An instance of the NfseClient. ``` -------------------------------- ### get Method Signature Source: https://fm-s.github.io/open-nfse/api/interfaces/ParametrosCache Retrieves a cached item by its key. Returns undefined if the item is not found or has expired. ```typescript get(key: string): Promise; ``` -------------------------------- ### ParametrosCache Interface Definition Source: https://fm-s.github.io/open-nfse/api/interfaces/ParametrosCache Defines the contract for cache implementations, including get and set methods with TTL. ```typescript interface ParametrosCache { get(key: string): Promise; set(key: string, value: T, ttlMs: number): Promise; } ``` -------------------------------- ### Hosts por Ambiente Source: https://fm-s.github.io/open-nfse/guide/ambientes Tabela que mapeia os serviços aos seus respectivos hosts para os ambientes de Produção Restrita e Produção. O `NfseClient` gerencia a seleção automática do host correto. ```APIDOC ## Hosts por ambiente A API oficial está **dividida em hosts distintos**. O `NfseClient` resolve automaticamente qual host usar por endpoint: Serviço| ProducaoRestrita| Producao ---|---|--- **SEFIN Nacional**| `sefin.producaorestrita.nfse.gov.br/SefinNacional`| `sefin.nfse.gov.br/SefinNacional` **ADN Contribuintes**| `adn.producaorestrita.nfse.gov.br/contribuintes`| `adn.nfse.gov.br/contribuintes` **ADN DANFSe**| `adn.producaorestrita.nfse.gov.br/danfse`| `adn.nfse.gov.br/danfse` **ADN Parâmetros Municipais**| `adn.producaorestrita.nfse.gov.br/parametrizacao`| `adn.nfse.gov.br/parametrizacao` Contratos diferentes por host **SEFIN** usa camelCase + `tipoAmbiente: int`. **ADN** usa PascalCase + `TipoAmbiente: string`. Essa diferença é proposital e a lib normaliza tudo para o shape público tipado — você nunca vê essas inconsistências no seu código. ``` -------------------------------- ### Initialize NfseClient with In-Memory Stores Source: https://fm-s.github.io/open-nfse Set up the NfseClient using in-memory stores for DPS counting and retries. These are suitable for testing; production environments should use persistent stores like Postgres. ```typescript import { NfseClient, Ambiente, createInMemoryDpsCounter, createInMemoryRetryStore, } from 'open-nfse'; const cliente = new NfseClient({ ambiente: Ambiente.ProducaoRestrita, certificado: { pfx: readFileSync('./cert.pfx'), password: process.env.CERT_PASSWORD! }, dpsCounter: createInMemoryDpsCounter(), retryStore: createInMemoryRetryStore(), }); ``` -------------------------------- ### ReceitaRejectionError Accessor: descricao Source: https://fm-s.github.io/open-nfse/api/classes/ReceitaRejectionError Provides a shortcut to get the description of the first rejection message. This offers a human-readable explanation of the rejection. ```typescript get descricao(): string; ``` -------------------------------- ### ReceitaRejectionError Accessor: complemento Source: https://fm-s.github.io/open-nfse/api/classes/ReceitaRejectionError Provides a shortcut to get the complement of the first rejection message, if available. This can offer additional details about the rejection. ```typescript get complemento(): string | undefined; ``` -------------------------------- ### Acesso Direto a `AmbienteEndpoints` Source: https://fm-s.github.io/open-nfse/guide/ambientes Demonstra como acessar diretamente os URLs dos endpoints para cada ambiente usando `AMBIENTE_ENDPOINTS`. ```APIDOC ## `AmbienteEndpoints` — acesso direto Se precisar dos URLs (ex: um dashboard mostrando para qual host está apontando): typescript ```typescript import { AMBIENTE_ENDPOINTS, Ambiente } from 'open-nfse'; const endpoints = AMBIENTE_ENDPOINTS[Ambiente.Producao]; endpoints.sefin; // "https://sefin.nfse.gov.br/SefinNacional" endpoints.adn; // "https://adn.nfse.gov.br/contribuintes" endpoints.danfse; endpoints.parametrosMunicipais; ``` ``` -------------------------------- ### NfseClient Constructor Source: https://fm-s.github.io/open-nfse/api-cheatsheet Initializes a new instance of the NfseClient with the provided configuration. All methods on this client return Promises. ```APIDOC ## NfseClient Constructor ### Description Initializes a new instance of the NfseClient with the provided configuration. ### Signature ```typescript new NfseClient(config: NfseClientConfig): NfseClient ``` ### Parameters - **config** (NfseClientConfig) - The configuration object for the client. ``` -------------------------------- ### ReceitaRejectionError Accessor: codigo Source: https://fm-s.github.io/open-nfse/api/classes/ReceitaRejectionError Provides a shortcut to get the code of the first rejection message. Useful for quickly identifying the type of rejection. ```typescript getcodigo(): string; ``` -------------------------------- ### buildSubstituicaoXml Source: https://fm-s.github.io/open-nfse/api/functions/buildSubstituicaoXml Constructs the XML for a cancellation event by substitution (105102). Requires the key of the substitute NFS-e, which must have already been issued. ```APIDOC ## Function: buildSubstituicaoXml() ```ts function buildSubstituicaoXml(params: BuildSubstituicaoXmlParams, options?: BuildEventoXmlOptions): string; ``` ### Description Constructs the XML for a cancellation event by substitution (105102). Requires the key of the substitute NFS-e, which must have already been issued. ### Parameters #### Parameters - **params** (`BuildSubstituicaoXmlParams`) - Required - The parameters for building the substitution XML. - **options** (`BuildEventoXmlOptions`) - Optional - Additional options for building the event XML. ### Returns - `string` - The generated XML string. ``` -------------------------------- ### RetencaoArtigoSexto Interface Properties Source: https://fm-s.github.io/open-nfse/api/interfaces/RetencaoArtigoSexto This snippet details the properties of the RetencaoArtigoSexto interface, including the mandatory start date of validity and the optional end date of validity. ```APIDOC ## Interface: RetencaoArtigoSexto ### Description Defines the properties for retention rules, including their validity periods. ### Properties #### `dataInicioVigencia` - **Type**: `Date` - **Required**: Yes - **Description**: The start date of the validity period for the retention rule. #### `dataFimVigencia` - **Type**: `Date` - **Required**: No - **Description**: The optional end date of the validity period for the retention rule. ``` -------------------------------- ### Instantiate NfseClient Source: https://fm-s.github.io/open-nfse/api-cheatsheet Create a new instance of the NfseClient with the provided configuration. All subsequent methods on this client will return Promises. ```typescript new NfseClient(config: NfseClientConfig): NfseClient ``` -------------------------------- ### Replay de Eventos Pendentes com Open-NFSe Source: https://fm-s.github.io/open-nfse/guide/emitir Executa um cron job para reenviar eventos que falharam ou ficaram pendentes. A biblioteca SEFIN garante a idempotência, permitindo múltiplas execuções sem duplicação de dados. ```typescript const items = await cliente.replayPendingEvents(); for (const item of items) { switch (item.status) { case 'success_emission': await db.insert('nfse_autorizadas', { chave_acesso: item.emission.chaveAcesso, id_dps: item.emission.idDps, xml_nfse: item.emission.xmlNfse, /* ... */ }); logger.info('replay emissão ok', { id: item.id }); break; case 'success': // Evento (cancelamento/substituição/rollback) bem sucedido await db.insert('nfse_eventos', { chave_acesso: item.evento.chaveNfse, tipo_evento: item.evento.tipoEvento, xml_evento: item.evento.xmlEvento, /* ... */ }); logger.info('replay evento ok', { id: item.id }); break; case 'still_pending': // Transiente de novo — fica no store, próxima rodada tenta logger.warn('replay transient', { id: item.id, err: item.error.message }); break; case 'failed_permanent': // Permanente — lib removeu do store. Caller decide (alerta, ticket, etc). logger.error('replay permanent', { id: item.id, err: item.error.message }); break; } } ``` -------------------------------- ### AtvEvento Interface Definition Source: https://fm-s.github.io/open-nfse/api/interfaces/AtvEvento This snippet details the properties of the AtvEvento interface, which represents event activity data. It includes readonly properties for start and end dates, identification, and the event name. ```APIDOC ## Interface: AtvEvento ### Description Represents event activity data. ### Properties | Property | Modifier | Type | Defined in | |-----------------|-----------|-----------------------|----------------------| | `dtFim` | `readonly`| `Date` | src/nfse/domain.ts:175 | | `dtIni` | `readonly`| `Date` | src/nfse/domain.ts:174 | | `identificacao` | `readonly`| `AtvEventoIdentificacao`| src/nfse/domain.ts:176 | | `xNome` | `readonly`| `string` | src/nfse/domain.ts:173 | ``` -------------------------------- ### Configuração de Cache Pluggable Source: https://fm-s.github.io/open-nfse/guide/parametros Interface para implementar caches customizadas. O NfseClient utiliza um cache in-memory por padrão, mas pode ser configurado com outras implementações como Redis. ```APIDOC ## Cache pluggable ### Interface ```typescript export interface ParametrosCache { get(key: string): Promise; set(key: string, value: T, ttlMs: number): Promise; } ``` ### Default Shipped `createInMemoryParametrosCache()` (Map com TTL, por processo). ### Example with Redis ```typescript import type { ParametrosCache } from 'open-nfse'; const redisCache: ParametrosCache = { async get(key) { const v = await redis.get(`nfse-param:${key}`); return v ? JSON.parse(v) : undefined; }, async set(key, value, ttlMs) { await redis.set(`nfse-param:${key}`, JSON.stringify(value), 'PX', ttlMs); }, }; const cliente = new NfseClient({ ..., parametrosCache: redisCache }); ``` ``` -------------------------------- ### CEP Validator with Custom Provider Source: https://fm-s.github.io/open-nfse/guide/validacoes The `CepValidator` interface is pluggable, allowing you to replace the default ViaCEP provider with alternatives like BrasilAPI or a custom mock for testing. This example shows how to implement a `CepValidator` for BrasilAPI. ```typescript import type { CepValidator } from 'open-nfse'; const brasilApi: CepValidator = { async validate(cep) { const r = await fetch(`https://brasilapi.com.br/api/cep/v1/${cep}`); if (r.status === 404) throw new InvalidCepError(cep, 'not_found'); if (!r.ok) throw new InvalidCepError(cep, 'api_unavailable'); const data = await r.json(); return { cep, logradouro: data.street, uf: data.state, /* ... */ }; }, }; const cliente = new NfseClient({..., cepValidator: brasilApi}); ``` -------------------------------- ### Import NfseClientFake and NfseClientLike Source: https://fm-s.github.io/open-nfse/guide/testing Import the fake client and the compatible type for dependency injection. The fake client is a subpath export, ensuring it's only loaded in test environments. ```typescript import { NfseClientFake, type NfseClientLike } from 'open-nfse/testing'; ``` -------------------------------- ### Use File-Based Certificate Provider Source: https://fm-s.github.io/open-nfse/guide/getting-started Utilize the `providerFromFile` utility for a common scenario where the certificate is stored in a PFX file. Requires the file path and password. ```typescript import { providerFromFile } from 'open-nfse'; const provider = providerFromFile('/secure/cert.pfx', process.env.CERT_PASSWORD!); ``` -------------------------------- ### Schema SQL para Tabela Emitentes Source: https://fm-s.github.io/open-nfse/guide/integracao Define a estrutura da tabela `emitentes` no PostgreSQL para armazenar informações sobre CNPJs que operam o sistema. Certificados digitais devem ser armazenados externamente, com apenas uma referência opaca na coluna `certificate_ref`. ```sql CREATE TABLE emitentes ( id BIGSERIAL PRIMARY KEY, cnpj CHAR(14) NOT NULL UNIQUE CHECK (cnpj ~ '^\d{14}$'), inscricao_municipal VARCHAR(30) NOT NULL, cod_municipio CHAR(7) NOT NULL CHECK (cod_municipio ~ '^\d{7}$'), razao_social TEXT NOT NULL, ambiente SMALLINT NOT NULL CHECK (ambiente IN (1, 2)), -- 1=Prod, 2=Homolog certificate_ref TEXT NOT NULL, -- KMS ARN, Vault path, etc. certificate_expires_on DATE, -- para alerta proativo created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ``` -------------------------------- ### DetalheEvento Type Alias Definition Source: https://fm-s.github.io/open-nfse/api/type-aliases/DetalheEvento This code snippet shows the TypeScript definition of the DetalheEvento type alias, which is a discriminated union representing different event details. It also includes an example of how to narrow down the type using the 'in' operator. ```APIDOC ## Type Alias: DetalheEvento ### Description This type alias represents a discriminated union covering all 16 event types defined in `tiposEventos_v1.01.xsd`, plus an `unknown` variant for raw XML nodes that the library hasn't modeled yet. This provides a defensive approach against potential new event types introduced by the Receita Federal. ### Usage Narrow down the type using the `in` operator: ts if ('e101101' in detalhe) { // Access properties like detalhe.e101101.xMotivo } ### Type Definition ```typescript type DetalheEvento = | { e101101: { cMotivo: JustificativaCancelamento; xDesc: string; xMotivo: string; }; } | { e105102: { chSubstituta: string; cMotivo: JustificativaSubstituicao; xDesc: string; xMotivo?: string; }; } | { e101103: { cMotivo: JustificativaAnaliseFiscalCancelamento; xDesc: string; xMotivo: string; }; } | { e105104: { cMotivo: JustificativaAnaliseFiscalCancelamentoDeferido; CPFAgTrib: string; nProcAdm?: string; xDesc: string; xMotivo: string; }; } | { e105105: { cMotivo: JustificativaAnaliseFiscalCancelamentoIndeferido; CPFAgTrib: string; nProcAdm?: string; xDesc: string; xMotivo: string; }; } | { e202201: { xDesc: string; }; } | { e203202: { xDesc: string; }; } | { e204203: { xDesc: string; }; } | { e205204: { xDesc: string; }; } | { e202205: { infRej: InfoEventoRejeicao; xDesc: string; }; } | { e203206: { infRej: InfoEventoRejeicao; xDesc: string; }; } | { e204207: { infRej: InfoEventoRejeicao; xDesc: string; }; } | { e205208: { infAnRej: InfoEventoAnulacaoRejeicao; xDesc: string; }; } | { e305101: { CPFAgTrib: string; nProcAdm: string; xDesc: string; xProcAdm: string; }; } | { e305102: { codEvento: string; CPFAgTrib: string; xDesc: string; xMotivo: string; }; } | { e305103: { CPFAgTrib: string; idBloqOfic: string; xDesc: string; }; } | { unknown: { elementName: string; raw: XmlObject; tipoEvento: string; }; }; ``` ``` -------------------------------- ### Dispatcher Customizado Source: https://fm-s.github.io/open-nfse/guide/ambientes Guia para uso avançado de um dispatcher customizado, com exemplos para testes usando `MockAgent`. ```APIDOC ## Dispatcher customizado (avançado) Use só em testes ou setups exóticos. Ao passar um dispatcher: * A lib **não fecha** ele em `close()` (você mantém o lifecycle) * A lib **ainda carrega o certificado** (precisa para assinar a DPS) * `MockAgent` do undici é o caso típico em testes typescript ```typescript import { MockAgent } from 'undici'; import { NfseClient } from 'open-nfse'; const mock = new MockAgent(); mock.disableNetConnect(); const cliente = new NfseClient({ ambiente: Ambiente.ProducaoRestrita, certificado: { pfx, password }, dispatcher: mock, }); ``` ``` -------------------------------- ### Implementar Cache de Parâmetros com Redis Source: https://fm-s.github.io/open-nfse/guide/parametros Exemplo de implementação da interface `ParametrosCache` utilizando Redis para cache compartilhado entre processos. Define métodos `get` e `set` para interagir com o Redis. ```typescript import type { ParametrosCache } from 'open-nfse'; const redisCache: ParametrosCache = { async get(key) { const v = await redis.get(`nfse-param:${key}`); return v ? JSON.parse(v) : undefined; }, async set(key, value, ttlMs) { await redis.set(`nfse-param:${key}`, JSON.stringify(value), 'PX', ttlMs); }, }; const cliente = new NfseClient({ ..., parametrosCache: redisCache }); ``` -------------------------------- ### Error.prepareStackTrace Static Method Source: https://fm-s.github.io/open-nfse/api/classes/ReceitaRejectionError Customizes the format of stack traces. This is inherited from `OpenNfseError`. ```APIDOC ### prepareStackTrace() ts ``` static prepareStackTrace(err: Error, stackTraces: CallSite[]): any; ``` Defined in: node_modules/@types/node/globals.d.ts:56 #### Parameters Parameter| Type ---|--- `err`| `Error` `stackTraces`| `CallSite`[] #### Returns `any` #### See https://v8.dev/docs/stack-trace-api#customizing-stack-traces #### Inherited from `OpenNfseError`.`prepareStackTrace` ``` -------------------------------- ### Opções por Chamada Source: https://fm-s.github.io/open-nfse/guide/parametros Cada método `consultar*` aceita um objeto de opções para customizar o comportamento do cache e do TTL. ```APIDOC ## Opções por chamada ### Description Cada `consultar*` aceita um objeto de opções: ### Parameters #### Options Object - **useCache** (boolean) - Optional - Força um miss no cache (bate direto no ADN). - **ttlMs** (number) - Optional - Override do TTL padrão desta chamada em milissegundos. - **cache** (ParametrosCache) - Optional - Cache específica a ser utilizada, sobrescrevendo a configuração do cliente. ### Request Example ```typescript await cliente.consultarAliquota('2111300', '250101', new Date(), { useCache: false, ttlMs: 60 * 60_000, cache: outra, }); ``` ``` -------------------------------- ### Error.captureStackTrace Example Source: https://fm-s.github.io/open-nfse/api/classes/InvalidCpfError Creates a .stack property on targetObject, which when accessed returns a string representing the location in the code at which Error.captureStackTrace() was called. The optional constructorOpt argument accepts a function. If given, all frames above constructorOpt, including constructorOpt, will be omitted from the generated stack trace. ```javascript const myObject = {}; Error.captureStackTrace(myObject); myObject.stack; // Similar to `new Error().stack` ``` ```javascript function a() { b(); } function b() { c(); } function c() { // Create an error without stack trace to avoid calculating the stack trace twice. const { stackTraceLimit } = Error; Error.stackTraceLimit = 0; const error = new Error(); Error.stackTraceLimit = stackTraceLimit; // Capture the stack trace above function b Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace throw error; } a(); ``` -------------------------------- ### TipoEventoNfse: EventoSistemico467201 Source: https://fm-s.github.io/open-nfse/api/enumerations/TipoEventoNfse Represents a system event code '467201' not declared in tiposeventos_v1.01.xsd. This event might be encountered in the 'tipoEvento' enum of the GET /nfse/{chave}/eventos/{tipoEvento}/{numSeqEvento} endpoint. The parser may fall back to 'unknown' if the exact shape is not published. ```typescript EventoSistemico467201: "467201"; ``` -------------------------------- ### Configure `fetchByNsu` Parameters Source: https://fm-s.github.io/open-nfse/guide/consultar Customize `fetchByNsu` requests with optional parameters like `cnpjConsulta` to query on behalf of another CNPJ, or `lote` to request the full batch. ```typescript await cliente.fetchByNsu({ ultimoNsu: 12345, cnpjConsulta: '00574753000100', // opcional — consulta em nome de outro CNPJ lote: true, // opcional — pede lote completo }); ``` -------------------------------- ### client.gerarDanfse(nfse) - Default 'auto' strategy Source: https://fm-s.github.io/open-nfse/guide/danfse This is the default method for generating the DANFSe PDF. It first attempts to fetch the official PDF from the ADN service (`GET /danfse/{chave}`). If transient network or server errors occur, it falls back to local rendering using pdfkit. Permanent errors like invalid keys or authorization issues will propagate. ```APIDOC ## `cliente.gerarDanfse(nfse)` — default `auto` ```typescript const r = await cliente.emitir(params); if (r.status === 'ok') { const pdf = await cliente.gerarDanfse(r.nfse.nfse); await fs.writeFile(`nfse-${r.nfse.chaveAcesso}.pdf`, pdf); } ``` **Attempt Order:** 1. `GET /danfse/{chave}` on the official ADN. 2. **Only transient failures** (`NetworkError`, `TimeoutError`, `ServerError`/5xx) → falls back to local renderer. 3. Logs `danfse.online.fallback` to the configured logger for traceability. **Permanent errors propagate:** `ForbiddenError` (CNPJ without access to the note), `UnauthorizedError` (expired/invalid certificate), `NotFoundError` (key does not exist), and `InvalidChaveAcessoError` (wrong format) **do not** fall back to local rendering — they propagate to the caller. Masking these errors with a degraded local PDF would hide a real problem (expired certificate, key typo, wrong CNPJ permission). ``` -------------------------------- ### Create nfse_eventos Table Source: https://fm-s.github.io/open-nfse/guide/integracao Schema for recording NF-e events such as cancellations and substitutions. It links to the authorized NF-e via `chave_acesso` and stores event details and the XML. ```sql CREATE TABLE nfse_eventos ( id BIGSERIAL PRIMARY KEY, chave_acesso CHAR(50) NOT NULL REFERENCES nfse_autorizadas(chave_acesso), tipo_evento VARCHAR(10) NOT NULL, -- 101101, 105102, ... num_seq_evento INT NOT NULL, xml_evento TEXT NOT NULL, dh_registro TIMESTAMPTZ NOT NULL, origem TEXT NOT NULL CHECK (origem IN ('emitido', 'recebido_dfe')), UNIQUE (chave_acesso, tipo_evento, num_seq_evento) ); ``` -------------------------------- ### Fake Client for Testing Source: https://fm-s.github.io/open-nfse/api-cheatsheet Provides a fake `NfseClient` implementation that is structurally compatible with `NfseClientLike` for testing purposes. Seeding API details are documented separately. ```APIDOC ```ts import { NfseClientFake, type NfseClientLike } from 'open-nfse/testing'; ``` Structurally compatible with `NfseClient` via `NfseClientLike`. API of seeding is documented in Testing with the fake. ``` -------------------------------- ### Substituir Nota Fiscal - Chamada Básica Source: https://fm-s.github.io/open-nfse/guide/substituir-cancelar Exemplo de como iniciar o processo de substituição de uma nota fiscal. A função `buildDps` ajuda a construir o objeto da nova nota, e a biblioteca preenche automaticamente o campo `subst` com a chave da nota original. ```typescript import { JustificativaSubstituicao, buildDps } from 'open-nfse'; const novaDps = buildDps({ emitente: { /* mesmo do original */ }, serie: '1', nDPS: '42', // obrigatório — use seu DpsCounter servico: { /* corrigido */ }, valores: { /* corrigido */ }, tomador: { /* ... */ }, // subst é auto-preenchido pela lib com chaveOriginal }); const r = await cliente.substituir({ chaveOriginal: '21113002200574753000100000000000146726037032711025', novaDps, autor: { CNPJ: '00574753000100' }, cMotivo: JustificativaSubstituicao.Outros, xMotivo: 'Correção de valor', }); ``` -------------------------------- ### Simulação de Emissão (Dry-Run) Source: https://fm-s.github.io/open-nfse/guide/emitir Realiza uma simulação de emissão de nota fiscal sem interagir com a rede ou consumir o contador de notas. Ideal para testes em CI, auditoria de payloads ou depuração offline. ```typescript const dry = await cliente.emitir({ ...params, dryRun: true }); dry.xmlDpsAssinado; // XML assinado (RSA-SHA256 + exc-c14n + enveloped) dry.xmlDpsGZipB64; // payload gzip+base64, pronto para POST manual se quiser ``` -------------------------------- ### consultarRetencoes Source: https://fm-s.github.io/open-nfse/api/classes/NfseClient Retrieves the ISSQN withholding configuration for a given municipality and competence period. ```APIDOC ## consultarRetencoes() ### Description Withholding configuration of ISSQN for the municipality for a given competence period. ### Parameters #### Parameters - **codigoMunicipio** (string) - Required - The municipality code. - **competencia** (string | Date) - Required - The competence period (year-month). - **options?** (ConsultaOptions) - Optional - Additional query options. ### Returns - `Promise` - A promise that resolves with the withholding configuration. ``` -------------------------------- ### Consultar Alíquota de ISSQN Source: https://fm-s.github.io/open-nfse/guide/parametros Consulta a alíquota de ISSQN parametrizada para um trio de município, serviço e competência. O resultado é um Record onde a chave é o código do serviço e o valor é um array de alíquotas. ```APIDOC ## consultarAliquota(codMunicipio, codServico, competencia) ### Description Alíquota de ISSQN parametrizada para o trio município + serviço + competência. ### Method `consultarAliquota` ### Parameters #### Path Parameters - **codMunicipio** (string) - Required - Código do município. - **codServico** (string) - Required - Código do serviço. - **competencia** (string) - Required - Data de competência (YYYY-MM-DD). ### Request Example ```typescript const r = await cliente.consultarAliquota('2111300', '250101', '2026-03-01'); // r.aliquotas é um Record for (const aliq of r.aliquotas['250101'] ?? []) { console.log(aliq.incidencia, aliq.aliquota, aliq.dataInicio); } ``` ### Response #### Success Response - **aliquotas** (Record) - Um registro onde a chave é o código do serviço e o valor é um array de objetos Aliquota. #### Response Example ```json { "aliquotas": { "250101": [ { "incidencia": "1", "aliquota": "2.5", "dataInicio": "2026-01-01" } ] } } ``` ``` -------------------------------- ### Consultar Alíquota de ISSQN Source: https://fm-s.github.io/open-nfse/guide/parametros Consulta a alíquota de ISSQN para um trio de município, serviço e competência. O resultado é um Record onde a chave é o código do serviço e o valor é um array de alíquotas. ```typescript const r = await cliente.consultarAliquota('2111300', '250101', '2026-03-01'); // r.aliquotas é um Record for (const aliq of r.aliquotas['250101'] ?? []) { console.log(aliq.incidencia, aliq.aliquota, aliq.dataInicio); } ``` -------------------------------- ### prepareStackTrace Static Method Source: https://fm-s.github.io/open-nfse/api/classes/ServerError Customizes the formatting of stack traces. This method is inherited from the parent class. ```APIDOC ## prepareStackTrace() ```ts static prepareStackTrace(err: Error, stackTraces: CallSite[]): any; ``` ### Parameters - **err** (Error) - The error object. - **stackTraces** (CallSite[]) - An array of CallSite objects representing the stack trace. ### Returns - `any` - The formatted stack trace. ``` -------------------------------- ### Create nfse_pending_events Table Source: https://fm-s.github.io/open-nfse/guide/integracao Defines the schema for `nfse_pending_events`, which serves as a backing store for the `RetryStore`. It accommodates various event kinds like emissions and cancellations with nullable columns for different event types. ```sql CREATE TABLE nfse_pending_events ( id TEXT PRIMARY KEY, kind TEXT NOT NULL CHECK (kind IN ( 'emission', 'cancelamento_simples', 'cancelamento_por_substituicao', 'rollback_cancelamento' )), -- emission: id_dps CHAR(45), emitente_cnpj CHAR(14), serie VARCHAR(5), ndps BIGINT, -- eventos: chave_nfse CHAR(50), chave_substituta CHAR(50), tipo_evento VARCHAR(10), n_ped_reg_evento VARCHAR(3), c_motivo VARCHAR(2), x_motivo TEXT, -- comum: xml_assinado TEXT NOT NULL, first_attempt_at TIMESTAMPTZ NOT NULL, last_attempt_at TIMESTAMPTZ NOT NULL, last_error_msg TEXT NOT NULL, last_error_name TEXT NOT NULL, last_error_transient BOOLEAN NOT NULL, CHECK ( (kind = 'emission' AND id_dps IS NOT NULL AND emitente_cnpj IS NOT NULL) OR (kind <> 'emission' AND chave_nfse IS NOT NULL AND tipo_evento IS NOT NULL) ) ); CREATE INDEX ix_pending_kind ON nfse_pending_events (kind); CREATE INDEX ix_pending_chave ON nfse_pending_events (chave_nfse) WHERE chave_nfse IS NOT NULL; CREATE INDEX ix_pending_emitente ON nfse_pending_events (emitente_cnpj) WHERE emitente_cnpj IS NOT NULL; CREATE INDEX ix_pending_last_attempt ON nfse_pending_events (last_attempt_at); ``` -------------------------------- ### Fetch NF-e by Key Source: https://fm-s.github.io/open-nfse/guide/getting-started Consult an NF-e using its access key. This operation does not require a DPS counter or retry store, making the minimum client configuration sufficient. ```typescript const resultado = await cliente.fetchByChave( '21113002200574753000100000000000146726037032711025', ); console.log(resultado.nfse.infNFSe.emit.xNome); // "VOGA LTDA" console.log(resultado.nfse.infNFSe.valores.vLiq); // 51.60 ``` -------------------------------- ### Fetch NFS-e by NSU (Incremental Pagination) Source: https://fm-s.github.io/open-nfse/guide/consultar Use `fetchByNsu` to paginate through NFS-e documents incrementally using the NSU (Número Sequencial Único). This is suitable for processing new documents as they are issued. ```typescript let ultimoNsu = Number(await db.getUltimoNsu(cnpj) ?? 0); while (true) { const r = await cliente.fetchByNsu({ ultimoNsu }); for (const doc of r.documentos) { await db.salvar(doc); // persista antes de avançar o cursor console.log(doc.nsu, doc.tipoDocumento, doc.chaveAcesso); console.log(doc.xmlDocumento); // já descomprimido } await db.setUltimoNsu(cnpj, r.ultimoNsu); if (r.status === 'NENHUM_DOCUMENTO_LOCALIZADO' || r.ultimoNsu === ultimoNsu) break; ultimoNsu = r.ultimoNsu; } ``` -------------------------------- ### Schema SQL para Tabela DPS Counters Source: https://fm-s.github.io/open-nfse/guide/integracao Estrutura da tabela `dps_counters` para gerenciar o sequenciamento do `nDPS` por `emitente` e `serie`. É crucial usar `UPDATE ... RETURNING` para garantir a atomicidade e evitar problemas com a Receita Federal. ```sql CREATE TABLE dps_counters ( emitente_id BIGINT NOT NULL REFERENCES emitentes(id) ON DELETE RESTRICT, serie VARCHAR(5) NOT NULL CHECK (serie ~ '^\d{1,5}$'), proximo_ndps BIGINT NOT NULL DEFAULT 1 CHECK (proximo_ndps BETWEEN 1 AND 999999999999999), PRIMARY KEY (emitente_id, serie) ); ``` -------------------------------- ### Schema SQL para Tabela NSU Cursors Source: https://fm-s.github.io/open-nfse/guide/integracao Define a tabela `nsu_cursors` para gerenciar o cursor de distribuição por CNPJ, permitindo o processamento incremental de lotes de `fetchByNsu`. É importante salvar o `ultimoNsu` após cada processamento bem-sucedido. ```sql CREATE TABLE nsu_cursors ( cnpj CHAR(14) PRIMARY KEY CHECK (cnpj ~ '^\d{14}$'), ultimo_nsu BIGINT NOT NULL DEFAULT 0, updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ``` -------------------------------- ### Error.prepareStackTrace static method Source: https://fm-s.github.io/open-nfse/api/classes/ClientClosedError Allows customization of the stack trace format. It takes an error object and an array of stack trace call sites, returning a formatted string or any other value. ```APIDOC ## prepareStackTrace() ts ```typescript static prepareStackTrace(err: Error, stackTraces: CallSite[]): any; ``` ### Parameters Parameter| Type ---|--- `err`| `Error` `stackTraces`| `CallSite`[] ### Returns `any` ### See https://v8.dev/docs/stack-trace-api#customizing-stack-traces ### Inherited from `OpenNfseError`.`prepareStackTrace` ``` -------------------------------- ### Schema SQL para Tabela NFSe Rejeições Source: https://fm-s.github.io/open-nfse/guide/integracao Estrutura da tabela `nfse_rejeicoes` para registrar rejeições permanentes de NFS-e. Inclui campos para código, descrição, mensagens de erro e um índice na coluna `codigo` para facilitar a busca. ```sql CREATE TABLE nfse_rejeicoes ( id BIGSERIAL PRIMARY KEY, id_dps CHAR(45) NOT NULL, codigo VARCHAR(20) NOT NULL, descricao TEXT NOT NULL, mensagens JSONB NOT NULL, -- array completo de MensagemProcessamento created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX ix_rejeicoes_codigo ON nfse_rejeicoes (codigo); ``` -------------------------------- ### BuildSubstituicaoXmlParams Interface Source: https://fm-s.github.io/open-nfse/api/interfaces/BuildSubstituicaoXmlParams The BuildSubstituicaoXmlParams interface defines the parameters required to build an XML for a substitution event. It includes details about the original and substitute keys, reason for substitution, and optional event details. ```APIDOC ## Interface: BuildSubstituicaoXmlParams ### Description This interface defines the parameters for building an XML for a substitution event. ### Properties - **chaveOriginal** (string) - Required - The original key of the event. - **chaveSubstituta** (string) - Required - The substitute key for the event. - **cMotivo** (JustificativaSubstituicao) - Required - The reason code for the substitution. - **autor** (AutorEvento) - Required - Information about the event author. - **xMotivo** (string) - Optional - A detailed description of the substitution reason. - **nPedRegEvento** (string) - Optional - The registration request number for the event. - **tpAmb** (TipoAmbienteDps) - Optional - The type of environment. - **verAplic** (string) - Optional - The application version. - **dhEvento** (Date) - Optional - The date and time of the event. - **ambGer** (AmbienteGeradorEvento) - Optional - The generator environment for the event. ``` -------------------------------- ### Type Dependencies with NfseClientLike Source: https://fm-s.github.io/open-nfse/guide/testing Type your service's client dependency as `NfseClientLike` to allow both the real `NfseClient` and the `NfseClientFake` to be injected. This enables seamless switching between production and testing environments. ```typescript import type { NfseClientLike } from 'open-nfse/testing'; export class PedidoService { constructor(private readonly nfse: NfseClientLike) {} async criar(pedido: Pedido) { return this.nfse.emitir({ ... }); } } // em prod: // new PedidoService(new NfseClient({ ambiente, certificado })); // em teste: // new PedidoService(new NfseClientFake()); ```