npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nfse-nacional

v0.1.1

Published

SDK TypeScript para emissão de NFS-e Nacional (SEFIN) — DPS, assinatura XMLDSig, DANF-Se em PDF e preview

Downloads

85

Readme

nfse-nacional

SDK TypeScript para emissão de NFS-e Nacional via API SEFIN do governo federal. Funciona com Node.js ≥ 18 e Bun ≥ 1.0.


O que é

O nfse-nacional é um SDK TypeScript para integração com a API SEFIN Nacional — a plataforma do governo federal para emissão de Nota Fiscal de Serviço eletrônica (NFS-e) pelos municípios aderentes ao programa.

Ele cuida de toda a pipeline técnica:

Seus dados  →  DPS (XML)  →  XMLDSig (RSA-SHA256)  →  GZip+Base64  →  API SEFIN  →  NFS-e

E também gera a DANF-Se (documento auxiliar da NFS-e) em HTML ou PDF, com suporte a prévia antes da emissão.


Funcionalidades

| Área | Recurso | |---|---| | Emissão | Monta, valida, assina e envia o DPS à API SEFIN | | Assinatura digital | XMLDSig RSA-SHA256 com certificado A1 (.pfx / buffer) | | Compressão | GZip + Base64 (formato obrigatório da API) | | mTLS | Autenticação mútua com certificado digital | | Validação | Schema Zod + regras de negócio antes do envio | | Consulta | NFS-e por chave de acesso, DPS por ID, eventos por tipo | | Cancelamento | Registro de evento com pré-verificação e erros tipados | | DANF-Se | Renderiza HTML e gera PDF via Puppeteer | | Preview | Gera DANF-Se com marca d'água antes da emissão | | Parser XML | Converte XML da NFS-e em objetos TypeScript | | Utilitários | Formatação de CPF/CNPJ, geração de IDs, cálculo de tributos |


Compatibilidade

| Runtime | Versão mínima | Observações | |---|---|---| | Node.js | 18.0.0 | Testado com 18 LTS e 20 LTS | | Bun | 1.0.0 | Runtime principal de desenvolvimento |

A build gerada (dist/) usa ESM puro e é compatível com qualquer ambiente que suporte import.


Instalação

# npm
npm install nfse-nacional

# yarn
yarn add nfse-nacional

# pnpm
pnpm add nfse-nacional

# bun
bun add nfse-nacional

Geração de DANF-Se em PDF (opcional)

A geração de PDF usa Puppeteer, que é uma dependência opcional. Instale apenas se precisar de PDF:

npm install puppeteer
# ou
bun add puppeteer

Sem Puppeteer, a geração de HTML da DANF-Se funciona normalmente. Apenas a conversão para PDF requer o Chrome headless.


Início rápido

1. Configure o contexto

import { ContribuinteService, TipoAmbiente, type NfseContext } from 'nfse-nacional'

const context: NfseContext = {
  ambiente: TipoAmbiente.Homologacao,   // ou TipoAmbiente.Producao
  certificatePath: './certificado.pfx', // caminho para o arquivo .pfx
  certificatePassword: 'senha_cert',
  codigoMunicipio: '3106200',           // código IBGE 7 dígitos (município do prestador)
}

Alternativamente, carregue o certificado em memória (ideal para ambientes serverless):

import { readFile } from 'node:fs/promises'

const context: NfseContext = {
  ambiente: TipoAmbiente.Homologacao,
  certificateData: await readFile('./certificado.pfx'),  // ArrayBuffer | Buffer
  certificatePassword: 'senha_cert',
  codigoMunicipio: '3106200',
}

2. Monte e emita o DPS

import {
  ContribuinteService,
  validateDps,
  TipoAmbiente,
  EmitenteDPS,
  TributacaoIssqn,
  TipoRetencaoIssqn,
  OpcaoSimplesNacional,
  RegimeEspecialTributacao,
  generateDpsId,
  generateNumDps,
  formatDhEmissao,
  formatDataCompetencia,
  type DpsData,
} from 'nfse-nacional'

