@neetru/sdk 2.3.6 → 3.0.1
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 +185 -0
- package/README.md +84 -22
- package/dist/auth.cjs +360 -140
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +1 -2
- package/dist/auth.d.ts +1 -2
- package/dist/auth.mjs +360 -140
- package/dist/auth.mjs.map +1 -1
- package/dist/catalog.cjs +21 -2
- package/dist/catalog.cjs.map +1 -1
- package/dist/catalog.d.cts +1 -2
- package/dist/catalog.d.ts +1 -2
- package/dist/catalog.mjs +21 -2
- package/dist/catalog.mjs.map +1 -1
- package/dist/checkout.cjs +21 -2
- package/dist/checkout.cjs.map +1 -1
- package/dist/checkout.d.cts +1 -2
- package/dist/checkout.d.ts +1 -2
- package/dist/checkout.mjs +21 -2
- package/dist/checkout.mjs.map +1 -1
- package/dist/db.cjs +28 -3
- package/dist/db.cjs.map +1 -1
- package/dist/db.d.cts +1 -2
- package/dist/db.d.ts +1 -2
- package/dist/db.mjs +28 -3
- package/dist/db.mjs.map +1 -1
- package/dist/entitlements.cjs +21 -2
- package/dist/entitlements.cjs.map +1 -1
- package/dist/entitlements.d.cts +1 -2
- package/dist/entitlements.d.ts +1 -2
- package/dist/entitlements.mjs +21 -2
- package/dist/entitlements.mjs.map +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +3 -1
- package/dist/errors.d.ts +3 -1
- package/dist/errors.mjs.map +1 -1
- package/dist/index.cjs +408 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -20
- package/dist/index.d.ts +31 -20
- package/dist/index.mjs +408 -146
- package/dist/index.mjs.map +1 -1
- package/dist/mocks.cjs +33 -33
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.cts +23 -20
- package/dist/mocks.d.ts +23 -20
- package/dist/mocks.mjs +33 -33
- package/dist/mocks.mjs.map +1 -1
- package/dist/notifications.cjs +80 -14
- package/dist/notifications.cjs.map +1 -1
- package/dist/notifications.d.cts +1 -2
- package/dist/notifications.d.ts +1 -2
- package/dist/notifications.mjs +80 -14
- package/dist/notifications.mjs.map +1 -1
- package/dist/react.d.cts +1 -2
- package/dist/react.d.ts +1 -2
- package/dist/support.cjs +72 -12
- package/dist/support.cjs.map +1 -1
- package/dist/support.d.cts +1 -2
- package/dist/support.d.ts +1 -2
- package/dist/support.mjs +72 -12
- package/dist/support.mjs.map +1 -1
- package/dist/telemetry.cjs +23 -4
- package/dist/telemetry.cjs.map +1 -1
- package/dist/telemetry.d.cts +1 -2
- package/dist/telemetry.d.ts +1 -2
- package/dist/telemetry.mjs +23 -4
- package/dist/telemetry.mjs.map +1 -1
- package/dist/{types-CSC-RIdS.d.ts → types-DALIhcbq.d.ts} +130 -74
- package/dist/{types-sGGN1vkg.d.cts → types-Lfd3LiAF.d.cts} +130 -74
- package/dist/usage.cjs +57 -63
- package/dist/usage.cjs.map +1 -1
- package/dist/usage.d.cts +1 -2
- package/dist/usage.d.ts +1 -2
- package/dist/usage.mjs +57 -63
- package/dist/usage.mjs.map +1 -1
- package/dist/webhooks.cjs +110 -33
- package/dist/webhooks.cjs.map +1 -1
- package/dist/webhooks.d.cts +1 -2
- package/dist/webhooks.d.ts +1 -2
- package/dist/webhooks.mjs +110 -33
- package/dist/webhooks.mjs.map +1 -1
- package/package.json +2 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,191 @@ All notable changes to `@neetru/sdk` will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.0.1] - 2026-05-29 — **fix: sincronizar VERSION + docstrings + contract-staging códigos de erro**
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- `src/index.ts` — `VERSION` constante sincronizada com `package.json` (`'3.0.0'` → `'3.0.1'`). Consumers que fazem `import { VERSION } from '@neetru/sdk'` recebiam `'3.0.0'` enquanto `npm list` mostrava `3.0.1` (LOW-NEW-SDK-01).
|
|
13
|
+
- `src/telemetry.ts` — JSDoc na linha 6 corrigido: path legacy `/api/v1/sdk/telemetry/event` → canônico `/api/sdk/v1/telemetry/event`. O código sempre usou o path correto; apenas a documentação estava stale (LOW-NEW-SDK-02).
|
|
14
|
+
- `src/__tests__/telemetry.test.ts` — comentário de cabeçalho atualizado para não dizer "(legado)" (LOW-NEW-SDK-02).
|
|
15
|
+
- `src/__tests__/contract-staging.test.ts` — `'http_error'` removido de todos os arrays `toContain`. `NeetruErrorCode` não inclui `'http_error'`; respostas HTTP não mapeáveis caem em `'unknown'`. Substituído por `'unknown'` em todos os 7 sites (LOW-NEW-SDK-03).
|
|
16
|
+
|
|
17
|
+
### Nota
|
|
18
|
+
|
|
19
|
+
Este patch corresponde ao commit `4c40f01` (inline realtime-protocol types) que não atualizou `VERSION` nem o CHANGELOG.
|
|
20
|
+
|
|
21
|
+
## [3.0.0] - 2026-05-27 — **MAJOR: contract hardening + Universal runtime + paths canonical**
|
|
22
|
+
|
|
23
|
+
> Major rewrite resolvendo 5 CRITICAL + 6 HIGH do review `CHEFE_SDK_REVIEW_2026-05-27`.
|
|
24
|
+
> SDK 2.3.6 estava com **4 dos 11 namespaces broken** contra Core LIVE (`usage`, `webhooks`, `notifications`, `support`) — 13 endpoints batendo 404/400. Tests passavam validando contrato errado (mock fetch aceita qualquer URL).
|
|
25
|
+
>
|
|
26
|
+
> **Justificativa do MAJOR**: paths/body shapes mudaram em 4 namespaces; 2 métodos removidos (`usage.track`, `usage.getQuota`); `verifyWebhookSignature` virou async. Toda CLI release/SaaS inaugural depende disso primeiro.
|
|
27
|
+
|
|
28
|
+
### BREAKING CHANGES
|
|
29
|
+
|
|
30
|
+
#### 1. `usage` namespace 100% rewrite (CRITICAL-SDK-01)
|
|
31
|
+
|
|
32
|
+
- **REMOVIDO** `usage.track(event, props)` — Core não aceitava esse shape; era vaporware testado contra mock. Use `usage.report(resource, qty, opts)`.
|
|
33
|
+
- **REMOVIDO** `usage.getQuota(metric)` — endpoint `/usage/quota` nunca existiu no Core. `usage.report()` devolve `{value, limit, remaining}` inline em todo POST.
|
|
34
|
+
- Paths corrigidos:
|
|
35
|
+
- `/sdk/v1/usage/record` → `/api/sdk/v1/usage/record` (canonical)
|
|
36
|
+
- `/sdk/v1/entitlements` → `/api/sdk/v1/entitlements` (canonical)
|
|
37
|
+
- `usage.report()` agora envia `Idempotency-Key: <uuid v4>` header automaticamente.
|
|
38
|
+
- `usage.check()` retorna novo field `behavior: "readonly" | null` (inferido de `reason === "limit_exceeded"`).
|
|
39
|
+
|
|
40
|
+
#### 2. `webhooks` namespace — `productId` obrigatório (CRITICAL-SDK-03)
|
|
41
|
+
|
|
42
|
+
- `RegisterWebhookInput.productId` adicionado. Default resolve do `config.productId`; lança `validation_failed` se ambos ausentes.
|
|
43
|
+
- `list(options?)`, `unregister(id, options?)`, `test(id, options?)` agora aceitam `{ productId }` (Core exige query param em todos os verbos).
|
|
44
|
+
- `webhooks.test()` envia `Idempotency-Key` header.
|
|
45
|
+
|
|
46
|
+
#### 3. `notifications` namespace — `productId` obrigatório (CRITICAL-SDK-04)
|
|
47
|
+
|
|
48
|
+
- `SendNotificationInput.productId` adicionado (Core valida via Zod `SendNotificationSchema`).
|
|
49
|
+
- `ListNotificationsOptions.productId` adicionado.
|
|
50
|
+
- `NotificationScopeOptions` novo type para `markRead`/`dismiss`.
|
|
51
|
+
- `notifications.send()` envia `Idempotency-Key` header.
|
|
52
|
+
|
|
53
|
+
#### 4. `support` namespace — endpoint canonical (CRITICAL-SDK-02)
|
|
54
|
+
|
|
55
|
+
- Endpoint mudou de `/api/v1/products/{slug}/tickets` (vaporware — **nunca existiu no Core**) para `/api/sdk/v1/support/tickets` (canonical SDK path).
|
|
56
|
+
- `productId` obrigatório (default `config.productId`).
|
|
57
|
+
- `createTicket()` envia `Idempotency-Key` header.
|
|
58
|
+
- `listMyTickets(options?)` aceita `{ productSlug }` override.
|
|
59
|
+
- **Pré-requisito Core**: endpoint `/api/sdk/v1/support/tickets` precisa ser construído (vide `docs/CORE_CHANGES_REQUIRED.md` §1).
|
|
60
|
+
|
|
61
|
+
#### 5. `verifyWebhookSignature` é async + Universal (HIGH-SDK-03)
|
|
62
|
+
|
|
63
|
+
- **Antes (2.x)**: `(payload, sig, secret) => boolean` — usava `require('node:crypto')` que quebrava em bundle browser/Edge ESM puro. README anunciava "Universal" mas mentia.
|
|
64
|
+
- **Agora (3.0)**: `(payload, sig, secret) => Promise<boolean>` via `WebCrypto.subtle.sign` HMAC-SHA-256 + constant-time XOR compare.
|
|
65
|
+
- Funciona em Node ≥20, browsers modernos, Vercel Edge Functions, Cloudflare Workers.
|
|
66
|
+
- Lança `NeetruError('runtime_unsupported')` se WebCrypto ausente (distingue "ambiente não suporta" de "assinatura inválida").
|
|
67
|
+
|
|
68
|
+
#### 6. `telemetry.event` / `telemetry.track` path canonical (CRITICAL-SDK-05)
|
|
69
|
+
|
|
70
|
+
- `POST /api/v1/sdk/telemetry/event` → `POST /api/sdk/v1/telemetry/event` (canonical SDK pattern).
|
|
71
|
+
- Pré-requisito Core: alias/handler para o canonical path (vide `docs/CORE_CHANGES_REQUIRED.md` §3).
|
|
72
|
+
|
|
73
|
+
#### 7. `baseUrl` allowlist fail-closed (HIGH-SDK-05)
|
|
74
|
+
|
|
75
|
+
- `createNeetruClient` agora chama `validateBaseUrl` antes de aceitar `config.baseUrl`.
|
|
76
|
+
- Allowlist padrão: HTTPS `*.neetru.com` + `localhost`/`127.0.0.1`/`*.test`/`*.localhost`.
|
|
77
|
+
- `NeetruClientConfig.allowedHosts: string[]` novo — adicione hosts custom (suffix match).
|
|
78
|
+
- Bypass: `NEETRU_ALLOW_INSECURE_BASEURL=1` (env) ou `globalThis.NEETRU_ALLOW_INSECURE_BASEURL='1'`. Warning no console quando ativo.
|
|
79
|
+
- Cenário ataque fechado: dev configura `NEETRU_BASE_URL=http://attacker.example/` no `.env`, agora lança `invalid_config` em vez de vazar Bearer.
|
|
80
|
+
|
|
81
|
+
#### 8. Retries default por método (HIGH-SDK-01)
|
|
82
|
+
|
|
83
|
+
- **GET/HEAD**: 2 retries default (= 3 tentativas) — idempotente, seguro.
|
|
84
|
+
- **POST/PUT/PATCH/DELETE**: **0 retries default** — mutations podem duplicar side effects (ex: `FieldValue.increment` no `usage/record`).
|
|
85
|
+
- Caller pode override: `httpRequest(config, { method: 'POST', ..., retries: 2 })`.
|
|
86
|
+
- Combinado com `Idempotency-Key` automático em mutations: dup-write rate → zero.
|
|
87
|
+
|
|
88
|
+
#### 9. Cleanup de stubs deprecated
|
|
89
|
+
|
|
90
|
+
- `initNeetru` (deprecated desde v0.2, no-op em v2.0) **definitivamente removido**.
|
|
91
|
+
- `NeetruConfig` type alias **removido** (use `NeetruClientConfig`).
|
|
92
|
+
|
|
93
|
+
#### 10. `NeetruErrorCode` ganhou `runtime_unsupported`
|
|
94
|
+
|
|
95
|
+
- Lançado por `verifyWebhookSignature` quando WebCrypto ausente. Não é breaking se você usa só `instanceof NeetruError`; é breaking se você fez `switch` no union type (TS error em case missing).
|
|
96
|
+
|
|
97
|
+
### ADDED
|
|
98
|
+
|
|
99
|
+
- `src/idempotency.ts` — `generateIdempotencyKey()` via `crypto.randomUUID()` (Node ≥20, browsers, Edge).
|
|
100
|
+
- `src/base-url-allowlist.ts` — `validateBaseUrl(url, allowedHosts)` fail-closed.
|
|
101
|
+
- `HttpRequestOptions.idempotencyKey: boolean | string` — injeta header automaticamente em todo POST de mutation.
|
|
102
|
+
- `client.usage.check().behavior: 'readonly' | null` — sinal para `<EntitlementGate mode='readonly'>` decidir UI.
|
|
103
|
+
- `NeetruClientConfig.allowedHosts` — extension point para hosts custom (staging/proxies).
|
|
104
|
+
- `MockUsage.__getReports()` substitui `__getRecords()` (legacy alias mantido).
|
|
105
|
+
- Test suite: `src/__tests__/base-url-allowlist.test.ts` (16 tests), `src/__tests__/idempotency.test.ts` (9 tests).
|
|
106
|
+
- `docs/CORE_CHANGES_REQUIRED.md` — catálogo de 5 endpoints Core a criar/modificar para 3.0 funcionar end-to-end.
|
|
107
|
+
|
|
108
|
+
### FIXED
|
|
109
|
+
|
|
110
|
+
- `<EntitlementGate>` v1.1 não morre mais em silent `allowed:false` — paths corrigidos no `usage.check` (era dependência transitiva, fixed via CRITICAL-SDK-01).
|
|
111
|
+
- README v2.x prometia "Universal: browser/Node/Edge" mas `verifyWebhookSignature` só funcionava em Node. 3.0 cumpre.
|
|
112
|
+
|
|
113
|
+
### Migration guide v2.x → v3.0
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
// ❌ Antes (v2.x)
|
|
117
|
+
await client.usage.track('api_call', { route: '/x' });
|
|
118
|
+
const quota = await client.usage.getQuota('api_calls');
|
|
119
|
+
|
|
120
|
+
await client.webhooks.register({
|
|
121
|
+
url: 'https://x.com/h',
|
|
122
|
+
events: ['subscription.activated'],
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
await client.notifications.send({
|
|
126
|
+
userId: 'u1',
|
|
127
|
+
kind: 'order.received',
|
|
128
|
+
title: 'Pedido',
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
await client.support.createTicket({
|
|
132
|
+
subject: 'help',
|
|
133
|
+
message: 'x',
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// ✅ Depois (v3.0)
|
|
137
|
+
const client = createNeetruClient({
|
|
138
|
+
apiKey: 'nrt_...',
|
|
139
|
+
productId: 'gestovendas', // 🆕 default p/ todos os namespaces
|
|
140
|
+
tenantId: 't-acme', // 🆕 default p/ usage
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const result = await client.usage.report('api_call', 1);
|
|
144
|
+
// result.value, result.limit, result.remaining inline — não precisa getQuota separado.
|
|
145
|
+
|
|
146
|
+
const allowed = await client.usage.check('api_call');
|
|
147
|
+
// allowed.behavior === 'readonly' quando over limit (use em <EntitlementGate>)
|
|
148
|
+
|
|
149
|
+
await client.webhooks.register({
|
|
150
|
+
// productId default config.productId, ou explícito:
|
|
151
|
+
url: 'https://x.com/h',
|
|
152
|
+
events: ['subscription.activated'],
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
await client.notifications.send({
|
|
156
|
+
userId: 'u1',
|
|
157
|
+
kind: 'order.received',
|
|
158
|
+
title: 'Pedido',
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
await client.support.createTicket({
|
|
162
|
+
subject: 'help',
|
|
163
|
+
message: 'x',
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Verificação de assinatura de webhook — agora async
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
// ❌ Antes (v2.x) — sync, quebrava em Edge
|
|
171
|
+
import { verifyWebhookSignature } from '@neetru/sdk/webhooks';
|
|
172
|
+
const ok = verifyWebhookSignature(rawPayload, sigHeader, secret);
|
|
173
|
+
|
|
174
|
+
// ✅ Depois (v3.0) — async, Universal
|
|
175
|
+
const ok = await verifyWebhookSignature(rawPayload, sigHeader, secret);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Endpoints Core que precisam ser criados/modificados antes do publish 3.0
|
|
179
|
+
|
|
180
|
+
Vide `docs/CORE_CHANGES_REQUIRED.md` completo:
|
|
181
|
+
|
|
182
|
+
1. **CRITICAL** — `POST/GET /api/sdk/v1/support/tickets` (customer-facing) — 3-4h.
|
|
183
|
+
2. **HIGH** — Idempotency-Key dedup em endpoints de mutation — 4-6h.
|
|
184
|
+
3. **HIGH** — `POST /api/sdk/v1/telemetry/event` (canonical) — 1-2h ou alias middleware.
|
|
185
|
+
4. **LOW** — `behavior` field em `/api/sdk/v1/entitlements` response — 30min.
|
|
186
|
+
5. **LOW** — Verificar envelope `/api/sdk/v1/datastore/{collection}` — 30min check.
|
|
187
|
+
|
|
188
|
+
### Tests
|
|
189
|
+
|
|
190
|
+
- **719 tests passing** (era 668 em 2.3.6). Tsc clean. Build clean.
|
|
191
|
+
- Contract tests reescritos para validar paths canonical + body shapes + headers (Idempotency-Key UUID v4 regex match).
|
|
192
|
+
|
|
8
193
|
## [2.3.6] - 2026-05-26 — **fix(bundle): webpackIgnore em TODOS os dynamic imports node-only — bug_168368ae [CRITICAL]**
|
|
9
194
|
|
|
10
195
|
### Corrigido
|
package/README.md
CHANGED
|
@@ -1,62 +1,79 @@
|
|
|
1
1
|
# @neetru/sdk
|
|
2
2
|
|
|
3
|
-
> Biblioteca runtime oficial pra consumir o ecossistema Neetru a partir de produtos SaaS (Next.js, Node, browser, Edge runtimes).
|
|
3
|
+
> Biblioteca runtime oficial pra consumir o ecossistema Neetru a partir de produtos SaaS (Next.js, Node ≥20, browser, Edge runtimes).
|
|
4
4
|
|
|
5
5
|
<p>
|
|
6
6
|
<img alt="npm" src="https://img.shields.io/npm/v/@neetru/sdk?logo=npm">
|
|
7
7
|
<img alt="downloads" src="https://img.shields.io/npm/dm/@neetru/sdk?logo=npm">
|
|
8
8
|
<img alt="bundle size" src="https://img.shields.io/bundlephobia/minzip/@neetru/sdk">
|
|
9
|
-
<img alt="Node" src="https://img.shields.io/badge/node-%3E%
|
|
9
|
+
<img alt="Node" src="https://img.shields.io/badge/node-%3E%3D20-339933?logo=node.js&logoColor=white">
|
|
10
10
|
<img alt="license" src="https://img.shields.io/badge/license-MIT-22c55e">
|
|
11
11
|
</p>
|
|
12
12
|
|
|
13
|
+
> ## ⚠ 3.0 é breaking — leia o [CHANGELOG](./CHANGELOG.md) antes de upgrade
|
|
14
|
+
>
|
|
15
|
+
> SDK 2.x estava com 4 namespaces broken contra Core LIVE. 3.0 corrige paths canonical, exige `productId` em mutations, adiciona `Idempotency-Key` automático, `baseUrl` allowlist fail-closed, e `verifyWebhookSignature` virou Universal async via WebCrypto.
|
|
16
|
+
>
|
|
17
|
+
> **Métodos removidos**: `usage.track`, `usage.getQuota` (use `usage.report` / `usage.check`).
|
|
18
|
+
>
|
|
19
|
+
> **Migration guide completo no CHANGELOG.md**.
|
|
20
|
+
|
|
13
21
|
## Instalação
|
|
14
22
|
|
|
15
23
|
```bash
|
|
16
24
|
npm install @neetru/sdk
|
|
17
25
|
```
|
|
18
26
|
|
|
19
|
-
## Hello world
|
|
27
|
+
## Hello world (3.0)
|
|
20
28
|
|
|
21
29
|
```ts
|
|
22
30
|
import { createNeetruClient } from '@neetru/sdk';
|
|
23
31
|
|
|
24
32
|
const neetru = createNeetruClient({
|
|
25
33
|
apiKey: process.env.NEETRU_API_KEY, // nrt_<keyId>_<secret>
|
|
34
|
+
productId: 'gestovendas', // 3.0: default p/ todos namespaces
|
|
35
|
+
tenantId: 't-acme', // 3.0: default p/ usage
|
|
26
36
|
env: 'prod', // 'dev' = mocks in-memory
|
|
27
37
|
});
|
|
28
38
|
|
|
29
39
|
// Auth
|
|
30
40
|
const user = await neetru.auth.signIn();
|
|
31
|
-
console.log('logado como:', user?.email);
|
|
32
41
|
|
|
33
|
-
//
|
|
34
|
-
const
|
|
35
|
-
|
|
42
|
+
// Meter consumo (canonical /api/sdk/v1/usage/record)
|
|
43
|
+
const r = await neetru.usage.report('api_call', 1);
|
|
44
|
+
console.log(r.value, '/', r.limit, '— restam', r.remaining);
|
|
45
|
+
|
|
46
|
+
// Entitlement check com behavior=readonly
|
|
47
|
+
const check = await neetru.usage.check('api_call');
|
|
48
|
+
if (!check.allowed && check.behavior === 'readonly') {
|
|
49
|
+
// UI degradada — read-only sem quebrar engajamento
|
|
50
|
+
}
|
|
36
51
|
```
|
|
37
52
|
|
|
38
53
|
## Princípios
|
|
39
54
|
|
|
40
55
|
- **Vendor-neutral** — superfície pública NÃO vaza Firebase/Stripe/etc. Backend Neetru pode mudar no futuro sem reescrever produto.
|
|
41
56
|
- **Tree-shakable** — ESM-first, sem side-effects. Importe só os namespaces que usa.
|
|
42
|
-
- **Universal** — browser, Node ≥
|
|
57
|
+
- **Universal** — browser, Node ≥20, Edge runtimes (Vercel Edge, Cloudflare Workers). Usa `fetch` global + WebCrypto.
|
|
58
|
+
- **Fail-closed segurança** — `baseUrl` allowlist (`*.neetru.com` + localhost) rejeita phishing/MITM. Bypass: `NEETRU_ALLOW_INSECURE_BASEURL=1`.
|
|
59
|
+
- **Idempotency-Key automático** — mutations (`usage.report`, `webhooks.test`, `notifications.send`, `support.createTicket`) injetam UUID v4 header. `retries: 0` default em POSTs para defesa em camada.
|
|
43
60
|
- **Tipado** — erros via `NeetruError` com `.code`, `.status`, `.requestId`.
|
|
44
61
|
- **Dev mode** — `NEETRU_ENV=dev` ativa mocks automáticos — zero rede em testes locais.
|
|
45
62
|
|
|
46
|
-
## Namespaces
|
|
47
|
-
|
|
48
|
-
| Namespace | O que oferece |
|
|
49
|
-
|
|
50
|
-
| `auth` | OIDC sign-in
|
|
51
|
-
| `catalog` | Produtos públicos (`list` / `get`) |
|
|
52
|
-
| `entitlements` | Verificação
|
|
53
|
-
| `telemetry` | `event(...)` + `log(...)`
|
|
54
|
-
| `usage` | `
|
|
55
|
-
| `support` | `createTicket` / `listMyTickets` |
|
|
56
|
-
| `db` | Coleções tenant-scoped (
|
|
57
|
-
| `checkout` | Stripe Checkout intent
|
|
58
|
-
| `webhooks`
|
|
59
|
-
| `notifications`
|
|
63
|
+
## Namespaces 3.0
|
|
64
|
+
|
|
65
|
+
| Namespace | O que oferece | Endpoint |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| `auth` | OIDC sign-in/out + verifyToken | `auth.neetru.com/api/v1/oauth/*` |
|
|
68
|
+
| `catalog` | Produtos públicos (`list` / `get`) | `/api/sdk/v1/catalog` |
|
|
69
|
+
| `entitlements` | Verificação boolean simples (legacy compat) | `/api/v1/sdk/entitlements/check` |
|
|
70
|
+
| `telemetry` | `event(...)` + `track(...)` + `log(...)` | `/api/sdk/v1/telemetry/{event,log}` |
|
|
71
|
+
| `usage` | `report` / `check` (metering + entitlement full) | `/api/sdk/v1/usage/record`, `/api/sdk/v1/entitlements` |
|
|
72
|
+
| `support` | `createTicket` / `listMyTickets` | `/api/sdk/v1/support/tickets` ⭐ 3.0 |
|
|
73
|
+
| `db` | Coleções tenant-scoped (offline-first v2.0) | `/api/sdk/v1/datastore/*` |
|
|
74
|
+
| `checkout` | Stripe Checkout intent | `/api/v1/checkout/intents` |
|
|
75
|
+
| `webhooks` | Produtos registram URL pra receber eventos | `/api/sdk/v1/webhooks` |
|
|
76
|
+
| `notifications` | Produto envia notification in-app | `/api/sdk/v1/notifications` |
|
|
60
77
|
|
|
61
78
|
## Exemplos por namespace
|
|
62
79
|
|
|
@@ -78,6 +95,26 @@ Eventos recebidos no seu endpoint chegam com:
|
|
|
78
95
|
- `X-Neetru-Signature: sha256=<hmac>` (se `secret` registrado)
|
|
79
96
|
- `X-Neetru-Timestamp: <ms>` (replay protection — rejeitar > 5min skew)
|
|
80
97
|
|
|
98
|
+
#### Verificar assinatura no consumer (3.0 — async + Universal)
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { verifyWebhookSignature } from '@neetru/sdk';
|
|
102
|
+
|
|
103
|
+
// Next.js Route Handler (Edge OU Node runtime — funciona em ambos)
|
|
104
|
+
export async function POST(req: Request) {
|
|
105
|
+
const raw = await req.text();
|
|
106
|
+
const sig = req.headers.get('X-Neetru-Signature');
|
|
107
|
+
const ok = await verifyWebhookSignature(raw, sig, process.env.NEETRU_WEBHOOK_SECRET!);
|
|
108
|
+
if (!ok) return new Response('unauthorized', { status: 401 });
|
|
109
|
+
|
|
110
|
+
const event = JSON.parse(raw);
|
|
111
|
+
// ... handle event
|
|
112
|
+
return Response.json({ ok: true });
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
> **Breaking 3.0**: era `boolean` sync usando `node:crypto`. Agora `Promise<boolean>` via WebCrypto.subtle — funciona em Cloudflare Workers, Vercel Edge, browsers e Node ≥20.
|
|
117
|
+
|
|
81
118
|
### Notifications produto → user (v1.2)
|
|
82
119
|
|
|
83
120
|
```ts
|
|
@@ -184,6 +221,31 @@ const neetru = createNeetruClient({
|
|
|
184
221
|
- Zero dependências runtime (usa `fetch` global)
|
|
185
222
|
- Bundle minzip <10KB (todos namespaces somados, tree-shake-friendly)
|
|
186
223
|
|
|
224
|
+
## Testes de contrato (staging)
|
|
225
|
+
|
|
226
|
+
O arquivo `src/__tests__/contract-staging.test.ts` contém testes que exercitam o HTTP real contra um ambiente de staging. Por default, todos os testes são skippados quando `NEETRU_STAGING_URL` não estiver definido.
|
|
227
|
+
|
|
228
|
+
Para rodar:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
NEETRU_STAGING_URL=https://api.staging.neetru.com \
|
|
232
|
+
NEETRU_STAGING_API_KEY=nrt_<keyId>_<secret> \
|
|
233
|
+
npx vitest run src/__tests__/contract-staging.test.ts
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Variáveis de ambiente:
|
|
237
|
+
|
|
238
|
+
| Variável | Obrigatória | Descrição |
|
|
239
|
+
|---|---|---|
|
|
240
|
+
| `NEETRU_STAGING_URL` | Sim | URL base da API de staging |
|
|
241
|
+
| `NEETRU_STAGING_API_KEY` | Sim | API key no formato `nrt_<keyId>_<secret>` |
|
|
242
|
+
| `NEETRU_STAGING_PRODUCT_ID` | Não | productId cadastrado no staging (default: `gestovendas`) |
|
|
243
|
+
| `NEETRU_STAGING_TENANT_ID` | Não | tenantId válido no staging (default: `t-acme`) |
|
|
244
|
+
|
|
245
|
+
Namespaces cobertos: `catalog.list`, `catalog.get`, `entitlements.check`, `entitlements.checkDetailed`, `usage.report`, `usage.check`, `telemetry.event`, `telemetry.log`, `auth.getUser`, `auth.signIn`.
|
|
246
|
+
|
|
247
|
+
Os testes assertam apenas o shape/tipos da resposta, nunca valores exatos — staging pode ter dados variáveis mas o contrato de formato deve ser estável.
|
|
248
|
+
|
|
187
249
|
## Mais info
|
|
188
250
|
|
|
189
251
|
- **Repo:** [github.com/Neetru/neetru-core](https://github.com/Neetru/neetru-core)
|