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-js

v0.3.0

Published

Spec-first TypeScript toolkit for Brazil's National NFS-e standard.

Readme

nfse-js

npm version CI Node.js npm downloads License

Spec-first TypeScript tools for Brazil's National NFS-e standard.

nfse-js builds and validates National DPS XML and processes National NFS-e documents without coupling your application to a CLI, YAML format, framework, storage layer, certificate provider, or municipal legacy layout.

The library produces the DPS submitted by a contributor. SEFIN validates that DPS and, when it accepts the submission, produces the NFS-e.

Capability status

| Capability | Status | Meaning | | --- | --- | --- | | Typed DPS model | Complete for reachable v1.01 TCInfDPS types | Every reachable complex type has an explicit TypeScript representation | | DPS serialization | Complete for the modeled v1.01 structure | Named coverage fixtures serialize deterministically and validate against the bundled XSD | | XSD structural validation | Available for DPS, NFS-e, and events | Proves conformance to the bundled schema structure, not acceptance by SEFIN | | Local semantic validation | Partial deterministic coverage | Implements documented facets and locally decidable National rules tracked in the coverage manifest | | Authoritative code-table validation | Available with supplied provider | Checks generally applicable ISO, IBGE/National location, BACEN, service, NBS, and IBS/CBS code membership without fetching or bundling tables | | Signing and transport | Implemented with synthetic tests | XMLDSig defaults, active wrappers, and response shapes still require live confirmation | | Restricted-production evidence | Not yet captured | No sanitized accepted and rejected issuance evidence is retained |

An XSD-valid DPS can still be rejected because of National business rules, authoritative reference data, municipal parameters, taxpayer state, signature requirements, or the active SEFIN API contract.

For the detailed implementation state, known limitations, architectural decisions, and the completion roadmap, see PROJECT_STATUS.md. Machine-readable DPS coverage claims are tracked in schemas/1.01/dps-coverage.json.

Task guides and the generated public export index are available in docs/. Runtime and release guarantees are defined in SUPPORT.md, COMPATIBILITY.md, and SECURITY.md.

Design

  • National NFS-e is the only wire standard.
  • Domain input is plain typed data, not files or configuration formats.
  • Decimal values stay strings and are serialized exactly.
  • Core XML generation is deterministic and synchronous.
  • XML parsing rejects DTD/entity declarations and applies byte/depth limits.
  • The root entry point preserves the core, error, and XSD compatibility surface.
  • Parsing, events, parameters, signing, and transport use explicit subpath imports.
  • XML signing is optional and isolated behind a subpath import.
  • SEFIN transport is optional and isolated behind a subpath import.
  • Official schemas are committed unchanged with recorded source URLs and hashes.
  • Every TCInfDPS descendant has an explicit type and serializer.
  • XSD choices are represented by TypeScript unions.

Install

npm install nfse-js

Node.js 20 or newer is required.

Build an unsigned DPS

import { createDps, decimal, serializeDps } from "nfse-js/core";

const dps = createDps({
  infDPS: {
    tpAmb: "2",
    dhEmi: "2026-06-11T10:30:00+01:00",
    verAplic: "my-application",
    serie: "1",
    nDPS: "1",
    dCompet: "2026-06-11",
    tpEmit: "1",
    cLocEmi: "3550308",
    prest: {
      CNPJ: "12345678000195",
      regTrib: { opSimpNac: "1", regEspTrib: "0" },
    },
    toma: {
      CPF: "12345678909",
      xNome: "Example Customer",
    },
    serv: {
      locPrest: { cLocPrestacao: "3550308" },
      cServ: {
        cTribNac: "010101",
        xDescServ: "Software consulting",
      },
    },
    valores: {
      vServPrest: { vServ: decimal("100.00") },
      trib: {
        tribMun: { tribISSQN: "1", tpRetISSQN: "1" },
        totTrib: { indTotTrib: "0" },
      },
    },
  },
});

const xml = serializeDps(dps, { pretty: true });

createDps derives the official 45-character Id from the municipality, selected issuer CNPJ/CPF, series, and DPS number. You can supply infDPS.Id when importing an existing document.