const numeroDps = generateNumDps()
const cnpjPrestador = '00000000000000'   // substitua pelo CNPJ real
const codIbge = '3106200'               // código IBGE do município

const dps: DpsData = {
  infDps: {
    id: generateDpsId(cnpjPrestador, codIbge, '001', numeroDps),
    tipoAmbiente: TipoAmbiente.Homologacao,
    dataEmissao: formatDhEmissao(new Date(), -3),
    numeroDps,
    serie: '001',
    dataCompetencia: formatDataCompetencia(),
    tipoEmitente: EmitenteDPS.Prestador,
    codigoLocalEmissao: codIbge,

    prestador: {
      cnpj: cnpjPrestador,
      regimeTributario: {
        opSimpNac: OpcaoSimplesNacional.NaoOptante,
        regEspTrib: RegimeEspecialTributacao.Nenhum,
      },
    },

    tomador: {
      cnpj: '11111111111111',
      nome: 'Empresa Tomadora LTDA',
      endereco: {
        cMun: '3550308',
        cep: '01310100',
        xLgr: 'Avenida Paulista',
        nro: '1000',
        xBairro: 'Bela Vista',
      },
    },

    servico: {
      localPrestacao: { cLocPrestacao: codIbge },
      codigoServico: {
        cServTribNac: '010100163',  // cód. tributação nacional
        cNBSPrinc: '109102000',     // cód. NBS — consulte tabela oficial
      },
      xDescServ: 'Descrição do serviço prestado.',
    },

    valores: { vServico: 1000.00 },

    tributacao: {
      issqn: {
        tributacaoIssqn: TributacaoIssqn.TributadaMunicipioPrestador,
        tipoRetencaoIssqn: TipoRetencaoIssqn.NaoRetido,
      },
      federal: { cstPisCofins: '00' },
      percentualTotalTributosFederais: 11.33,
      percentualTotalTributosEstaduais: 0.00,
      percentualTotalTributosMunicipais: 2.00,
    },
  },
}

// Valida antes de enviar (opcional — emitir() também valida internamente)
const validation = validateDps(dps)
if (!validation.isValid) {
  console.error(validation.errors)
  process.exit(1)
}

const service = new ContribuinteService(context)
const response = await service.emitir(dps)

console.log('cStat      :', response.cStat)       // '100' = aprovado
console.log('xMotivo    :', response.xMotivo)
console.log('chaveAcesso:', response.chaveAcesso)
console.log('nNFSe      :', response.nfse?.infNfse?.nNFSe)

Cancelamento de NFS-e

import {
  ContribuinteService,
  TipoEvento,
  MotivoEventoCancelamento,
  NfseNaoEncontradaError,
  NfseJaCanceladaError,
} from 'nfse-nacional'

const service = new ContribuinteService(context)

try {
  const resultado = await service.cancelar({
    chNFSe: '31448052231674343000165...',  // chave de acesso (50 dígitos)
    tipoEvento: TipoEvento.Cancelamento,
    tipoAmbiente: TipoAmbiente.Homologacao,
    cnpjAutor: cnpjPrestador,
    cMotivo: MotivoEventoCancelamento.ErroNaEmissao,
    xMotivo: 'Nota emitida para fins de teste.',
  })

  console.log('cStat  :', resultado.cStat)
  console.log('xMotivo:', resultado.xMotivo)

} catch (err) {
  if (err instanceof NfseNaoEncontradaError) {
    // Nota não existe na SEFIN — cancelamento abortado pelo SDK
    console.error('NFS-e nao encontrada:', err.chaveAcesso)
  } else if (err instanceof NfseJaCanceladaError) {
    // API retornou E0840 — nota ja tem cancelamento vinculado
    console.warn('NFS-e ja esta cancelada:', err.chaveAcesso)
  } else {
    throw err
  }
}

O método cancelar realiza uma consulta prévia antes de enviar o evento. Se a NFS-e não for encontrada, lança NfseNaoEncontradaError sem chamar o endpoint de eventos. Se já estiver cancelada (E0840), lança NfseJaCanceladaError.


Geração da DANF-Se

A partir do XML da NFS-e (retornado pela API)

