@neetru/sdk 3.8.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/README.md +4 -1
- package/dist/ai.cjs +1 -1
- package/dist/ai.d.cts +1 -1
- package/dist/ai.d.ts +1 -1
- package/dist/ai.mjs +1 -1
- package/dist/auth.cjs +1171 -1110
- package/dist/auth.d.cts +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/auth.mjs +1168 -1107
- package/dist/catalog.cjs +1 -1
- package/dist/catalog.d.cts +1 -1
- package/dist/catalog.d.ts +1 -1
- package/dist/catalog.mjs +1 -1
- package/dist/checkout.cjs +62 -49
- package/dist/checkout.d.cts +1 -1
- package/dist/checkout.d.ts +1 -1
- package/dist/checkout.mjs +62 -49
- package/dist/db-react.d.cts +1 -1
- package/dist/db-react.d.ts +1 -1
- package/dist/db.cjs +303 -270
- package/dist/db.d.cts +1 -1
- package/dist/db.d.ts +1 -1
- package/dist/db.mjs +322 -289
- package/dist/entitlements.d.cts +1 -1
- package/dist/entitlements.d.ts +1 -1
- package/dist/firestore-compat.d.cts +1 -1
- package/dist/firestore-compat.d.ts +1 -1
- package/dist/index.cjs +1275 -1214
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +1390 -1329
- package/dist/mobile.cjs +328 -276
- package/dist/mobile.d.cts +12 -2
- package/dist/mobile.d.ts +12 -2
- package/dist/mobile.mjs +328 -276
- package/dist/mocks.cjs +5 -5
- package/dist/mocks.d.cts +2 -2
- package/dist/mocks.d.ts +2 -2
- package/dist/mocks.mjs +4 -4
- package/dist/notifications.cjs +1 -1
- package/dist/notifications.d.cts +1 -1
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.mjs +1 -1
- package/dist/react.cjs +119 -119
- package/dist/react.d.cts +8 -2
- package/dist/react.d.ts +8 -2
- package/dist/react.mjs +119 -119
- package/dist/support.cjs +1 -1
- package/dist/support.d.cts +1 -1
- package/dist/support.d.ts +1 -1
- package/dist/support.mjs +1 -1
- package/dist/telemetry.cjs +62 -49
- package/dist/telemetry.d.cts +1 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.mjs +62 -49
- package/dist/{types-D-9bjlM0.d.cts → types-Bl_4HROd.d.cts} +118 -19
- package/dist/{types-bVztFQTI.d.ts → types-Bqnsqvow.d.ts} +118 -19
- package/dist/usage.cjs +1 -1
- package/dist/usage.d.cts +1 -1
- package/dist/usage.d.ts +1 -1
- package/dist/usage.mjs +1 -1
- package/dist/webhooks.cjs +1 -1
- package/dist/webhooks.d.cts +1 -1
- package/dist/webhooks.d.ts +1 -1
- package/dist/webhooks.mjs +1 -1
- package/package.json +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,59 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.9.0] — 2026-10-11 (signOut deixa de falhar em silêncio)
|
|
11
|
+
|
|
12
|
+
> **Por que MINOR e não PATCH.** O conteúdo é conserto de defeito, mas o tipo
|
|
13
|
+
> público mudou: `signOut()` passou de `Promise<void>` para
|
|
14
|
+
> `Promise<SignOutResult>`. Em runtime é aditivo — quem faz
|
|
15
|
+
> `await client.auth.signOut()` e ignora o retorno continua idêntico. Em
|
|
16
|
+
> TypeScript quebra quem anotou o retorno como `void` explicitamente ou
|
|
17
|
+
> implementa `AuthNamespace` por conta própria. Chamar isso de patch faria o
|
|
18
|
+
> número mentir sobre o código, que é o defeito que estamos justamente
|
|
19
|
+
> consertando no ecossistema esta semana.
|
|
20
|
+
|
|
21
|
+
### Corrigido
|
|
22
|
+
|
|
23
|
+
- **`auth.signOut()` falhava em silêncio quando a revogação remota não acontecia** (bug_2bfde1e346a74737bf80104b1c95b2b2, continuação). A 3.8.0 consertou o *formato* da requisição (`application/x-www-form-urlencoded` + `client_id`, RFC 7009) — mas o `signOut` seguia devolvendo `void` e engolindo a falha num `console.warn`. Pro produto, "revoguei" e "o servidor recusou" eram **indistinguíveis**: a tela dizia "você saiu" e o `refresh_token` de 30 dias podia seguir válido no servidor. Num terminal compartilhado (PDV, balcão), é a próxima pessoa herdando a sessão.
|
|
24
|
+
- `auth.signOut()` e `mobile.signOut()` agora devolvem `SignOutResult` — `{ localSessionCleared, remoteRevocation }`, com `remoteRevocation` em `accepted | skipped | not_configured | failed`.
|
|
25
|
+
- **Não lança** em falha de revogação, de propósito: a sessão LOCAL é encerrada sempre (o usuário pediu pra sair, e deixá-lo logado porque a rede caiu é o pior dos mundos), e um `throw` seria engolido pelo `try/catch` que todo caller de signOut tem — inclusive o `<AccountBar>` deste próprio SDK. O sinal precisa voltar como **valor**, não como exceção.
|
|
26
|
+
- `not_configured` cobre o caso mais silencioso de todos: sem `oidcClientId`/`apiKey` o SDK não monta o `client_id` que o `/revoke` exige, então **nenhuma requisição saía** — zero fetch, zero erro, sessão do servidor intacta.
|
|
27
|
+
- Honestidade sobre o que `accepted` significa: a RFC 7009 §2.2 manda o `/revoke` responder 200 **inclusive** pra token desconhecido (não vazar enumeração). `accepted` é "o servidor aceitou a revogação", não "o token existia e morreu". `failed`, esse sim, é inequívoco.
|
|
28
|
+
- `<AccountBar>`: `onSignOut` passa a receber o `SignOutResult` (`undefined` se o signOut lançou).
|
|
29
|
+
|
|
30
|
+
- **Storage que falha podia abortar a saída do usuário.** Um `removeItem` que lançasse (localStorage bloqueado/quota; SecureStore indisponível no RN) derrubava o `signOut` inteiro **antes** do revoke: sobravam chaves no aparelho, a sessão do servidor seguia de pé e o produto recebia uma exceção no lugar da saída. Agora cada remoção é isolada, a revogação acontece mesmo assim, e `localSessionCleared: false` avisa que ainda pode haver material de sessão **neste** aparelho.
|
|
31
|
+
- No mobile, o `notify()` final também relia o storage: uma falha de **leitura** fazia o `signOut` rejeitar depois de já ter limpado e revogado — o resultado nunca chegava ao caller e os listeners de `onAuthStateChanged` não ficavam sabendo que o usuário saiu (a UI seguia mostrando sessão). O `notify` agora aceita o estado já conhecido (`null` pós-signOut) e nunca rejeita por causa do storage.
|
|
32
|
+
|
|
33
|
+
> As três entradas abaixo vieram do #46, mesclado depois do PR de release da 3.9.0 (#45) e antes de qualquer publicação. A 3.9.0 nunca foi publicada, então o número continua identificando um código só: este.
|
|
34
|
+
|
|
35
|
+
- **A trava contra mock em produção estava pela metade.** Com `env: 'dev'` vazado para um runtime de produção, só o `auth` respeitava a trava: o `checkout` caía no `MockCheckout` e devolvia link de pagamento falso (`https://localhost:9003/portal/checkout/...`) como se fosse real; a `telemetry` virava console e respondia ok sem enviar nada; o `db.sql()` lançava "use `neetru dev`". Agora a decisão é uma só — `isDevMode()` em `src/runtime-env.ts` — e os quatro pontos consultam ela.
|
|
36
|
+
- **A guarda que impede dependência de Node no bundle de navegador nunca rodava.** O teste se pulava quando `dist/` não existia, e o gate rodava os testes antes do build (inclusive com `--full`), assim como o CI. Os dois bugs CRÍTICOS que ela devia cobrir (`bug_0f836014`, `bug_168368ae`, o segundo publicado no npm) ficaram "cobertos" por um teste verde que não olhava nada. A guarda virou `scripts/browser-bundle-guard.mjs` e roda no `postbuild` — então também no `prepublishOnly`: bundle contaminado não chega mais ao npm. A ordem do gate e do CI passou a ser `lint → build → test`, o detector roda sempre com fixtures em memória e a varredura do artefato falha (em vez de pular) quando `dist/` não existe.
|
|
37
|
+
- **O refresh de token podia morrer para sempre.** O `fetch` do refresh ia sem prazo: uma conexão pendurada (captive portal, proxy que engole o pacote, app voltando do background) deixava a promise sem desfecho, e o `finally` que libera o latch nunca rodava — nenhum refresh novo saía até recarregar o app. Agora há prazo de 15 s em duas camadas (`src/timeout.ts`): `AbortSignal` que corta a conexão e uma corrida que garante o desfecho mesmo se o `fetch` injetado ignorar o sinal. Resposta que chega depois do prazo é descartada, para não ressuscitar uma sessão que o caller já encerrou. Vale para o refresh na web e para o `postToken` do mobile (refresh e troca `code`→tokens).
|
|
38
|
+
|
|
39
|
+
### Compatibilidade
|
|
40
|
+
|
|
41
|
+
- `signOut()` passou de `Promise<void>` para `Promise<SignOutResult>`. Em runtime é aditivo — quem faz `await client.auth.signOut()` e ignora o retorno continua idêntico. Em TypeScript só quebra quem anotou o retorno como `void` explicitamente (ex.: `const r: void = await signOut()`) ou implementa `AuthNamespace` por conta própria.
|
|
42
|
+
|
|
43
|
+
## [3.8.1] — 2026-10-11 (re-lease em falha de autenticação + doc de mTLS)
|
|
44
|
+
|
|
45
|
+
### Corrigido
|
|
46
|
+
|
|
47
|
+
- **`client.db.sql()` não se recuperava sozinho depois de um `rotate-credentials`** (bug_b7f5f2cff6d14a2aaa5d5c2068dc9dfd). A rotação (ALTER ROLE + userlist do PgBouncer) mantém vivas as conexões já abertas, mas toda conexão **nova** do pool, ainda com a senha do lease antigo, era recusada na autenticação até o próximo renew (~3 min). O re-lease reativo só cobria erro de rede/TLS, então os produtos recriavam o client na mão e vazavam pools. Agora falha de autenticação também dispara o re-lease: lease novo → pool novo → pool velho drenado com `end()` → a operação é repetida **uma vez**. Se a credencial nova também for recusada, o erro propaga (sem laço).
|
|
48
|
+
- Critério pelo SQLSTATE em `err.code`: `28P01` (senha inválida) e `28000` (autorização inválida). O PgBouncer devolve falha de SCRAM com o código genérico `08P01`; esse caso só conta com a mensagem `SASL authentication failed` / `password authentication failed` (`08P01` sozinho, como `query_wait_timeout`, **não** dispara).
|
|
49
|
+
- **Transações:** o `connect()` que abre a transação também ganha o re-lease + 1 nova tentativa, **só** em falha de autenticação (acontece no startup da conexão, antes do `BEGIN`; o corpo da transação nunca é repetido). Erro de rede/TLS no `connect()` segue sem retry, como antes.
|
|
50
|
+
- Só Postgres: o pool do `client.db.sql()` é `pg.Pool`; não há driver MySQL no SDK, então `ER_ACCESS_DENIED_ERROR` (1045) não se aplica.
|
|
51
|
+
- Sem API pública nova ou removida (`isAuthenticationError` é interno do módulo SQL).
|
|
52
|
+
|
|
53
|
+
### Documentação
|
|
54
|
+
|
|
55
|
+
- **A doc de `DbSqlLease` dizia que o mTLS de cliente "não está implementado no Core" e que `clientCert`/`clientKey` são "SEMPRE `null`". Isso é falso** (bug_e6e3af03f19c406994fe9d05a5f2617a). O texto veio do S2 de 2026-09-20 (`8d39b32`), baseado numa auditoria que já não batia com o código.
|
|
56
|
+
- O Core emite `sslca` + `clientCert` + `clientKey` em **todo** lease SQL (emissão e renovação), sem flag. O cert de cliente tem CN = `leaseId`, EKU `clientAuth` e 15 min de validade; a chave é EC P-256 efêmera. Se a CA não existir, o Core falha com 500 em vez de mandar `null`.
|
|
57
|
+
- O SDK já repassava os três ao `pg.Pool` (`ssl = { ca, cert, key, rejectUnauthorized: true }`). Agora há teste fixando isso nos dois factories.
|
|
58
|
+
- O PgBouncer da VM exige o cert de cliente (`client_tls_sslmode = verify-full` + `client_tls_ca_file` = CA do Core) **e** a senha SCRAM.
|
|
59
|
+
- Resultado: o mTLS está ativo de ponta a ponta. O `certificate expired` (alerta TLS 45) que a renovação e o re-lease curam é do cert de **cliente**, que expira com o lease. Não é o cert do servidor, que vale 365 dias. Comentários de `lease.ts`/`resilient-pool.ts`/`sql-client.ts` e o texto do `console.warn` de renovação falha foram corrigidos.
|
|
60
|
+
- `credentialVersion`: documentado que hoje é o placeholder fixo `1` do Core. A rotação é detectada pela troca de `password`, não por ele.
|
|
61
|
+
- Sem mudança de comportamento nem de tipos públicos (`clientCert`/`clientKey`/`sslca` seguem `string | null`, por tolerância a resposta sem o campo).
|
|
62
|
+
|
|
10
63
|
## [3.8.0] - 2026-10-03 — **feat(apps): chave `nrt_` só de servidor, `verifyAccessToken`, mobile integrado, correlation id**
|
|
11
64
|
|
|
12
65
|
Release **minor**. Nenhuma API pública removida; produtos que ainda usam a chave no navegador **continuam funcionando** (só ganham um aviso). Base para produtos com app móvel (primeiro: PDV em React Native/Expo).
|
package/README.md
CHANGED
|
@@ -107,7 +107,10 @@ await auth.signIn({ redirectUri });
|
|
|
107
107
|
await auth.completeSignIn(callbackUrl);
|
|
108
108
|
const res = await auth.authFetch('/vendas'); // Bearer access_token, renova 1x num 401
|
|
109
109
|
const me = await auth.getUserInfo(); // /userinfo do Core
|
|
110
|
-
await auth.signOut();
|
|
110
|
+
const out = await auth.signOut(); // limpa local + revoga refresh/access no Core
|
|
111
|
+
if (out.remoteRevocation === 'failed') { // NÃO é silencioso: trate no produto
|
|
112
|
+
warn('Saímos deste aparelho, mas não deu pra encerrar a sessão no servidor.');
|
|
113
|
+
}
|
|
111
114
|
```
|
|
112
115
|
|
|
113
116
|
`client.db` em React Native lança erro claro (dados de negócio vão pela API do
|
package/dist/ai.cjs
CHANGED
package/dist/ai.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { A as AiChatChoice, a as AiChatMessage, b as AiChatOptions, c as AiChatResult, d as AiChatUsage, e as AiContentPart, f as AiImageUrlPart, g as AiNamespace, h as AiResponseFormat, i as AiStreamHandle, j as AiStreamMeta, k as AiTextPart,
|
|
1
|
+
export { A as AiChatChoice, a as AiChatMessage, b as AiChatOptions, c as AiChatResult, d as AiChatUsage, e as AiContentPart, f as AiImageUrlPart, g as AiNamespace, h as AiResponseFormat, i as AiStreamHandle, j as AiStreamMeta, k as AiTextPart, aM as createAiNamespace } from './types-Bl_4HROd.cjs';
|
|
2
2
|
import 'drizzle-orm/node-postgres';
|
|
3
3
|
import './errors.cjs';
|
package/dist/ai.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { A as AiChatChoice, a as AiChatMessage, b as AiChatOptions, c as AiChatResult, d as AiChatUsage, e as AiContentPart, f as AiImageUrlPart, g as AiNamespace, h as AiResponseFormat, i as AiStreamHandle, j as AiStreamMeta, k as AiTextPart,
|
|
1
|
+
export { A as AiChatChoice, a as AiChatMessage, b as AiChatOptions, c as AiChatResult, d as AiChatUsage, e as AiContentPart, f as AiImageUrlPart, g as AiNamespace, h as AiResponseFormat, i as AiStreamHandle, j as AiStreamMeta, k as AiTextPart, aM as createAiNamespace } from './types-Bqnsqvow.js';
|
|
2
2
|
import 'drizzle-orm/node-postgres';
|
|
3
3
|
import './errors.js';
|