Fiscal decimal fields have XSD-specific constructors: decimal15v2, decimal3v2, decimal2v2, and decimal1v2. decimal() is the decimal15v2 monetary default.

Validate local rules

import {
  validateDps,
  validateDpsWithReferenceData,
  validateDpsWithMunicipalParameters,
} from "nfse-js/core";

const result = validateDps(dps);

const referenceResult = validateDpsWithReferenceData(dps, referenceData);

const municipalResult = validateDpsWithMunicipalParameters(dps, {
  municipality: "3550308",
  serviceCode: "010101",
  providerMunicipalRegistrationRequired: false,
  allowedDeductionModes: ["percentage", "value"],
  allowedWithholding: ["1", "2"],
});

Local validation covers centralized XSD facets, CPF/CNPJ check digits, real dates, DPS identifier consistency, and deterministic cross-field rules from the official v1.01 Annex I. Issues include a stable category, official rejection code where documented, and source metadata. Use validateDps(dps, { mode: "fail-fast" }) to stop at the first issue.

Reference-data validation accepts caller-supplied authoritative datasets and performs no network calls or bundled-snapshot fallback. It distinguishes a confirmed unknown code from an unavailable dataset and reports source metadata for audit. See Reference data validation for the provider contract and covered fields.

Municipal validation accepts already-resolved parameters and also performs no network calls. Rules that require SEFIN, CNC, municipal parameter, taxpayer state, or IBS/CBS calculator state are intentionally not guessed by the pure validator.

Validate against the XSD

import { validateDpsXml } from "nfse-js/validation";

await validateDpsXml(xml);

Validation uses libxml2 compiled to WebAssembly. Importing nfse-js/core does not load it.

To collect errors rather than throw:

const result = await validateDpsXml(xml, { throwOnInvalid: false });

Other validators are available for generated NFS-e documents and events: validateNfseXml, validateEventRequestXml, validateEventXml, and the generic validateXml.

Parse received documents

import {
  parseDpsXml,
  parseEventRequestXml,
  parseNfseXml,
  parseRegisteredEventXml,
  parseSefinDocumentResponse,
} from "nfse-js/parsing";

const parsedDps = parseDpsXml(xml);
const parsedNfse = parseNfseXml(nfseXml);
const parsedRequest = parseEventRequestXml(eventRequestXml);
const parsedEvent = parseRegisteredEventXml(eventXml);

const response = parseSefinDocumentResponse(responseBody, {
  status: 200,
  contentType: "application/json",
});

Parsers preserve the exact original XML, parsed signature material, and raw XML trees alongside typed document fields. SEFIN JSON envelopes are parsed without relying on undocumented property names: plain XML and gzip/base64 XML documents are discovered recursively, while rejection payloads remain available as structured JSON.

Sign and verify XML

import {
  createPkcs12Signer,
  signDpsXml,
  verifyNationalXmlSignature,
} from "nfse-js/signing";

const signer = createPkcs12Signer(pfxBytes, { password: process.env.PFX_PASSWORD });
const signedXml = await signDpsXml(xml, signer);

const verification = verifyNationalXmlSignature(signedXml, {
  trustedCertificates: [trustedCertificatePem],
  requireTrustedCertificate: true,
});

PEM private keys and certificate chains are supported through createPemSigner. Applications using an HSM, cloud KMS, or remote signing service can implement the asynchronous XmlSigner interface without exporting private key material.

Signing targets the document information element by Id, inserts the enveloped signature in schema order, and supports DPS, generated NFS-e, event requests, and registered events. Verification checks the digest, signature, reference target, algorithm profile, certificate dates, and an optional caller-provided trust chain. Only cryptographically authenticated referenced XML is returned.

The accessible National NFS-e documentation requires W3C XML Digital Signature but does not publish the canonicalization, digest, and signature algorithm URIs. The default profile therefore uses inclusive C14N 1.0 and RSA-SHA256, and is explicit and configurable. Confirm this profile against the restricted SEFIN environment before production use.

Call SEFIN and ADN APIs

