@neetru/sdk 2.3.5 → 3.0.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 +184 -0
- package/README.md +59 -22
- package/dist/auth.cjs +368 -142
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/auth.mjs +368 -142
- 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 -1
- package/dist/catalog.d.ts +1 -1
- 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 -1
- package/dist/checkout.d.ts +1 -1
- package/dist/checkout.mjs +21 -2
- package/dist/checkout.mjs.map +1 -1
- package/dist/db.cjs +36 -5
- package/dist/db.cjs.map +1 -1
- package/dist/db.d.cts +1 -1
- package/dist/db.d.ts +1 -1
- package/dist/db.mjs +36 -5
- 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 -1
- package/dist/entitlements.d.ts +1 -1
- 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 +432 -152
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -19
- package/dist/index.d.ts +31 -19
- package/dist/index.mjs +432 -152
- package/dist/index.mjs.map +1 -1
- package/dist/mocks.cjs +49 -37
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.cts +23 -19
- package/dist/mocks.d.ts +23 -19
- package/dist/mocks.mjs +49 -37
- 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 -1
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.mjs +80 -14
- package/dist/notifications.mjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/support.cjs +72 -12
- package/dist/support.cjs.map +1 -1
- package/dist/support.d.cts +1 -1
- package/dist/support.d.ts +1 -1
- 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 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.mjs +23 -4
- package/dist/telemetry.mjs.map +1 -1
- package/dist/{types-sGGN1vkg.d.cts → types-DLOvkeAP.d.cts} +110 -49
- package/dist/{types-CSC-RIdS.d.ts → types-dw19bdID.d.ts} +110 -49
- package/dist/usage.cjs +57 -63
- package/dist/usage.cjs.map +1 -1
- package/dist/usage.d.cts +1 -1
- package/dist/usage.d.ts +1 -1
- 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 -1
- package/dist/webhooks.d.ts +1 -1
- package/dist/webhooks.mjs +110 -33
- package/dist/webhooks.mjs.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,190 @@ 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.0] - 2026-05-27 — **MAJOR: contract hardening + Universal runtime + paths canonical**
|
|
9
|
+
|
|
10
|
+
> Major rewrite resolvendo 5 CRITICAL + 6 HIGH do review `CHEFE_SDK_REVIEW_2026-05-27`.
|
|
11
|
+
> 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).
|
|
12
|
+
>
|
|
13
|
+
> **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.
|
|
14
|
+
|
|
15
|
+
### BREAKING CHANGES
|
|
16
|
+
|
|
17
|
+
#### 1. `usage` namespace 100% rewrite (CRITICAL-SDK-01)
|
|
18
|
+
|
|
19
|
+
- **REMOVIDO** `usage.track(event, props)` — Core não aceitava esse shape; era vaporware testado contra mock. Use `usage.report(resource, qty, opts)`.
|
|
20
|
+
- **REMOVIDO** `usage.getQuota(metric)` — endpoint `/usage/quota` nunca existiu no Core. `usage.report()` devolve `{value, limit, remaining}` inline em todo POST.
|
|
21
|
+
- Paths corrigidos:
|
|
22
|
+
- `/sdk/v1/usage/record` → `/api/sdk/v1/usage/record` (canonical)
|
|
23
|
+
- `/sdk/v1/entitlements` → `/api/sdk/v1/entitlements` (canonical)
|
|
24
|
+
- `usage.report()` agora envia `Idempotency-Key: <uuid v4>` header automaticamente.
|
|
25
|
+
- `usage.check()` retorna novo field `behavior: "readonly" | null` (inferido de `reason === "limit_exceeded"`).
|
|
26
|
+
|
|
27
|
+
#### 2. `webhooks` namespace — `productId` obrigatório (CRITICAL-SDK-03)
|
|
28
|
+
|
|
29
|
+
- `RegisterWebhookInput.productId` adicionado. Default resolve do `config.productId`; lança `validation_failed` se ambos ausentes.
|
|
30
|
+
- `list(options?)`, `unregister(id, options?)`, `test(id, options?)` agora aceitam `{ productId }` (Core exige query param em todos os verbos).
|
|
31
|
+
- `webhooks.test()` envia `Idempotency-Key` header.
|
|
32
|
+
|
|
33
|
+
#### 3. `notifications` namespace — `productId` obrigatório (CRITICAL-SDK-04)
|
|
34
|
+
|
|
35
|
+
- `SendNotificationInput.productId` adicionado (Core valida via Zod `SendNotificationSchema`).
|
|
36
|
+
- `ListNotificationsOptions.productId` adicionado.
|
|
37
|
+
- `NotificationScopeOptions` novo type para `markRead`/`dismiss`.
|
|
38
|
+
- `notifications.send()` envia `Idempotency-Key` header.
|
|
39
|
+
|
|
40
|
+
#### 4. `support` namespace — endpoint canonical (CRITICAL-SDK-02)
|
|
41
|
+
|
|
42
|
+
- Endpoint mudou de `/api/v1/products/{slug}/tickets` (vaporware — **nunca existiu no Core**) para `/api/sdk/v1/support/tickets` (canonical SDK path).
|
|
43
|
+
- `productId` obrigatório (default `config.productId`).
|
|
44
|
+
- `createTicket()` envia `Idempotency-Key` header.
|
|
45
|
+
- `listMyTickets(options?)` aceita `{ productSlug }` override.
|
|
46
|
+
- **Pré-requisito Core**: endpoint `/api/sdk/v1/support/tickets` precisa ser construído (vide `docs/CORE_CHANGES_REQUIRED.md` §1).
|
|
47
|
+
|
|
48
|
+
#### 5. `verifyWebhookSignature` é async + Universal (HIGH-SDK-03)
|
|
49
|
+
|
|
50
|
+
- **Antes (2.x)**: `(payload, sig, secret) => boolean` — usava `require('node:crypto')` que quebrava em bundle browser/Edge ESM puro. README anunciava "Universal" mas mentia.
|
|
51
|
+
- **Agora (3.0)**: `(payload, sig, secret) => Promise<boolean>` via `WebCrypto.subtle.sign` HMAC-SHA-256 + constant-time XOR compare.
|
|
52
|
+
- Funciona em Node ≥20, browsers modernos, Vercel Edge Functions, Cloudflare Workers.
|
|
53
|
+
- Lança `NeetruError('runtime_unsupported')` se WebCrypto ausente (distingue "ambiente não suporta" de "assinatura inválida").
|
|
54
|
+
|
|
55
|
+
#### 6. `telemetry.event` / `telemetry.track` path canonical (CRITICAL-SDK-05)
|
|
56
|
+
|
|
57
|
+
- `POST /api/v1/sdk/telemetry/event` → `POST /api/sdk/v1/telemetry/event` (canonical SDK pattern).
|
|
58
|
+
- Pré-requisito Core: alias/handler para o canonical path (vide `docs/CORE_CHANGES_REQUIRED.md` §3).
|
|
59
|
+
|
|
60
|
+
#### 7. `baseUrl` allowlist fail-closed (HIGH-SDK-05)
|
|
61
|
+
|
|
62
|
+
- `createNeetruClient` agora chama `validateBaseUrl` antes de aceitar `config.baseUrl`.
|
|
63
|
+
- Allowlist padrão: HTTPS `*.neetru.com` + `localhost`/`127.0.0.1`/`*.test`/`*.localhost`.
|
|
64
|
+
- `NeetruClientConfig.allowedHosts: string[]` novo — adicione hosts custom (suffix match).
|
|
65
|
+
- Bypass: `NEETRU_ALLOW_INSECURE_BASEURL=1` (env) ou `globalThis.NEETRU_ALLOW_INSECURE_BASEURL='1'`. Warning no console quando ativo.
|
|
66
|
+
- Cenário ataque fechado: dev configura `NEETRU_BASE_URL=http://attacker.example/` no `.env`, agora lança `invalid_config` em vez de vazar Bearer.
|
|
67
|
+
|
|
68
|
+
#### 8. Retries default por método (HIGH-SDK-01)
|
|
69
|
+
|
|
70
|
+
- **GET/HEAD**: 2 retries default (= 3 tentativas) — idempotente, seguro.
|
|
71
|
+
- **POST/PUT/PATCH/DELETE**: **0 retries default** — mutations podem duplicar side effects (ex: `FieldValue.increment` no `usage/record`).
|
|
72
|
+
- Caller pode override: `httpRequest(config, { method: 'POST', ..., retries: 2 })`.
|
|
73
|
+
- Combinado com `Idempotency-Key` automático em mutations: dup-write rate → zero.
|
|
74
|
+
|
|
75
|
+
#### 9. Cleanup de stubs deprecated
|
|
76
|
+
|
|
77
|
+
- `initNeetru` (deprecated desde v0.2, no-op em v2.0) **definitivamente removido**.
|
|
78
|
+
- `NeetruConfig` type alias **removido** (use `NeetruClientConfig`).
|
|
79
|
+
|
|
80
|
+
#### 10. `NeetruErrorCode` ganhou `runtime_unsupported`
|
|
81
|
+
|
|
82
|
+
- 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).
|
|
83
|
+
|
|
84
|
+
### ADDED
|
|
85
|
+
|
|
86
|
+
- `src/idempotency.ts` — `generateIdempotencyKey()` via `crypto.randomUUID()` (Node ≥20, browsers, Edge).
|
|
87
|
+
- `src/base-url-allowlist.ts` — `validateBaseUrl(url, allowedHosts)` fail-closed.
|
|
88
|
+
- `HttpRequestOptions.idempotencyKey: boolean | string` — injeta header automaticamente em todo POST de mutation.
|
|
89
|
+
- `client.usage.check().behavior: 'readonly' | null` — sinal para `<EntitlementGate mode='readonly'>` decidir UI.
|
|
90
|
+
- `NeetruClientConfig.allowedHosts` — extension point para hosts custom (staging/proxies).
|
|
91
|
+
- `MockUsage.__getReports()` substitui `__getRecords()` (legacy alias mantido).
|
|
92
|
+
- Test suite: `src/__tests__/base-url-allowlist.test.ts` (16 tests), `src/__tests__/idempotency.test.ts` (9 tests).
|
|
93
|
+
- `docs/CORE_CHANGES_REQUIRED.md` — catálogo de 5 endpoints Core a criar/modificar para 3.0 funcionar end-to-end.
|
|
94
|
+
|
|
95
|
+
### FIXED
|
|
96
|
+
|
|
97
|
+
- `<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).
|
|
98
|
+
- README v2.x prometia "Universal: browser/Node/Edge" mas `verifyWebhookSignature` só funcionava em Node. 3.0 cumpre.
|
|
99
|
+
|
|
100
|
+
### Migration guide v2.x → v3.0
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
// ❌ Antes (v2.x)
|
|
104
|
+
await client.usage.track('api_call', { route: '/x' });
|
|
105
|
+
const quota = await client.usage.getQuota('api_calls');
|
|
106
|
+
|
|
107
|
+
await client.webhooks.register({
|
|
108
|
+
url: 'https://x.com/h',
|
|
109
|
+
events: ['subscription.activated'],
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
await client.notifications.send({
|
|
113
|
+
userId: 'u1',
|
|
114
|
+
kind: 'order.received',
|
|
115
|
+
title: 'Pedido',
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
await client.support.createTicket({
|
|
119
|
+
subject: 'help',
|
|
120
|
+
message: 'x',
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// ✅ Depois (v3.0)
|
|
124
|
+
const client = createNeetruClient({
|
|
125
|
+
apiKey: 'nrt_...',
|
|
126
|
+
productId: 'gestovendas', // 🆕 default p/ todos os namespaces
|
|
127
|
+
tenantId: 't-acme', // 🆕 default p/ usage
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const result = await client.usage.report('api_call', 1);
|
|
131
|
+
// result.value, result.limit, result.remaining inline — não precisa getQuota separado.
|
|
132
|
+
|
|
133
|
+
const allowed = await client.usage.check('api_call');
|
|
134
|
+
// allowed.behavior === 'readonly' quando over limit (use em <EntitlementGate>)
|
|
135
|
+
|
|
136
|
+
await client.webhooks.register({
|
|
137
|
+
// productId default config.productId, ou explícito:
|
|
138
|
+
url: 'https://x.com/h',
|
|
139
|
+
events: ['subscription.activated'],
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
await client.notifications.send({
|
|
143
|
+
userId: 'u1',
|
|
144
|
+
kind: 'order.received',
|
|
145
|
+
title: 'Pedido',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
await client.support.createTicket({
|
|
149
|
+
subject: 'help',
|
|
150
|
+
message: 'x',
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Verificação de assinatura de webhook — agora async
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
// ❌ Antes (v2.x) — sync, quebrava em Edge
|
|
158
|
+
import { verifyWebhookSignature } from '@neetru/sdk/webhooks';
|
|
159
|
+
const ok = verifyWebhookSignature(rawPayload, sigHeader, secret);
|
|
160
|
+
|
|
161
|
+
// ✅ Depois (v3.0) — async, Universal
|
|
162
|
+
const ok = await verifyWebhookSignature(rawPayload, sigHeader, secret);
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Endpoints Core que precisam ser criados/modificados antes do publish 3.0
|
|
166
|
+
|
|
167
|
+
Vide `docs/CORE_CHANGES_REQUIRED.md` completo:
|
|
168
|
+
|
|
169
|
+
1. **CRITICAL** — `POST/GET /api/sdk/v1/support/tickets` (customer-facing) — 3-4h.
|
|
170
|
+
2. **HIGH** — Idempotency-Key dedup em endpoints de mutation — 4-6h.
|
|
171
|
+
3. **HIGH** — `POST /api/sdk/v1/telemetry/event` (canonical) — 1-2h ou alias middleware.
|
|
172
|
+
4. **LOW** — `behavior` field em `/api/sdk/v1/entitlements` response — 30min.
|
|
173
|
+
5. **LOW** — Verificar envelope `/api/sdk/v1/datastore/{collection}` — 30min check.
|
|
174
|
+
|
|
175
|
+
### Tests
|
|
176
|
+
|
|
177
|
+
- **719 tests passing** (era 668 em 2.3.6). Tsc clean. Build clean.
|
|
178
|
+
- Contract tests reescritos para validar paths canonical + body shapes + headers (Idempotency-Key UUID v4 regex match).
|
|
179
|
+
|
|
180
|
+
## [2.3.6] - 2026-05-26 — **fix(bundle): webpackIgnore em TODOS os dynamic imports node-only — bug_168368ae [CRITICAL]**
|
|
181
|
+
|
|
182
|
+
### Corrigido
|
|
183
|
+
|
|
184
|
+
- **bug_168368aedb664edba1ca1f1945b568ac (CRITICAL) — fix 2.3.5 foi parcial: `webpackIgnore` aplicado só em `createSqlClientFromConfig`, mas `createPgPool` + `createDrizzleHandle` (helpers separados no mesmo arquivo) + os 3 dynamic imports em `MockDb.sql()` (`pg-mem`, `drizzle-orm/node-postgres`, `@electric-sql/pglite`, `drizzle-orm/pglite`) ainda estavam sem o magic comment.**
|
|
185
|
+
Resultado: webpack do consumer Next.js seguia o module graph daqueles paths e ainda tentava bundle `pg` → `Module not found: tls/fs` no client.
|
|
186
|
+
Fix 2.3.6: `/* webpackIgnore: true */` em **todos** os 7 spots de `await import('pg' | 'drizzle-orm/node-postgres' | 'pg-mem' | '@electric-sql/pglite' | 'drizzle-orm/pglite')` em `sql-client.ts` + `mocks.ts`.
|
|
187
|
+
|
|
188
|
+
### Testes (antirregressão atualizado)
|
|
189
|
+
|
|
190
|
+
- **`no-node-deps-in-browser-bundle.regression.test.ts`** expandido: agora pega `import("X")` dynamic SEM `webpackIgnore` (regex negative lookahead). Antes só cobria `from "X"` static. Adicionado 4 patterns: pg, drizzle-orm/node-postgres, pg-mem, @electric-sql/pglite.
|
|
191
|
+
|
|
8
192
|
## [2.3.5] - 2026-05-26 — **fix(bundle): node deps fora do browser entry — bug_0f836014 [CRITICAL]**
|
|
9
193
|
|
|
10
194
|
### 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
|