{"_id":"@dfe-kit/jacobina-saatri","_rev":"2-6423927954a900c7fbdcd8fe2401ee2a","name":"@dfe-kit/jacobina-saatri","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@dfe-kit/jacobina-saatri","version":"0.1.0","license":"BUSL-1.1","_id":"@dfe-kit/jacobina-saatri@0.1.0","maintainers":[{"name":"yorizel","email":"manoel.netocarvalho03@gmail.com"}],"nx":{"tags":["scope:provider"],"implicitDependencies":["@dfe-kit/fiscal","@dfe-kit/adapter-saatri"]},"dist":{"shasum":"196b4eb29bc5045b7ab3ea619a95326030c24012","tarball":"https://registry.npmjs.org/@dfe-kit/jacobina-saatri/-/jacobina-saatri-0.1.0.tgz","fileCount":5,"integrity":"sha512-t+YKj7NpZfzI92BFXMAIkRd0vKXv8JtjTXout82zNFGAZ9xk6JNKfmW/1FnjgHtslR+h45efUsxXJ9W6rQlV2g==","signatures":[{"sig":"MEUCIA26S+oAKWcHG3YNWNz/rSBuhyLP6f8Id6dZKFGJz7h5AiEA7JIrnXkpeQtWT7HxLWCIOdK6ZmaswaqudGciPf3xAT4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":407478},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"f938aa3bedd8191ca7b0436423c85d8a17f0da77","scripts":{"test":"bun test ./__tests__","build":"bunup","publint":"publint --strict","typecheck":"tsc -p tsconfig.json --noEmit","publish:npm":"bun run build && bun run publint && npm publish --access public --provenance","publish:npm:dry":"bun run build && bun run publint && npm publish --access public --provenance --dry-run"},"_npmUser":{"name":"yorizel","email":"manoel.netocarvalho03@gmail.com"},"_npmVersion":"11.16.0","description":"Provider NFS-e para **Jacobina/BA** via **SAATRI / ABRASF 2.03**.","directories":{},"sideEffects":false,"_nodeVersion":"26.2.0","dependencies":{"better-result":"^2.9.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@dfe-kit/adapter-saatri":"workspace:*"},"_npmOperationalInternal":{"tmp":"tmp/jacobina-saatri_0.1.0_1781113348372_0.06216249288863018","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@dfe-kit/jacobina-saatri","version":"0.1.1","license":"Apache-2.0","repository":{"type":"git","url":"git+https://github.com/Montte-erp/dfe-kit.git","directory":"packages/jacobina-saatri"},"type":"module","sideEffects":false,"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./manifest":{"types":"./dist/manifest.d.ts","import":"./dist/manifest.js"},"./runtime":{"types":"./dist/runtime.d.ts","import":"./dist/runtime.js"}},"publishConfig":{"access":"public"},"scripts":{"build":"bunup","typecheck":"tsc -p tsconfig.json --noEmit","test":"vitest run ./__tests__","publint":"publint --strict","publish:npm":"bun run build && bun run publint && npm publish --access public --provenance","publish:npm:dry":"bun run build && bun run publint && npm publish --access public --provenance --dry-run"},"dependencies":{"effect":"4.0.0-beta.81"},"devDependencies":{"@dfe-kit/adapter-saatri":"workspace:*","@dfe-kit/fiscal":"workspace:*"},"nx":{"tags":["scope:provider"],"implicitDependencies":["@dfe-kit/fiscal","@dfe-kit/adapter-saatri"]},"gitHead":"3038817349f4e541eb88509713e46a2c63c0b4e2","_id":"@dfe-kit/jacobina-saatri@0.1.1","description":"Provider NFS-e para **Jacobina/BA** via **SAATRI / ABRASF 2.03**.","bugs":{"url":"https://github.com/Montte-erp/dfe-kit/issues"},"homepage":"https://github.com/Montte-erp/dfe-kit#readme","_nodeVersion":"22.12.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-glrautjEX8DngoY89/8LZHh0zpksly2sa+dOJTzsUCGtOiJDEiznB0jM+6wfiw70l4Pnv/k1FDxwux5EOhnPeA==","shasum":"733e73844bd4640dd4430173bad9637d9afa5330","tarball":"https://registry.npmjs.org/@dfe-kit/jacobina-saatri/-/jacobina-saatri-0.1.1.tgz","fileCount":12,"unpackedSize":204892,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dfe-kit%2fjacobina-saatri@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIH8Ip5WKBWx3Syva70/O+adeqxz6ttZbxCgyajd2NFAaAiEAj4UzTioF325QOcuuoPQG9RWpqcd75ciJRhLDtDm657Y="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:221c0dde-4439-4b3b-8053-1ae21b086858"}},"directories":{},"maintainers":[{"name":"yorizel","email":"manoel.netocarvalho03@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jacobina-saatri_0.1.1_1781301903523_0.5904457259069444"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-10T17:42:28.236Z","modified":"2026-06-12T22:05:04.054Z","0.1.0":"2026-06-10T17:42:28.578Z","0.1.1":"2026-06-12T22:05:03.726Z"},"license":"Apache-2.0","description":"Provider NFS-e para **Jacobina/BA** via **SAATRI / ABRASF 2.03**.","maintainers":[{"name":"yorizel","email":"manoel.netocarvalho03@gmail.com"}],"readme":"# @dfe-kit/jacobina-saatri\n\nProvider NFS-e para **Jacobina/BA** via **SAATRI / ABRASF 2.03**.\n\nEste pacote é parte do DFeKit: infraestrutura fiscal open source para documentos fiscais eletrônicos brasileiros.\n\n## Status\n\n**Experimental / homologação primeiro.**\n\nCapacidade declarada hoje:\n\n- `issue_nfse`: geração de NFS-e/RPS via operação SAATRI `GerarNfse`.\n\nO `manifest.capabilityMetadata` também cataloga serviços do manual como `unverified_in_homologation` quando ainda não há prova automatizada. Não trate esses itens como suporte operacional.\n\nAtenção 2026: `GerarNfse` e `ConsultaNfsePorRps` podem se comportar de forma assíncrona por compartilhamento com o ambiente nacional; respostas como “DPS gerada/compartilhada” viram `accepted_pending_authorization` e exigem consulta posterior.\n\nAinda **não** declare suporte produtivo amplo para:\n\n- consulta por RPS;\n- cancelamento;\n- substituição;\n- lote;\n- consultas prestadas/tomadas/faixa;\n- NFS-e Nacional direta;\n- assinatura XML obrigatória;\n- qualquer outro município.\n\nEssas capacidades só devem aparecer no `manifest` depois de prova em homologação com fixtures e testes automatizados.\n\n## Licença\n\nEste pacote é distribuído sob **Apache License 2.0 (`Apache-2.0`)**.\n\nA licença permite uso, cópia, modificação, distribuição, sublicenciamento e uso comercial conforme os termos da Apache 2.0.\n\nVeja o arquivo [`LICENSE`](../../LICENSE).\n\n## Instalação\n\n```bash\nbun add @dfe-kit/jacobina-saatri effect\n```\n\nOu com npm:\n\n```bash\nnpm install @dfe-kit/jacobina-saatri effect\n```\n\n> `effect` faz parte do contrato público: `provider.issue(...)` e outros métodos fiscais\n> retornam `Effect.Effect<T, SaatriProviderError>`, ou seja, falhas técnicas tipadas no\n> canal de erro. Rejeição fiscal continua como sucesso de negócio (`providerResponse.status`).\n\nSem wrappers de retorno legados.\n\n```ts\nimport { Effect } from \"effect\";\nimport {\n  createJacobinaSaatriProvider,\n  type SaatriProviderError,\n} from \"@dfe-kit/jacobina-saatri/runtime\";\n\nconst provider = createJacobinaSaatriProvider(\n  {\n    username: process.env.SAATRI_USERNAME!,\n    password: process.env.SAATRI_PASSWORD!,\n    issuerCnpj: process.env.SAATRI_ISSUER_CNPJ!,\n    municipalRegistration: process.env.SAATRI_MUNICIPAL_REGISTRATION!,\n  },\n  {\n    environment: \"homologation\",\n  },\n);\n\nconst issued = await Effect.runPromise(\n  provider.issue({\n    environment: \"homologation\",\n    documentKind: \"nfse\",\n    series: \"1\",\n    number: \"1\",\n    issuedAt: new Date().toISOString(),\n    issuer: {\n      legalName: \"Empresa Prestadora LTDA\",\n      cnpj: \"00000000000000\",\n      municipalRegistration: \"12345\",\n      address: {\n        street: \"Rua Exemplo\",\n        number: \"100\",\n        district: \"Centro\",\n        cityCode: \"2917706\",\n        city: \"Jacobina\",\n        state: \"BA\",\n        postalCode: \"44700000\",\n        countryCode: \"1058\",\n      },\n    },\n    customer: {\n      legalName: \"Cliente Tomador\",\n      cpf: \"00000000000\",\n      address: {\n        street: \"Rua Cliente\",\n        number: \"200\",\n        district: \"Centro\",\n        cityCode: \"2917706\",\n        city: \"Jacobina\",\n        state: \"BA\",\n        postalCode: \"44700000\",\n        countryCode: \"1058\",\n      },\n    },\n    services: [\n      {\n        description: \"Serviço de teste em homologação\",\n        serviceListCode: \"01.05\",\n        amount: \"150.00\",\n        taxable: true,\n      },\n    ],\n  }),\n);\n\nconst providerResponse = issued.providerResponse;\n\nif (providerResponse.status === \"rejected\") {\n  // Rejeição fiscal: o provedor processou a requisição, mas recusou por regra fiscal.\n  console.log(providerResponse.rejections);\n} else if (providerResponse.status === \"authorized\") {\n  console.log(\"NFS-e autorizada\", {\n    documentRef: issued.documentRef,\n    providerDocumentId: providerResponse.providerDocumentId,\n    protocol: providerResponse.protocol,\n    verificationUrl: providerResponse.verificationUrl,\n  });\n}\n```\n\n## Endpoints SAATRI Jacobina\n\n- homologação: `https://homologa-homologa-jacobina.saatri.com.br/servicos/nfse.svc`\n- produção: `https://homologa-jacobina.saatri.com.br/servicos/nfse.svc`\n- WSDL: acrescente `?wsdl`\n- limite XML informado: 512 KB\n\n## Modelo de erro\n\nDFeKit separa erro técnico de rejeição fiscal.\n\n### Rejeição fiscal\n\nRejeição fiscal é resposta válida do provedor. Ela volta como sucesso no Effect com:\n\n```ts\nproviderResponse.status === \"rejected\";\nproviderResponse.rejections.length > 0;\n```\n\nExemplos:\n\n- inscrição municipal ausente;\n- código de serviço inválido;\n- RPS já informado;\n- tomador inválido;\n- regra municipal descumprida.\n\n### Erro técnico\n\nErro técnico volta como falha tipada no canal de erro do Effect (`SaatriProviderError`), conforme catálogo de códigos em `@dfe-kit/adapter-saatri/src/config.ts`.\n\nExemplos:\n\n- timeout;\n- falha de rede;\n- HTTP não-2xx;\n- SOAP Fault técnico;\n- XML de resposta irreconhecível;\n- falha do hook de assinatura.\n\n## Artefatos fiscais\n\nA resposta preserva XML bruto em `providerResponse.artifacts`.\n\nHoje o provider salva, no mínimo:\n\n- `request_xml`;\n- `response_xml`.\n\nConsumidores devem persistir esses artefatos junto com protocolo, número, código de verificação e eventos de ciclo de vida. Documento fiscal sem XML/protocolo preservado não é auditável.\n\n## Assinatura XML\n\nAssinatura XML é opcional e injetável:\n\n```ts\nimport { Effect } from \"effect\";\nimport type { SaatriProviderError, GerarNfseSigner } from \"@dfe-kit/jacobina-saatri\";\n\nconst signer: GerarNfseSigner = (xmlToSign) => {\n  // Assine o XML fora do DFeKit usando seu provedor de certificado/HSM/KMS.\n  // `GerarNfseSigner` é Effect-native:\n  // - sucesso: Effect.succeed(xmlAssinado)\n  // - falha técnica: Effect.fail(new SaatriProviderError({ ... }))\n  return Effect.succeed(xmlToSign);\n};\n```\n\n> `GerarNfseSigner` tem assinatura:\n>\n> `type GerarNfseSigner = (xmlToSign: string) => Effect.Effect<string, SaatriProviderError>`\n\n## OpenTelemetry opcional\n\nO subpath `@dfe-kit/jacobina-saatri/manifest` não depende de OpenTelemetry e não instancia SDK, exporter, cliente HTTP ou provider configurado. O subpath `@dfe-kit/jacobina-saatri/runtime` expõe as factories de execução.\n\nO adapter SAATRI já emite spans, métricas e logs via `effect`:\n\n- spans: `dfe.saatri.issue`, `dfe.saatri.envelope.build`, `dfe.saatri.sign`, `dfe.saatri.http.post`, `dfe.saatri.response.parse`, `dfe.saatri.xml.parse`;\n- métricas: `dfe_saatri_issue_total`, `dfe_saatri_issue_error_total`, `dfe_saatri_fiscal_status_total`, `dfe_saatri_http_attempt_total`, `dfe_saatri_http_status_total`, `dfe_saatri_http_retry_total`, `dfe_saatri_parse_error_total`, `dfe_saatri_xml_bytes`.\n\nPara exportar traces via OpenTelemetry, configure `@effect/opentelemetry` no runtime da aplicação consumidora. Métricas e logs exigem leitores/processadores adicionais no `NodeSdk.layer`; o DFeKit não escolhe exporters, resource ou sampling por você.\n\n```bash\nbun add @effect/opentelemetry @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-http\n```\n\nExemplo de composição opcional no boundary da aplicação:\n\n```ts\nimport * as NodeSdk from \"@effect/opentelemetry/NodeSdk\";\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-http\";\nimport { BatchSpanProcessor } from \"@opentelemetry/sdk-trace-base\";\nimport { Effect } from \"effect\";\nimport { createJacobinaSaatriProvider } from \"@dfe-kit/jacobina-saatri/runtime\";\n\nconst OtelLive = NodeSdk.layer(() => ({\n  resource: { serviceName: \"my-fiscal-service\" },\n  spanProcessor: new BatchSpanProcessor(\n    new OTLPTraceExporter({ url: \"http://localhost:4318/v1/traces\" }),\n  ),\n}));\n\nconst provider = createJacobinaSaatriProvider(credentials, {\n  environment: \"homologation\",\n  correlationId: \"request-123\",\n});\n\nconst result = await Effect.runPromise(provider.issue(input).pipe(Effect.provide(OtelLive)));\n```\n\nEssa decisão mantém OTel configurável e opcional no adapter: DFeKit emite observabilidade nativa do Effect; a aplicação escolhe exporters, resource, leitores de métricas/logs e política de sampling.\n\n## DFeKit não armazena chaves\n\nDFeKit **não** guarda certificado, senha de PFX ou material criptográfico. Certificado A1, vault, HSM e política de segredo ficam fora deste pacote.\n\n## Segurança de produção\n\nEmissão em `production` gera documento fiscal real.\n\nRecomendações para consumidores:\n\n- usar `homologation` por padrão;\n- exigir confirmação explícita para produção;\n- persistir todos os XMLs e eventos;\n- usar idempotência por ambiente + CNPJ + série + número;\n- nunca fazer retry automático cego de emissão fiscal;\n- esconder credenciais e XMLs sensíveis de logs públicos.\n\n## API pública principal\n\n```ts\ncreateJacobinaSaatriProvider(\n  credentials: SaatriCredentials,\n  options: CreateSaatriPackageProviderOptions,\n): FiscalProvider\n```\n\nCredenciais e opções da API schema-first vêm dos tipos exportados pelo pacote:\n\n```ts\nimport {\n  createJacobinaSaatriProvider,\n  type SaatriCredentials,\n  type CreateSaatriPackageProviderOptions,\n} from \"@dfe-kit/jacobina-saatri/runtime\";\n\nconst credentials: SaatriCredentials = {\n  username: process.env.SAATRI_USERNAME!,\n  password: process.env.SAATRI_PASSWORD!,\n  issuerCnpj: process.env.SAATRI_ISSUER_CNPJ!,\n  municipalRegistration: process.env.SAATRI_MUNICIPAL_REGISTRATION!,\n};\n\nconst options: CreateSaatriPackageProviderOptions = {\n  environment: \"homologation\",\n};\n\nconst provider = createJacobinaSaatriProvider(credentials, options);\n```\n\n## Constantes públicas\n\nImports recomendados:\n\n```ts\nimport { jacobinaSaatriManifest } from \"@dfe-kit/jacobina-saatri/manifest\";\nimport { createJacobinaSaatriProvider } from \"@dfe-kit/jacobina-saatri/runtime\";\n```\n\nO pacote exporta constantes de provider:\n\n- `JACOBINA_CITY_CODE`;\n- `SAATRI_ABRASF_VERSION`;\n- `SAATRI_JACOBINA_HOMOLOGATION_ENDPOINT`;\n- `SAATRI_JACOBINA_PRODUCTION_ENDPOINT`;\n- `jacobinaSaatriManifest`.\n\n## Changelog\n\nVeja [`CHANGELOG.md`](./CHANGELOG.md) para mudanças publicáveis deste pacote.\n\n## Desenvolvimento\n\nAsserções e cenários devem permanecer em `@effect/vitest` (incluindo `@effect/vitest/static` para validação estática de contratos).\n\nNa raiz do repositório:\n\n```bash\nbun install\nbun run check:static\nbun run test\nbun run typecheck\nbun run build\nbun run publint\n```\n\nAntes de publicar pacote:\n\n```bash\nbun run publish:npm:dry\nbun run publish:npm\n```\n\nO tarball deve incluir apenas:\n\n- `package.json`;\n- `LICENSE`;\n- `README.md`;\n- `dist/index.js`;\n- `dist/index.d.ts`;\n- `dist/manifest.js`;\n- `dist/manifest.d.ts`;\n- `dist/runtime.js`;\n- `dist/runtime.d.ts`.\n","readmeFilename":"README.md","homepage":"https://github.com/Montte-erp/dfe-kit#readme","repository":{"type":"git","url":"git+https://github.com/Montte-erp/dfe-kit.git","directory":"packages/jacobina-saatri"},"bugs":{"url":"https://github.com/Montte-erp/dfe-kit/issues"}}