import { DanfeService } from 'nfse-nacional'
import { writeFileSync } from 'node:fs'

const danfe = new DanfeService()

// PDF
const result = await danfe.generateFromXml(xmlNfse, {
  chaveAcesso: response.chaveAcesso,  // necessário quando o XML não contém <chNFSe>
})
writeFileSync('nota.pdf', result.pdfBytes)

// HTML (sem Puppeteer)
console.log(result.html)

A partir do GZip+Base64 retornado pela API

const result = await danfe.generateFromGzipB64(response.nfseXmlGZipB64, {
  chaveAcesso: response.chaveAcesso,
})
writeFileSync('nota.pdf', result.pdfBytes)

Preview antes da emissão (sem certificado, sem API)

Gera uma DANF-Se com marca d'água "PRÉVIA — SEM VALOR FISCAL" a partir dos dados do DPS, sem necessidade de certificado ou conexão com a API.

import { DanfeService, DanfePreviewFormat } from 'nfse-nacional'

const danfe = new DanfeService()

// Preview em HTML (sem Puppeteer)
const preview = await danfe.previewFromDps(dps.infDps, {
  format: DanfePreviewFormat.Html,
})
writeFileSync('preview.html', preview.html)

// Preview em PDF (requer Puppeteer)
const preview = await danfe.previewFromDps(dps.infDps, {
  format: DanfePreviewFormat.Pdf,
})
writeFileSync('preview.pdf', preview.pdfBytes!)

Referência da API

ContribuinteService

| Método | Descrição | |---|---| | emitir(dps) | Valida, assina e envia o DPS à API SEFIN. Retorna EmissaoNfseResponse. | | consultar(chaveAcesso) | Consulta uma NFS-e pela chave de acesso (50 dígitos). | | consultarDps(idDps) | Consulta a situação de um DPS pelo ID (42 dígitos numéricos). | | verificarDps(idDps) | Verifica se um DPS existe na SEFIN (retorna boolean). | | cancelar(evento) | Registra evento de cancelamento com pré-verificação. | | consultarEventos(chaveAcesso) | Lista todos os eventos de uma NFS-e. | | consultarEventosPorTipo(chave, tipo) | Lista eventos de um tipo específico (TipoEvento). | | consultarEvento(chave, tipo, seq?) | Consulta um evento específico por tipo e número sequencial. | | downloadDanfse(chaveAcesso) | Baixa a DANF-Se em PDF direto da SEFIN (quando disponível). | | consultarAliquota(codMun, codServ) | Consulta alíquota de ISSQN por município e código de serviço. | | consultarConvenio(codMunicipio) | Consulta parâmetros de convênio do município com a SEFIN. |

Erros tipados

| Classe | Quando é lançado | |---|---| | DpsValidationError | DPS inválido (schema/regras de negócio) antes de chamar a API | | NfseNaoEncontradaError | NFS-e não localizada na SEFIN durante pré-verificação do cancelamento | | NfseJaCanceladaError | API retornou E0840 — nota já possui cancelamento vinculado | | NfseApiError | Erro HTTP genérico da API SEFIN (acesse .statusCode e .body) |

DanfeService

| Método | Descrição | |---|---| | generateFromXml(xml, opts?) | Gera HTML + PDF a partir do XML da NFS-e. | | generateFromGzipB64(b64, opts?) | Gera HTML + PDF a partir do GZip+Base64 retornado pela API. | | generate(schema, opts?) | Gera HTML + PDF a partir de um NfseSchema já parseado. | | saveToFile(xml, path, isGzip?, opts?) | Gera o PDF e salva diretamente em arquivo. | | previewFromDps(dps, opts?) | Gera prévia com marca d'água antes da emissão. |

DanfeGenerateOptions

{
  chaveAcesso?: string   // injeta <chNFSe> quando ausente no XML
  isCancelled?: boolean  // exibe marca d'água de cancelamento
  danfe?: DanfeOptions   // opções de renderização (fonte, template customizado)
  pdf?: PdfOptions       // opções do Puppeteer (pageSize, etc.)
}

