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

@creativeproject/fiscal-gateway

v0.4.0

Published

SDK Node.js/TypeScript do Fiscal Gateway — emissão de NFS-e Padrão Nacional

Readme

@creativeproject/fiscal-gateway

SDK Node.js/TypeScript do Fiscal Gateway da Creative Project — emissão de NFS-e Padrão Nacional com uma chamada de função.

  • Zero dependências (usa fetch nativo — Node 18+)
  • ESM + CJS + tipos TypeScript completos
  • Retry automático com backoff para 429/5xx/falhas de rede (seguro: a emissão é idempotente)
  • Verificação de assinatura HMAC de webhooks embutida (com replay protection)

Instalação

npm install @creativeproject/fiscal-gateway

Uso

Emitir uma NFS-e

import { FiscalGateway } from '@creativeproject/fiscal-gateway';

const fiscal = new FiscalGateway({
  apiKey: process.env.FISCAL_API_KEY!,
  baseUrl: 'https://api.fiscal.creativeproject.com.br',
});

const nota = await fiscal.nfse.emit({
  organizationId: 'org_...',
  externalId: 'charge_987',          // seu ID — reenviar nunca duplica a nota
  customer: { name: 'João da Silva', cpfCnpj: '39053344705' },
  service: { description: 'Taxa de administração 06/2026', amount: 200.0 },
  metadata: { source: 'mylapro', contractId: 'contract_123' },
});
// nota.status === 'pending' — o resultado chega via webhook

Receber o resultado via webhook (recomendado)

import express from 'express';
import { createWebhookHandler } from '@creativeproject/fiscal-gateway';

const app = express();

// IMPORTANTE: express.raw — o HMAC é calculado sobre o corpo cru
app.post(
  '/hooks/fiscal',
  express.raw({ type: 'application/json' }),
  createWebhookHandler({
    secret: process.env.FISCAL_WEBHOOK_SECRET!, // retornado ao criar o endpoint
    onAuthorized: async (nota) => {
      await marcarCobrancaComNota(nota.externalId, nota.accessKey!);
    },
    onRejected: async (nota) => {
      await alertarOperacao(nota.externalId, nota.rejectionReason!);
    },
    onCancelled: async (nota) => { /* ... */ },
  }),
);

Ou verifique manualmente (qualquer framework):

import { verifyWebhook } from '@creativeproject/fiscal-gateway';

const event = verifyWebhook(rawBody, req.headers['x-fiscal-signature'], secret);
// lança WebhookVerificationError se a assinatura for inválida/expirada

Outras operações

// Consulta e polling (scripts/testes — em produção prefira webhooks)
const doc = await fiscal.nfse.get(id);
const final = await fiscal.nfse.waitForResult(id, { timeoutMs: 30_000 });

// Listagem, XML, DANFSe, cancelamento
const lista = await fiscal.nfse.list({ status: 'authorized', limit: 20 });
const xml = await fiscal.nfse.xml(id);
const { url } = await fiscal.nfse.pdf(id);         // URL pré-assinada (15 min)
await fiscal.nfse.cancel(id, 'Valor incorreto');

// Consulta/cancelamento POR CHAVE DE ACESSO — funciona inclusive para notas
// emitidas FORA do gateway (Emissor Web), desde que do mesmo CNPJ:
const nota = await fiscal.nfse.consultByKey(accessKey, organizationId);   // XML + dados da Sefin
const pdf = await fiscal.nfse.officialDanfse(accessKey, organizationId);  // ArrayBuffer do PDF oficial
await fiscal.nfse.cancelByKey(accessKey, organizationId, 'Valor incorreto');

// Emissão completa: endereço do tomador + tributos federais (todos opcionais)
await fiscal.nfse.emit({
  organizationId,
  externalId: 'invoice_77',
  customer: { name: 'Diagonal Ltda', cpfCnpj: '01115194000133', email: '[email protected]' },
  service: { description: 'Consultoria', amount: 13971.99 },
  customerAddress: { cityCode: '3550308', zipCode: '01009907', street: 'Líbero Badaró', number: '293', complement: 'Andar 31', neighborhood: 'Centro' },
  federalTaxes: { pisCofinsCst: '00', vRetIRRF: 15.5, vRetCSLL: 10 },
});

// Emissão com retenção de ISS nesta nota (ex.: tomador PJ que retém):
await fiscal.nfse.emit({
  organizationId,
  externalId: 'invoice_42',
  customer: { name: 'Holding XYZ', cpfCnpj: '11222333000181' },
  service: { description: 'Consultoria', amount: 5000, issWithheld: true },
});

// Buscar código de tributação nacional (cTribNac) — autocomplete no onboarding
const codes = await fiscal.serviceCodes.search({ q: 'corretagem' });
// codes.items → [{ code: '100501', description: 'Agenciamento, corretagem...' }, ...]
const detail = await fiscal.serviceCodes.get('080201');

// Onboarding de organizações
const org = await fiscal.organizations.create({
  cnpj: '12345678000190',
  legalName: 'Imobiliária Alfa Ltda',
  cityCode: '3550308',
  state: 'SP',
  taxRegime: 'simples_nacional',
  fiscalSettings: {
    provider: 'nacional',
    serviceCode: '070101',
    serviceDescription: 'Administração imobiliária',
    issRate: 2.0,
  },
});
await fiscal.organizations.addCredential(org.id, {
  type: 'certificate_a1',
  payload: { pfxBase64: '...', password: '...' }, // validado no upload
});

// Webhook endpoints
const endpoint = await fiscal.webhookEndpoints.create('https://meuapp.com/hooks/fiscal');
console.log(endpoint.secret); // exibido SÓ aqui — guarde no seu secret manager

Tratamento de erros

import { FiscalGatewayError } from '@creativeproject/fiscal-gateway';

try {
  await fiscal.nfse.emit(params);
} catch (err) {
  if (err instanceof FiscalGatewayError) {
    err.status;        // HTTP status
    err.body;          // corpo da resposta do gateway
    err.isClientError; // 4xx — corrija o payload, não retente
  }
}

Erros 429/5xx/rede são retentados automaticamente (3x, backoff exponencial). Configure com maxRetries e timeoutMs no construtor.

Desenvolvimento

npm install
npm test         # vitest — 14 testes (HMAC, retry, contrato HTTP)
npm run build    # tsup — dist/ com ESM + CJS + .d.ts

Publicação no npm

O prepublishOnly roda testes + build automaticamente.

Opção A — npm público (npmjs.com)

# 1ª vez: criar a organização "creativeproject" em npmjs.com e fazer login
npm login

cd packages/sdk
npm version patch        # ou minor/major — atualiza package.json e cria tag
npm publish              # access public já configurado no package.json

Opção B — GitHub Packages (privado, dentro da org)

# .npmrc do projeto consumidor:
# @creativeproject:registry=https://npm.pkg.github.com

cd packages/sdk
npm publish --registry=https://npm.pkg.github.com

Opção C — automática por tag (workflow já configurado)

git tag sdk-v0.1.0 && git push origin sdk-v0.1.0
# o workflow .github/workflows/publish-sdk.yml testa, builda e publica
# requer o secret NPM_TOKEN configurado no repositório (npmjs → Access Tokens → Automation)