Repository navigation
Release v6.0.1 — distribuição no plural, envelopes desembrulhados e licença - #53
Merged
Merged
Conversation
…ma serve
getProductInvoiceDetails, getProductInvoiceEventDetails, getJson e
reprocessWebhook montavam /inbound/productinvoice/ (singular). A
plataforma serve so o plural, /inbound/productinvoices/. Medido em
2026-10-14:
singular, com ou sem credencial 404 de corpo vazio, igual a um path
inventado
plural, sem credencial 401
plural, com credencial 200 (detalhes e JSON)
A spec local consulta-nfe-distribuicao-v1.yaml (safra b487823) ainda diz
singular; o upstream corrigiu em nfe/docs@51d8816. Os cinco testes que
afirmavam o path errado agora afirmam o plural, e falham com o codigo
antigo.
O bug era latente: em 30 dias de gateway o singular teve 9 respostas
404, nenhuma com User-Agent do SDK. Evidencia em
tests/fixtures/live-contracts/inbound-distribution-routes.json, com corpo
sintetico.
… entidade
A API responde { "municipalTax": {...} }, { "stateTax": {...} } e
{ "notification": {...} }, e o SDK repassava o corpo tipado como a
entidade: resultado.id era undefined, sem erro de compilacao. Medido no
retrieve dos tres em 2026-10-15; em stateTaxes, 11 de 12 inscricoes da
conta do time responderam com o envelope (a outra respondeu 503,
problema daquele registro).
src/core/utils/envelope.ts devolve o conteudo da chave quando o corpo a
traz como objeto, e o corpo como veio nos demais casos. Passam a usa-lo
o create, o retrieve e o update de municipalTaxes e stateTaxes, e o
notifications.retrieve. O create e o update nao foram sondados, porque
exigiriam escrever num registro real: seguem a spec contribuintes-v2,
que declara o mesmo envelope, e o desembrulho defensivo deixa passar a
entidade direta se a resposta vier assim.
O helper fica nos recursos, nao na camada HTTP: cada recurso sabe a
chave do proprio envelope, e um desembrulho generico teria de adivinha-la
e mudaria o retorno de metodos que ja desembrulham certo (companies,
webhooks, legalPeople).
Os mocks dos testes passam a ter o formato do fio, e cada recurso ganha
um caso de entidade direta. Com o codigo antigo, 6 testes falham.
Evidencia em tests/fixtures/live-contracts/response-envelopes.json, que
registra tambem tres casos em que o SDK ja estava certo e a spec erra.
Pela documentacao da plataforma (nfe/docs@b9e7953), o update de inscricao municipal e um PUT que substitui o registro: omitir taxNumber apaga o numero da inscricao, e omitir environment volta para Development. rpsNumber e lastRpsSent sao a excecao: omitidos, preservam o contador de RPS; enviados, sobrescrevem o contador, inclusive para tras. O JSDoc dizia so "Update a municipal tax registration", e a pagina do recurso, "Atualiza". O JSDoc, docs/recursos/municipal-taxes.md, a referencia da skill e o exemplo passam a mostrar o roteiro: ler com retrieve, alterar e reenviar sem os dois campos do contador. O exemplo do JSDoc foi checado em modo estrito com exactOptionalPropertyTypes. O SDK nao sondou isso, porque exigiria escrever sobre uma inscricao real. Na mesma pagina, o exemplo de create nao compilava (usava `code` no primeiro nivel, que nao e campo da inscricao) e chamava updatePrefecture. Ele e getSeries estao @deprecated desde a 6.0.0, porque a plataforma nao serve as rotas, e o exemplo de examples/ chamava getSeries de fato. Agora os dois aparecem como descontinuados, e os exemplos usam os campos reais (city, taxNumber, rpsSerialNumber, environment).
…nsinados consumerInvoiceQuery.retrieve e downloadXml estao @deprecated desde a 6.0.0: a plataforma nao serve /v1/consumerinvoices/coupon/{chave}, que responde 404 igual a um path inventado, inclusive sem credencial. Mesmo assim o README, docs/API.md, docs/recursos/consumer-invoice-query.md, a referencia da skill e o exemplo ensinavam os dois como caminho de uso. Agora aparecem como descontinuados, e o exemplo so demonstra o erro. O fluxo completo do README criava webhook por empresa (webhooks.create(empresaId, ...)), descontinuado desde a v5.1 porque a rota responde 404 (confirmado em tres contas em 2026-07). Passa ao webhook de conta (createAccountWebhook), com validacao de assinatura sobre o corpo cru. A secao v2 -> v3 do MIGRATION ganha o mesmo aviso no topo do bloco de webhooks.
…de sucesso A verificacao existente casa nome de metodo. getSeries existe no codigo, entao uma pagina que o ensinava como funcional passava, e foi assim que os metodos de rota nao servida continuaram ensinados um mes depois de a v6 os depreciar. A nova verificacao procura, em README, MIGRATION, docs/**, skills/** e examples/**, cada citacao <recurso>.<metodo>( de um metodo sem caminho de sucesso, e exige aviso no mesmo bloco (paragrafo, linha de tabela, bloco de codigo; em examples/, os comentarios logo acima) ou no titulo da secao. O CHANGELOG fica de fora, por ser historico. O conjunto sai do codigo, nao de uma lista mantida a mao: entram os metodos com @deprecated no JSDoc, inclusive o @deprecated de classe (consumerInvoiceQuery), menos as depreciacoes funcionais declaradas com motivo (companies.list, webhooks.getAvailableEvents), que funcionam. Um teste de guarda confere que o conjunto inclui os metodos de rota nao servida, para a verificacao nao passar por estar vazia.
Tres links apontavam para arquivos que nao existem:
README.md docs/MIGRATION-TO-GENERATED-TYPES.md -> MIGRATION.md
CHANGELOG.md RELEASE_NOTES_v3.md (entrada 3.0) -> secao v2 -> v3
do MIGRATION.md
docs/API.md ../LICENSE -> URL do repositorio
docs/ e espelhado sozinho no portal de documentacao, entao link que sai
dele quebra la, mesmo que o arquivo exista aqui. Os outros links de
docs/API.md que saiam de docs/ (../src/core/types.ts cinco vezes,
../CONTRIBUTING.md) e o de docs/EXTENDING.md passam a URLs absolutas do
repositorio.
docs-drift.test.ts ganha a verificacao: em README, MIGRATION, CHANGELOG,
docs/** e skills/**, todo link relativo precisa resolver para um arquivo
que existe, e em docs/** nao pode sair de docs/. Ela falhava nos tres
links antes da correcao. Um teste de guarda confere que ela pega link
inexistente e link que sai de docs/.
Refs #47
A 6.0.0 documentou que as duas chaves "respondem 403 no territorio da
outra", generalizando uma sonda de 2026-09-01 que so testou rotas de
documento fiscal em api.nfse.io. A matriz refeita em 2026-10-14, sobre
16 rotas, mostra outra coisa:
principal dados
documento fiscal (tax-codes, NF-e, aceita 403
NFC-e, distribuicao, NFS-e v1)
cadastro da conta, na leitura aceita aceita
(empresas, inscricoes, certificados,
webhooks)
hosts de consulta (CNPJ, CEP, NF-e 403 aceita
por chave de acesso)
O calculo de tributos, medido em 2026-10-16, se comporta como documento
fiscal. A escrita com a chave de dados nao foi testada.
O SDK nao tinha bug: ele envia a principal a todo recurso de api.nfe.io
e api.nfse.io. A aceitacao da chave de dados no cadastro nao e contrato
documentado, e o SDK nao depende dela. docs/multi-host-routing.md, a
secao v5 -> v6 do MIGRATION, a skill, o JSDoc de NfeConfig.dataApiKey e
o comentario do cliente fiscal passam a descrever a regra por rota. Os
getters de cadastro (companies, stateTaxes, municipalTaxes,
certificates) dizem so que usam a chave principal; os de documento
fiscal mantem a frase do 403, que e verdadeira para eles. O README ja
estava correto, e a entrada 6.0.0 do CHANGELOG nao e reescrita: a
correcao entra na 6.0.1 como correcao de registro.
Evidencia em tests/fixtures/live-contracts/api-key-route-matrix.json. O
fixture de 2026-09-01 fica como registro historico, com supersededBy
apontando para o novo.
O repositorio nunca teve arquivo de licenca: o MIT existia so no campo license do package.json, e a API do GitHub reportava o repositorio como sem licenca. Para varredura de dependencias e revisao juridica, licenca so em metadado e licenca nao confirmada. Decisao de 2026-10-16: MIT, com a linha "Copyright (c) 2026 NFE.IO HUB SERVICOS DE TECNOLOGIA LTDA", e contribuicoes sob a mesma licenca, sem CLA. - LICENSE com o texto MIT identico ao modelo do choosealicense, que e o que o GitHub usa para detectar; - README, cabecalhos de src/index.ts e src/core/client.ts e CONTRIBUTING citam o mesmo SPDX e o mesmo titular. O README diz que a licenca cobre o SDK e que o uso da API segue o contrato da conta; - o banner do bundle passa a /*! ... */ com o SPDX e o titular. Os minificadores preservam esse formato quando a aplicacao re-empacota o SDK, e a MIT exige que o aviso acompanhe o codigo; - tests/unit/license.test.ts compara o SPDX declarado com o texto inteiro do LICENSE, confere o arquivo no tarball (npm pack --dry-run, sem scripts) e procura titular escrito de outro jeito. Verificado por mutacao: falha com o arquivo removido e com o SPDX trocado. Refs #47
Versao 6.0.1 no package.json e src/version.ts regenerado. Entrada 6.0.1 no CHANGELOG: rotas de distribuicao e envelopes (corrigido); PUT da inscricao municipal, metodos sem caminho de sucesso, links e licenca (documentacao); e a regra de chaves por rota (correcao de registro). A entrada 6.0.0 nao muda.
📋 OpenAPI Spec Validation✅ All specs validated and types generated successfully Specs processed:
Generated types available as artifact in |
Dois lugares ainda carregavam versao antiga:
package-lock.json 5.2.0 na raiz e em packages[""]: a 6.0.0 subiu so
o package.json
src/index.ts @Version 5.1.0 no cabecalho do modulo
O lockfile foi editado nos dois campos, sem npm install, para nao
re-resolver dependencias. A tag @Version saiu em vez de ser atualizada:
a versao vive so em src/version.ts, e um numero num comentario apodrece
de novo. Ela nao chegava ao .d.ts publicado.
version.test.ts ganha duas guardas: o lockfile precisa ter o nome e a
versao do package.json, e nenhum arquivo de src/ (fora src/generated/)
pode ter tag @Version X.Y.Z. A varredura de literais continua ignorando
comentarios, que citam versoes antigas como historico; uma tag nao e
historico, declara a versao. Verificado por mutacao: as duas falham com
o lockfile em 5.2.0 e com uma tag @Version num comentario.
companies.integration.test.ts criava e apagava empresas na conta da chave configurada, que costuma ser compartilhada por varias pessoas. E nao rodava so no test:integration: fora da CI, o setup carrega o .env e o npm test executa a integracao sempre que ha chave. A limpeza tambem nao limpava. O companies.remove responde com sucesso (o teste de delete, que o chama sem try/catch, passa), mas a empresa continua na conta com status Inactive, em v1 e v2, horas depois. Cada rodada deixava sete empresas. Medido em 2026-10-16: ha 42 com o nome gerado pelo teste, todas inativas, 14 delas de duas rodadas locais desta release. O comentario que atribuia a sobra a consistencia eventual saiu. Os seis testes que criam, alteram ou apagam empresa (create, retrieve, list, update, delete e CNPJ duplicado) passam a exigir NFE_ALLOW_ACCOUNT_WRITES=true, declarado em setup.ts com o motivo. Continuam rodando por padrao o 404 de empresa inexistente e a recusa de corpo invalido, que nao gravam nada. O README de integracao documenta a variavel e corrige a secao de limpeza. Verificado ao vivo sem a variavel: 2 passam, os 6 de escrita e o de certificado pulam. Com a variavel nao foi exercido, porque escreveria na conta compartilhada.
📋 OpenAPI Spec Validation✅ All specs validated and types generated successfully Specs processed:
Generated types available as artifact in |
A skill publicada, que vai no pacote npm, ensinava assinaturas de antes
da 6.0.0. Comparada ao codigo, ela tinha 32 metodos com parametro,
retorno ou nome errado:
productInvoices 9 downloads devolvem NfeFileResource ({ uri }),
nao Buffer; sendCorrectionLetter recebe
reason: string; disable(companyId,
invoiceId, reason?); disableRange devolve
NfeDisablementResource; create devolve
NfeProductInvoiceIssueData
inboundProductInvoices 9 XML e PDF devolvem InboundFileResource; os
metodos de evento exigem eventKey; getJson
nao tem format; manifest e reprocessWebhook
tem outro retorno
consumerInvoices 7 leituras sem environment; downloads devolvem
ConsumerInvoiceFileResource; cancel aceita
reason e devolve
ConsumerInvoiceCancellationResponse
serviceInvoices 4 cancel devolve CancelInvoiceResponse;
downloads exigem invoiceId (nao ha ZIP em
lote); getStatus citava um tipo inexistente
transportationInvoices 3 retrieveEvent nao existe (o metodo e
getEvent, com eventKey); downloads devolvem
InboundFileResource
Tambem estavam errados: o CRUD de webhook por empresa aparecia como
funcional numa tabela, que a guarda de drift nao le; o pitfall 7 dizia
que o calculo de tributos usa a chave de dados (usa a principal, e a de
dados toma 403); NfeStateTax nao batia com o tipo; a descricao contava
16 recursos (sao 22); e sete linhas tinham perdido os acentos.
Entram as notas da 6.0.1 que faltavam: os quatro metodos de distribuicao
so alcancam a API a partir dela, e stateTaxes e notifications devolvem
a entidade.
Verificado: a comparacao mecanica das assinaturas fica so com
diferencas de nome de parametro; um arquivo com os usos que a skill
ensina compila em modo estrito, e tres usos da versao anterior nao
compilam.
📋 OpenAPI Spec Validation✅ All specs validated and types generated successfully Specs processed:
Generated types available as artifact in |
…reais O rodape do CHANGELOG parou na 5.2.0: [Unreleased] ainda comparava a partir dela, e oito versoes nao tinham link (6.0.1, 6.0.0, 4.0.0, 3.2.1, 3.2.0, 3.1.0, 3.0.2, 3.0.1). A referencia [Unreleased] tambem nao casava com o titulo da secao, que e "Nao lancado". Dois links existentes estavam quebrados: [3.0.0] apontava para a tag v3.0.0, mas no remoto ela se chama 3.0.0, sem o v; e [2.0.0] apontava para uma tag v2.0.0 que nao existe no repositorio. Esta passa a apontar para a versao no npm, onde ela esta publicada. Verificado: os links do GitHub respondem 200; os dois da 6.0.1 so existem depois da release. A 2.0.0 confere no registro do npm.
📋 OpenAPI Spec Validation✅ All specs validated and types generated successfully Specs processed:
Generated types available as artifact in |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
O que é
Patch de contrato e de documentação. Dois bugs de código, provados por sonda ao vivo contra a
API real entre 14 e 16/10, e uma rodada de correções na documentação, que ensinava métodos sem
caminho de sucesso e uma regra de chaves imprecisa. Entra também o arquivo de licença.
Nenhuma assinatura pública muda. Evidência versionada em
tests/fixtures/live-contracts/,com corpo sintético.
O
publish.ymldispara só emrelease: createde emworkflow_dispatch. Push, PR e merge namasterrodam só o CI. A 6.0.1 vai para o npm quando alguém criar a releasev6.0.1noGitHub (ver "Depois do merge").
O
npm run releasepublica direto da máquina local, sem passar pelo portão do workflow. Nãousar.
Os bugs
Quatro métodos da distribuição de NF-e chamavam uma rota que não existe.
inboundProductInvoices.getProductInvoiceDetails,getProductInvoiceEventDetails,getJsonereprocessWebhookmontavam/inbound/productinvoice/(singular), e a plataforma serve só oplural.
404de corpo vazio mesmo sem credencial, igual a um path inventado.401sem credencial e200com ela.singular.
municipalTaxes,stateTaxesenotificationsdevolviam o envelope no lugar da entidade.A API responde
{ "municipalTax": {…} },{ "stateTax": {…} }e{ "notification": {…} }. OSDK repassava o corpo tipado como a entidade, e
resultado.idvinhaundefinedsem erro decompilação. Agora o
create, oretrievee oupdatedas inscrições, e onotifications.retrieve, devolvem a entidade.Só o
retrievefoi sondado. Ocreatee oupdateseguem a spec, que declara o mesmo envelope,e o desembrulho é defensivo: se a resposta vier com a entidade direta, ela passa como veio.
Documentação
municipalTaxes.updateé um PUT de substituição, pela documentação da plataforma:taxNumberapaga o número da inscrição;environmentvolta paraDevelopment;rpsNumbersobrescreve o contador de RPS.O JSDoc, a página do recurso, a skill e o exemplo mostram o roteiro de ler e depois substituir.
O SDK não sondou isso, porque exigiria escrever sobre uma inscrição real.
Métodos de rota não servida deixaram de ser ensinados como funcionais:
getSeries,updatePrefecture, a consulta de cupom CFe-SAT e o webhook por empresa, no README, emdocs/, na skill e nos exemplos. O exemplo antigo de inscrição nem compilava.Uma guarda nova no
docs-drift.test.tsfalha quando um documento cita, sem aviso, um método@deprecatedpor rota não servida. O conjunto de métodos sai do código, não de uma listamantida à mão.
Links quebrados da Repositório declara MIT mas não distribui o arquivo LICENSE (+2 links de doc quebrados) #47: os três foram corrigidos, e o
docs-drift.test.tspassa a conferiros links relativos. Em
docs/**, que é espelhado sozinho no portal, o link também não podesair de
docs/.Arquivo
LICENSE(Repositório declara MIT mas não distribui o arquivo LICENSE (+2 links de doc quebrados) #47): MIT, com a linhaCopyright (c) 2026 NFE.IO HUB SERVICOS DE TECNOLOGIA LTDA, conforme decidido em 16/10./*! … */do bundle, que osminificadores preservam.
license.test.tsconfere que o SPDX declarado, o texto do arquivo e o conteúdo do tarballconcordam.
A skill publicada ensinava assinaturas de antes da 6.0.0. Comparada ao código, ela tinha 32
métodos com parâmetro, retorno ou nome errado, quase todos de quebras da 6.0.0 que nunca
chegaram a ela:
Bufferquando devolvem um recurso com URI;sendCorrectionLetterrecebendo objeto;environment;transportationInvoices.retrieveEvent, que não existe.O CRUD de webhook por empresa aparecia como funcional numa tabela, e o pitfall de chaves dizia
que o cálculo de tributos usa a chave de dados. Tudo foi conferido contra o código: os usos que
a skill ensina agora compilam em modo estrito, e os que ela ensinava antes não compilam.
Correção de registro
A 6.0.0 documentou que as duas chaves "respondem 403 no território da outra". A matriz refeita
em 14/10, sobre 16 rotas, mostra que a regra é por rota:
webhooks);
O SDK não tinha bug: ele envia a chave principal a todo recurso de
api.nfe.ioeapi.nfse.io.A leitura do cadastro com a chave de dados não é contrato documentado, e o SDK não depende dela.
A entrada 6.0.0 do CHANGELOG não foi reescrita; a correção entra na 6.0.1.
Manutenção
package-lock.jsonestava na 5.2.0, porque a 6.0.0 só atualizou opackage.json, e ocabeçalho de
src/index.tsdizia@version 5.1.0. Os dois foram corrigidos, com guarda noversion.test.ts.companiesque criam, alteram ou apagam empresas passam a exigirNFE_ALLOW_ACCOUNT_WRITES=true. Fora da CI, onpm testroda também a integração sempre quehá chave no
.env. E ocompanies.removeresponde com sucesso, mas deixa a empresa na conta,inativa, então cada rodada deixava sete empresas.
Commits
Cada commit é revisável sozinho, e todos passam em typecheck e na suíte unitária isoladamente.
5b949c1fix(inbound)c3c23b0fix(resources)b4e227cdocs(municipal-taxes)29f7376docsfa2c027test(docs)8c54f70docs31bd3bddocs(keys)7ceff1fchore(license)LICENSEe titular únicoecd0805chore(release)b94e536chore(version)cdec742test(integration)8650e6edocs(skill)7aebfacdocs(changelog)Verificação
Uma correção sobre o que rodou. A execução explícita da integração deixou
companiesdefora. Mas as duas rodadas de
npm test -- --rundesta release também executaram a integração,porque o setup carrega o
.enve, fora da CI, roda sempre que há chave. Essas rodadas criaram 14empresas de teste na conta compartilhada, que o
removedo teste deixou inativas. É isso que oopt-in deste PR fecha (ver "Manutenção"). As 42 empresas com nome de teste na conta, de 02/09 até
hoje, estão todas inativas. Nenhuma rota deste PR passa pela integração.
Depois do merge
v6.0.1no GitHub sobre o commit de merge, que é o que dispara opublish.yml.package.json, roda testes, lint, typecheck,test:typese build, e publica com provenance.antes.
PR não usa palavra de fechamento, então as duas seguem abertas até lá.
<3.0.0no npm (npm deprecate), que fica fora deste PR.Fora deste PR: o JSDoc de
companies.removenão diz que a empresa continua na conta,inativa. Isso fica para um follow-up, com sonda própria.