Funções utilitárias

// Geração de IDs
generateDpsId(cnpj, codMun, serie, numeroDps)  // ID no formato da SEFIN (45 chars)
generateNumDps()                               // número sequencial único (timestamp)

// Formatação de datas
formatDataCompetencia(date?)                   // 'YYYY-MM-DD'
formatDhEmissao(date, offsetHours)             // ISO 8601 com offset BRT

// Formatação de documentos
formatCpf(cpf)     // '000.000.000-00'
formatCnpj(cnpj)   // '00.000.000/0000-00'
formatCep(cep)     // '00000-000'

// Outros
calculateTax(base, aliquota)   // base × aliquota / 100
validateDps(dps)               // { isValid, errors }
parseNfseXml(xml)              // NfseSchema

Enums principais

import {
  TipoAmbiente,             // Producao = 1, Homologacao = 2
  EmitenteDPS,              // Prestador = 1, Tomador = 2, Intermediario = 3
  TributacaoIssqn,          // TributadaMunicipioPrestador = 1, ...
  TipoRetencaoIssqn,        // NaoRetido = 1, RetidoTomador = 2, RetidoIntermediario = 3
  OpcaoSimplesNacional,     // NaoOptante = 1, Optante = 2
  RegimeEspecialTributacao,
  TipoEvento,               // Todos os 15 tipos do XSD (cancelamento, manifestação, ofício)
  MotivoEventoCancelamento, // ErroNaEmissao = 1, ServicoNaoPrestado = 2, Outros = 9
  DanfePreviewFormat,       // Html = 'html', Pdf = 'pdf'
  DanfeEnvironment,         // Production = 1, Restricted = 2
} from 'nfse-nacional'

TipoEvento — tipos de evento do XSD

// Cancelamento (iniciado pelo contribuinte)
TipoEvento.Cancelamento                        // e101101 — cancelamento direto (requer cMotivo)
TipoEvento.CancelamentoPorSubstituicao         // e105102 — substituição por nova nota
TipoEvento.SolicitacaoAnaliseFiscal            // e101103 — pedido de análise fiscal
TipoEvento.CancelamentoDeferidoAnaliseFiscal   // e105104
TipoEvento.CancelamentoIndeferidoAnaliseFiscal // e105105

Configuração (NfseContext)

interface NfseContext {
  /** Ambiente de emissão */
  ambiente: TipoAmbiente

  /** Caminho para o .pfx em disco */
  certificatePath?: string

  /** Conteúdo do .pfx em memória (alternativa ao path) */
  certificateData?: ArrayBuffer | Buffer

  /** Senha do certificado .pfx */
  certificatePassword: string

  /** Código IBGE do município (7 dígitos) */
  codigoMunicipio?: string

  /** Endpoint customizado (sobrescreve o padrão da SEFIN) */
  endpoint?: { producao: string; homologacao: string }

  /**
   * Quando true, salva os XMLs gerados (antes e após assinatura)
   * na pasta debug/ antes de enviar à API.
   */
  debug?: boolean
}

Exemplos

A pasta examples/ contém scripts prontos para uso:

| # | Arquivo | Descrição | |---|---|---| | 1 | 1-homologacao.ts | Emissão em homologação — certificado via arquivo | | 2 | 1b-homologacao-buffer.ts | Emissão em homologação — certificado em memória (ArrayBuffer) | | 3 | 3-homologacao-pf.ts | Emissão com tomador pessoa física (CPF) | | 4 | 4-danfe.ts | Geração de DANF-Se a partir de um XML existente | | 5 | 5-emitir-e-danfe.ts | Emissão + geração automática da DANF-Se em PDF | | 6 | 6-preview-danfe.ts | Preview da DANF-Se antes da emissão (marca d'água) | | 7 | 7-consulta.ts | Consulta de NFS-e por chave de acesso ou ID do DPS | | 8 | 8-cancelamento.ts | Cancelamento de NFS-e com registro de evento |

Configurar e executar os exemplos

# 1. Copie o template de variáveis de ambiente
cp examples/.env.example examples/.env