import {
  createNodeHttpTransport,
  createSefinClient,
} from "nfse-js/transport";

const transport = createNodeHttpTransport({
  tls: {
    pfx: connectionCertificateBytes,
    passphrase: process.env.PFX_PASSWORD,
  },
});

const sefin = createSefinClient({
  environment: "restricted-production",
  transport,
});

const result = await sefin.submitDps(signedXml, {
  signal: abortController.signal,
  timeoutMs: 30_000,
});

The client models the official restricted-production and production hosts and the documented NFS-e, DPS, event, and contributor ADN routes. It supports DPS submission, NFS-e and DPS reconciliation queries, event registration and queries, and contributor ADN document/event queries. NSU document lookups support the optional CNPJ selector for another establishment with the same CNPJ root as the connection certificate.

Connection certificates are configured on the HTTP transport and remain independent from XML-signing credentials. GET and HEAD requests retry transient network failures and selected HTTP statuses; POST operations are never retried automatically because the official material does not document a safe idempotency mechanism. Logs contain operation metadata only, not URLs, headers, taxpayer identifiers, XML, certificates, or response bodies.

The public manuals describe DPS submission as XML and event communication as JSON, but the accessible documentation does not publish every current Swagger wrapper property. Raw XML and JSON payloads are supported directly. When the active environment requires gzip/base64 JSON, use gzipBase64XmlJsonPayload(xml, propertyName) with the property name from that environment's Swagger instead of relying on a guessed field.

Build event requests

import { createEventRequest, serializeEventRequest } from "nfse-js/events";
import { signEventRequestXml } from "nfse-js/signing";

const request = createEventRequest({
  infPedReg: {
    tpAmb: "2",
    verAplic: "my-application",
    dhEvento: "2026-06-12T10:00:00-03:00",
    autor: { CNPJAutor: "12345678000195" },
    chNFSe: accessKey,
    evento: {
      code: "e101101",
      cMotivo: "1",
      xMotivo: "Documento emitido incorretamente",
    },
  },
});

const eventXml = serializeEventRequest(request);
const signedEventXml = await signEventRequestXml(eventXml, signer);

All 16 request variants in the v1.01 event schema are discriminated TypeScript unions. The library generates the official fixed descriptions and PRE identifier, validates local facets and references, serializes in XSD order, and reuses the signing and transport modules for registration.

Resolve municipal parameters

import { createMunicipalParameterResolver } from "nfse-js/parameters";

const parameters = createMunicipalParameterResolver({
  client: sefin,
  ttlMs: 5 * 60_000,
  map(snapshot) {
    return mapCurrentSwaggerResponses(snapshot);
  },
});

const resolved = await parameters.resolve({
  municipality: "3550308",
  serviceCode: "010101",
  contributorTaxId: "12345678000195",
});

The resolver fetches convention, service, and optional contributor parameters, deduplicates concurrent requests, applies bounded TTL caching, and returns the same ResolvedMunicipalParameters contract consumed by validateDpsWithMunicipalParameters. The current public manuals do not define stable response fields, so raw responses remain lossless and applications provide an explicit mapper for the active Swagger version.

Entry points

| Import | Purpose | | --- | --- | | nfse-js | Full public API | | nfse-js/core | Types, DPS IDs, semantic validation, XML generation | | nfse-js/events | Event IDs, typed request construction, validation, XML | | nfse-js/parameters | Municipal parameter resolution and bounded caching | | nfse-js/parsing | Secure DPS, NFS-e, event, and SEFIN response parsing | | nfse-js/signing | XML signing, credentials, and signature verification | | nfse-js/transport | SEFIN/ADN clients, retries, timeouts, and mutual TLS | | nfse-js/validation | XSD validation | | nfse-js/schemas | Access to bundled National NFS-e schemas |

Scope

This library does not implement ABRASF or municipality-specific legacy formats. Municipal configuration is still relevant to National NFS-e, but it is data obtained from National APIs rather than a separate DPS layout.

Remaining work includes completing locally decidable semantic validation, capturing restricted-production conformance evidence, independently verifying XMLDSig interoperability, and exercising releases in real consumer applications.

Production readiness