# 2. Preencha examples/.env com seus dados reais:
#    CERT_PATH, CERT_PASSWORD, CNPJ_PRESTADOR, etc.

# 3. Execute um exemplo pelo número
bun run example 1   # ou 2, 3, 4, 5, 6, 7, 8

Dados sensíveis locais: Se preferir hardcodar os dados diretamente no código, crie um arquivo *.local.ts ao lado do exemplo (ex: 1-homologacao.local.ts). Esses arquivos são ignorados pelo git (.gitignore) e têm prioridade automática sobre o arquivo base quando você executa bun run example <n>.


Estrutura do projeto

nfse-nacional/
├── src/
│   ├── types/          # Enums, DTOs (InfDpsData, PrestadorData, …), NfseContext
│   ├── xml/            # DPS builder, NFS-e parser, builder de eventos
│   ├── crypto/         # Certificado A1 (node-forge), XMLDSig signer, compressão
│   ├── http/           # SefinClient — mTLS + parse de respostas da API
│   ├── service/        # ContribuinteService — orquestração de alto nível
│   ├── danfe/          # HTML renderer, PDF generator (Puppeteer), preview builder
│   ├── validator/      # Zod schema + regras de negócio (DPS validator)
│   ├── utils/          # CPF/CNPJ, ID generator, cálculo de tributos, endpoint resolver
│   └── index.ts        # Exports públicos do pacote
├── assets/
│   ├── templates/
│   │   └── danfe.html  # Template HTML da DANF-Se (customizável)
│   └── municipios.csv  # Tabela IBGE de municípios para lookup no PDF
├── tests/
│   ├── crypto/         # Testes de assinatura e compressão
│   ├── utils/          # Testes de utilitários
│   ├── validator/      # Testes do validador de DPS
│   ├── xml/            # Testes do builder e parser XML
│   ├── danfe/          # Testes do preview e renderização
│   └── e2e/            # Testes end-to-end contra o dist compilado
├── examples/           # Scripts de exemplo (veja acima)
├── dist/               # Build compilada (gerada por `bun run build`)
└── package.json

Desenvolvimento e contribuição

Pré-requisitos

# Clonar o repositório
git clone https://github.com/andrejfg/gerador-nfse-nacional-bun.git
cd gerador-nfse-nacional-bun

# Instalar dependências
bun install

Scripts disponíveis

bun run build          # Compila src/ → dist/ (JS + tipos)
bun run test           # Roda a suite de testes unitários e de integração
bun run test:e2e       # Roda os testes e2e contra o dist compilado
bun run test:coverage  # Testes com relatório de cobertura
bun run typecheck      # Verificação de tipos sem emitir arquivos
bun run lint           # Linting com Biome
bun run lint:fix       # Linting com auto-correção
bun run format         # Formatação com Biome
bun run example <n>    # Executa o exemplo de número <n> (1–8)

Rodando os testes

# Testes unitários (não requerem certificado nem API)
bun run test

# Testes e2e (requerem build prévia)
bun run build && bun run test:e2e

Workflow de contribuição

  1. Crie um branch a partir de main: git checkout -b feat/minha-funcionalidade
  2. Implemente as alterações com testes correspondentes
  3. Certifique-se que bun run test passa sem falhas
  4. Garanta que bun run typecheck não retorna erros
  5. Abra um Pull Request descrevendo o que foi alterado e por quê

Publicação (mantenedores)

# O hook prepublishOnly executa typecheck + test + build automaticamente
npm version patch   # ou minor / major
npm publish

Limitações conhecidas

  • São Paulo/SP usa sistema próprio (SOAP) e não é compatível com esta biblioteca. Consulte nfe.prefeitura.sp.gov.br.
  • DANF-Se em PDF requer Puppeteer (Chrome headless). Em ambientes sem interface gráfica (Docker, CI) instale o Chrome via apt-get install -y google-chrome-stable ou utilize puppeteer/chrome Docker image.
  • O bloco IBS/CBS (Reforma Tributária — NT 007/2026) é opcional durante o período de transição e omitido por padrão nos exemplos.

Referências


Licença

MIT © André Guimarães