The library has broad implementation coverage, automated tests, cross-platform CI, package-consumer checks, security controls, and release automation. It should still be treated as an implementation candidate until the following evidence exists:

  • successful and rejected DPS submissions have been exercised in the official restricted-production environment and retained as sanitized fixtures;
  • the default XMLDSig canonicalization, digest, and signature algorithms have been confirmed against SEFIN and independently verified outside this package;
  • event registration and municipal-parameter responses have been exercised against the active restricted-production Swagger contracts;
  • remaining locally decidable National business rules and optional DPS schema branches have exhaustive positive and negative coverage;
  • certificate revocation and ICP-Brasil taxpayer identity requirements have an agreed production policy;
  • official schema updates have a publisher-authenticated provenance or digest channel, rather than relying only on an operator-supplied hash;
  • release candidates have been exercised by multiple real applications with different document profiles, certificate providers, and deployment environments.

Until those conditions are met, validate generated XML against the bundled XSD, keep POST retry decisions application-controlled, verify certificates against application-provided trust anchors, and test the exact taxpayer, municipality, service, and event flows in restricted production before relying on the library operationally.

The detailed evidence requirements and current limitations are tracked in PROJECT_STATUS.md.

Help wanted

External usage and conformance evidence are now more valuable than adding another abstraction. Contributions are especially useful in these areas:

  • Real consumers: integrate a release candidate into an application and report the Node.js version, runtime, package entry points, document features, certificate provider, and any compatibility problems encountered.
  • Restricted-production testing: help exercise accepted and rejected DPS issuance, reconciliation queries, events, and municipal parameters. Sanitized request/response fixtures and current Swagger observations are particularly valuable.
  • Independent signature interoperability: verify an nfse-js signature with another XMLDSig implementation, or provide a compatible fixture produced by Java, .NET, OpenSSL-based tooling, an HSM, or a cloud signing service.
  • National rule review: map remaining locally decidable rules from official manuals and technical notes to source references, rejection codes, and positive/negative tests.
  • Schema provenance: identify an official authenticated channel for schema archive digests or publisher signatures.
  • Deployment diversity: test ESM and CommonJS consumers on supported Node versions, Windows/macOS/Linux, serverless platforms, containers, and bundlers.

Please open an issue or pull request with a reproducible description and the smallest safe fixture possible. Never publish private keys, certificate passwords, taxpayer secrets, or unsanitized fiscal documents. Security vulnerabilities should follow SECURITY.md; general contribution guidance is in CONTRIBUTING.md.

Schema sources and hashes

The v1.01 schemas were published by the Brazilian National NFS-e project on February 9, 2026. See schemas/manifest.json for the official source URL, retrieval date, hashes, and a documented libxml2 compatibility adjustment applied only to the generated runtime copy.

Applications can pin a supported standard version explicitly:

import {
  getNationalNfseSchemaSet,
  SUPPORTED_NATIONAL_NFSE_VERSIONS,
} from "nfse-js/schemas";

const schemas = getNationalNfseSchemaSet("1.01");

SUPPORTED_NATIONAL_NFSE_VERSIONS is the authoritative list. Supporting a new version requires adding a separate immutable schema directory and public type support; an existing version is never replaced in place.

Maintainers can stage an official directory or ZIP bundle for review:

npm run schema:stage -- \
  --source ./reference-docs/nfse/anexos \
  --version 1.01

The command writes schemas and a hash-based diff report under the ignored .schema-staging/ directory. It never edits the supported bundle. ZIP inputs require the unzip command. Remote downloads are restricted to official gov.br HTTPS URLs and require an independently verified archive digest:

npm run schema:stage -- \
  --source https://www.gov.br/path/to/official-schemas.zip \
  --sha256 <verified-archive-sha256> \
  --version 1.01

Every redirect is revalidated and the verified final URL and archive digest are recorded in the report. Technical-note review state is tracked separately in schemas/technical-notes.json.

Development checks

npm run verify
npm run test:coverage
npm run benchmark

npm run docs:api regenerates the committed API export reference. The normal verification command fails when that reference is stale.

License

MIT