@neetru/sdk 3.7.0 → 3.8.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 +55 -0
- package/README.md +66 -1
- package/dist/ai.cjs +221 -177
- package/dist/ai.d.cts +1 -1
- package/dist/ai.d.ts +1 -1
- package/dist/ai.mjs +221 -177
- package/dist/auth.cjs +1227 -1064
- package/dist/auth.d.cts +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/auth.mjs +1224 -1061
- package/dist/catalog.cjs +164 -97
- package/dist/catalog.d.cts +1 -1
- package/dist/catalog.d.ts +1 -1
- package/dist/catalog.mjs +164 -97
- package/dist/checkout.cjs +182 -115
- package/dist/checkout.d.cts +1 -1
- package/dist/checkout.d.ts +1 -1
- package/dist/checkout.mjs +181 -114
- package/dist/db-react.d.cts +1 -1
- package/dist/db-react.d.ts +1 -1
- package/dist/db.cjs +370 -298
- package/dist/db.d.cts +1 -1
- package/dist/db.d.ts +1 -1
- package/dist/db.mjs +362 -290
- package/dist/entitlements.cjs +17 -10
- package/dist/entitlements.d.cts +1 -1
- package/dist/entitlements.d.ts +1 -1
- package/dist/entitlements.mjs +17 -10
- package/dist/errors.cjs +15 -8
- package/dist/errors.d.cts +24 -3
- package/dist/errors.d.ts +24 -3
- package/dist/errors.mjs +14 -7
- package/dist/firestore-compat.d.cts +1 -1
- package/dist/firestore-compat.d.ts +1 -1
- package/dist/index.cjs +1409 -1075
- package/dist/index.d.cts +177 -3
- package/dist/index.d.ts +177 -3
- package/dist/index.mjs +1544 -1217
- package/dist/mobile.cjs +400 -181
- package/dist/mobile.d.cts +59 -4
- package/dist/mobile.d.ts +59 -4
- package/dist/mobile.mjs +400 -181
- package/dist/mocks.cjs +9 -2
- package/dist/mocks.d.cts +1 -1
- package/dist/mocks.d.ts +1 -1
- package/dist/mocks.mjs +9 -2
- package/dist/notifications.cjs +197 -130
- package/dist/notifications.d.cts +1 -1
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.mjs +196 -129
- package/dist/react.cjs +303 -282
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.mjs +295 -274
- package/dist/support.cjs +299 -229
- package/dist/support.d.cts +8 -4
- package/dist/support.d.ts +8 -4
- package/dist/support.mjs +298 -228
- package/dist/telemetry.cjs +234 -167
- package/dist/telemetry.d.cts +1 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.mjs +234 -167
- package/dist/{types-Bx4kTLmk.d.cts → types-D-9bjlM0.d.cts} +48 -1
- package/dist/{types-Dx0IrOSF.d.ts → types-bVztFQTI.d.ts} +48 -1
- package/dist/usage.cjs +183 -116
- package/dist/usage.d.cts +1 -1
- package/dist/usage.d.ts +1 -1
- package/dist/usage.mjs +183 -116
- package/dist/webhooks.cjs +215 -148
- package/dist/webhooks.d.cts +1 -1
- package/dist/webhooks.d.ts +1 -1
- package/dist/webhooks.mjs +212 -145
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { createNeetruClient, getServerNeetruClient } from './auth.cjs';
|
|
2
2
|
export { NeetruAuthRequiredError, NeetruError, NeetruErrorCode } from './errors.cjs';
|
|
3
|
-
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, l as AuthNamespace, m as AuthStateListener, C as CatalogListOptions, n as CatalogListResponse, p as CheckoutIntentInfo, q as CheckoutIntentStatus, r as CheckoutNamespace, s as CheckoutStartInput, t as CheckoutStartResult, u as CheckoutTenantType, v as CompleteSignInResult, y as CreateTicketInput, D as DEFAULT_BASE_URL, z as DbBatchOp, B as DbChangeType, E as DbCollectionRef, F as DbDoc, G as DbDocRef, H as DbGetResult, I as DbListResult, J as DbNamespace, K as DbQuery, L as DbSqlLease, M as DbWhereFilter, O as
|
|
3
|
+
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, l as AuthNamespace, m as AuthStateListener, C as CatalogListOptions, n as CatalogListResponse, p as CheckoutIntentInfo, q as CheckoutIntentStatus, r as CheckoutNamespace, s as CheckoutStartInput, t as CheckoutStartResult, u as CheckoutTenantType, v as CompleteSignInResult, y as CreateTicketInput, D as DEFAULT_BASE_URL, z as DbBatchOp, B as DbChangeType, E as DbCollectionRef, F as DbDoc, G as DbDocRef, H as DbGetResult, I as DbListResult, J as DbNamespace, K as DbQuery, L as DbSqlLease, M as DbWhereFilter, O as EndUserTokenProvider, P as EntitlementCheck, Q as FieldSentinel, R as IncrementSentinel, S as ListNotificationsOptions, T as MockCheckout, U as MockNotifications, V as MockWebhooks, W as NEETRU_SENTINEL_KEY, X as NeetruClient, Y as NeetruClientConfig, Z as NeetruDb, $ as NeetruDbEngine, a0 as NeetruDbError, a1 as NeetruDbErrorCode, a2 as NeetruDbOptions, a3 as NeetruDbTransport, a4 as NeetruEnv, a5 as NeetruSqlClient, a6 as NeetruUser, a7 as NotificationScopeOptions, a8 as NotificationsNamespace, a9 as Product, aa as ProductNotification, ab as ProductNotificationSeverity, ac as ProductPlan, ad as ProductStatus, af as RedirectCallbackResult, ag as RegisterWebhookInput, ah as ResolvedConfig, ai as SendNotificationInput, aj as ServerTimestampSentinel, ak as SignInOptions, am as SupportNamespace, an as SupportSeverity, ao as SupportStatus, ap as SupportTicket, as as TelemetryEventAck, at as TelemetryEventInput, ax as UsageEventInput, ay as UsageNamespace, az as UsageQuota, aA as VerifyTokenOptions, aB as VerifyWebhookRequestOptions, aC as VerifyWebhookRequestResult, aD as WebhookEndpoint, aE as WebhookEvent, aF as WebhookScopeOptions, aG as WebhookTestResult, aH as WebhooksNamespace, aI as WithFieldSentinels, aK as createAiNamespace, aL as createCheckoutNamespace, aM as createNeetruDb, aN as createNotificationsNamespace, aP as createWebhooksNamespace, aR as increment, aS as isFieldSentinel, aT as isIncrementSentinel, aU as isServerTimestampSentinel, aV as serverTimestamp, aW as verifyWebhookRequest, aX as verifyWebhookSignature } from './types-D-9bjlM0.cjs';
|
|
4
4
|
export { DEV_FIXTURE_USER, MockAi, MockAuth, MockAuthOptions, MockDb, MockEntitlements, MockSupport, MockUsage } from './mocks.cjs';
|
|
5
|
+
import { JWTPayload } from 'jose';
|
|
5
6
|
import 'drizzle-orm/node-postgres';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -38,6 +39,179 @@ import 'drizzle-orm/node-postgres';
|
|
|
38
39
|
*/
|
|
39
40
|
declare function checkCoreVersionCompat(coreVersion: string): void;
|
|
40
41
|
|
|
42
|
+
/**
|
|
43
|
+
* 3.8.0 — `verifyAccessToken`: validação SERVER-SIDE do access_token OIDC do
|
|
44
|
+
* usuário final, para a API do PRODUTO aceitar `Authorization: Bearer
|
|
45
|
+
* <access_token>` (app React Native / SPA) além do cookie de sessão.
|
|
46
|
+
*
|
|
47
|
+
* ## Fluxo canônico (decisão do dono, 2026-10-03)
|
|
48
|
+
*
|
|
49
|
+
* app/site ──Bearer access_token──▶ API do produto ──SDK + nrt_ (servidor)──▶ Core
|
|
50
|
+
*
|
|
51
|
+
* O app nunca carrega a chave `nrt_`. Ele faz login no auth.neetru.com (PKCE,
|
|
52
|
+
* client OIDC público do app) e manda o access_token pra API do produto, que
|
|
53
|
+
* valida aqui — sem ir ao Core por request.
|
|
54
|
+
*
|
|
55
|
+
* ## Formato real do token (conferido no Core, `src/lib/oidc/tokens.ts`)
|
|
56
|
+
*
|
|
57
|
+
* header: `{ alg: 'RS256', kid, typ: 'JWT' }`
|
|
58
|
+
* claims: `iss` = `https://auth.neetru.com` · `sub` = uid do usuário (ou
|
|
59
|
+
* `client:<client_id>` em client_credentials) · `aud` = `client_id`
|
|
60
|
+
* (string) · `client_id` · `scope` (string separada por espaço) ·
|
|
61
|
+
* `iat` · `exp` (15 min) · `jti`.
|
|
62
|
+
* JWKS: `https://auth.neetru.com/api/v1/oauth/.well-known/jwks`.
|
|
63
|
+
*
|
|
64
|
+
* O id_token usa a MESMA chave, `iss` e `aud` — o que o distingue é NÃO ter
|
|
65
|
+
* `jti`/`scope`/`client_id`. Por isso exigimos os três: um id_token (que vai
|
|
66
|
+
* para terceiros como prova de login) não serve de credencial de API.
|
|
67
|
+
*
|
|
68
|
+
* ## Revogação
|
|
69
|
+
*
|
|
70
|
+
* A validação é local (assinatura + claims), sem consulta ao Core. Um access
|
|
71
|
+
* token revogado continua aceito até expirar — no máximo 15 min (TTL do Core).
|
|
72
|
+
* Para encerrar a sessão de verdade, o app revoga o refresh_token no logout
|
|
73
|
+
* (o `@neetru/sdk/mobile` faz isso no `signOut`). O `/introspect` do Core é só
|
|
74
|
+
* para clients confidenciais do mesmo `client_id`, então não serve a uma API
|
|
75
|
+
* que aceita tokens de vários clients (web + iOS + Android).
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
/** Issuer canônico do Core em produção. */
|
|
79
|
+
declare const NEETRU_OIDC_ISSUER = "https://auth.neetru.com";
|
|
80
|
+
interface VerifyAccessTokenOptions {
|
|
81
|
+
/**
|
|
82
|
+
* `client_id` OIDC aceitos como `aud` — tipicamente o client web + o do app
|
|
83
|
+
* iOS + o do app Android DO MESMO PRODUTO. Obrigatório e não-vazio: sem isso
|
|
84
|
+
* um token emitido para o client de OUTRO produto passaria.
|
|
85
|
+
*/
|
|
86
|
+
audience: string | readonly string[];
|
|
87
|
+
/** Escopos que o token TEM que ter (todos). Ex.: `['openid']`. Default: nenhum. */
|
|
88
|
+
requiredScopes?: readonly string[];
|
|
89
|
+
/** Issuer esperado. Default `https://auth.neetru.com`. Só mude para staging/emulador. */
|
|
90
|
+
issuer?: string;
|
|
91
|
+
/** URL do JWKS. Default `<issuer>/api/v1/oauth/.well-known/jwks`. */
|
|
92
|
+
jwksUrl?: string;
|
|
93
|
+
/** TTL da instância de JWKS cacheada. Default 1h. */
|
|
94
|
+
jwksCacheTtlMs?: number;
|
|
95
|
+
/** Tolerância de relógio para `exp`/`iat`/`nbf`, em segundos. Default 5, máx 60. */
|
|
96
|
+
clockToleranceSec?: number;
|
|
97
|
+
/**
|
|
98
|
+
* Aceitar token de máquina (`client_credentials`, `sub` = `client:<id>`).
|
|
99
|
+
* Default `false` — a API do produto quer um USUÁRIO.
|
|
100
|
+
*/
|
|
101
|
+
allowClientCredentials?: boolean;
|
|
102
|
+
}
|
|
103
|
+
interface VerifiedAccessToken {
|
|
104
|
+
/** uid do usuário final (ou `client:<id>` se `allowClientCredentials`). */
|
|
105
|
+
sub: string;
|
|
106
|
+
/** `client_id` que pediu o token (web, iOS ou Android). */
|
|
107
|
+
clientId: string;
|
|
108
|
+
/** `aud` do token (= `clientId` no Core). */
|
|
109
|
+
audience: string;
|
|
110
|
+
/** Escopos concedidos. */
|
|
111
|
+
scopes: string[];
|
|
112
|
+
/** Id único do token (útil pra log/auditoria; NÃO é segredo). */
|
|
113
|
+
jti: string;
|
|
114
|
+
/** Emitido em (epoch s). */
|
|
115
|
+
issuedAt: number;
|
|
116
|
+
/** Expira em (epoch s). */
|
|
117
|
+
expiresAt: number;
|
|
118
|
+
/** `true` se é token de máquina (`client_credentials`). */
|
|
119
|
+
isClientCredentials: boolean;
|
|
120
|
+
/** Claims crus verificados. */
|
|
121
|
+
claims: JWTPayload;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Valida um access_token OIDC emitido pelo auth.neetru.com.
|
|
125
|
+
*
|
|
126
|
+
* Checa: assinatura RS256 contra o JWKS (cacheado) · `iss` · `exp` (com
|
|
127
|
+
* tolerância curta) · `aud ∈ audience` · formato de access token (`jti`,
|
|
128
|
+
* `scope`, `client_id` === `aud`) · usuário (não máquina) · `requiredScopes`.
|
|
129
|
+
*
|
|
130
|
+
* @throws {NeetruError} `invalid_config` (sem audience) · `token_expired` ·
|
|
131
|
+
* `token_invalid_signature` · `token_invalid_audience` · `token_invalid_issuer` ·
|
|
132
|
+
* `token_invalid` (não é access token / malformado / máquina) ·
|
|
133
|
+
* `insufficient_scope` (status 403).
|
|
134
|
+
*/
|
|
135
|
+
declare function verifyAccessToken(token: string, options: VerifyAccessTokenOptions): Promise<VerifiedAccessToken>;
|
|
136
|
+
/** Qualquer coisa com headers: `Request` (fetch/Next), `Headers`, ou objeto Node (`req.headers`). */
|
|
137
|
+
type HeadersSource = Headers | {
|
|
138
|
+
headers: Headers | Record<string, string | string[] | undefined>;
|
|
139
|
+
} | Record<string, string | string[] | undefined>;
|
|
140
|
+
/**
|
|
141
|
+
* Extrai o token de `Authorization: Bearer <token>`. `null` se ausente ou se o
|
|
142
|
+
* esquema não for Bearer.
|
|
143
|
+
*/
|
|
144
|
+
declare function readBearerToken(source: HeadersSource): string | null;
|
|
145
|
+
/** Lê um cookie pelo nome do header `Cookie`. */
|
|
146
|
+
declare function readCookie(source: HeadersSource, name: string): string | null;
|
|
147
|
+
interface AuthenticateProductRequestOptions<TSession> extends VerifyAccessTokenOptions {
|
|
148
|
+
/**
|
|
149
|
+
* Sessão por cookie do site (o caminho que o produto JÁ tem). Se a request
|
|
150
|
+
* não trouxer `Authorization: Bearer`, o helper lê o cookie `name` e chama
|
|
151
|
+
* `verify(valor)` — a validação do cookie continua sendo do produto.
|
|
152
|
+
*/
|
|
153
|
+
cookie?: {
|
|
154
|
+
name: string;
|
|
155
|
+
verify: (value: string) => Promise<TSession | null> | TSession | null;
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
type ProductRequestAuth<TSession> = {
|
|
159
|
+
kind: 'access_token';
|
|
160
|
+
token: VerifiedAccessToken;
|
|
161
|
+
} | {
|
|
162
|
+
kind: 'cookie';
|
|
163
|
+
session: TSession;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Autentica uma request na API do produto aceitando `Authorization: Bearer
|
|
167
|
+
* <access_token>` (app/SPA) **ou** o cookie de sessão do site.
|
|
168
|
+
*
|
|
169
|
+
* - Bearer presente → valida com `verifyAccessToken`. Inválido → LANÇA (não cai
|
|
170
|
+
* pro cookie: credencial ruim explícita nunca é "rebaixada" em silêncio).
|
|
171
|
+
* - Sem Bearer e com `cookie` configurado → `cookie.verify(valor)`.
|
|
172
|
+
* - Nada válido → `null` (o produto responde 401).
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```ts
|
|
176
|
+
* // app/api/v1/vendas/route.ts (Next.js, servidor)
|
|
177
|
+
* import { authenticateProductRequest, accessTokenErrorToHttp } from '@neetru/sdk';
|
|
178
|
+
* export async function GET(req: Request) {
|
|
179
|
+
* try {
|
|
180
|
+
* const auth = await authenticateProductRequest(req, {
|
|
181
|
+
* audience: [process.env.NEETRU_OIDC_CLIENT_ID_WEB!, process.env.NEETRU_OIDC_CLIENT_ID_IOS!,
|
|
182
|
+
* process.env.NEETRU_OIDC_CLIENT_ID_ANDROID!],
|
|
183
|
+
* requiredScopes: ['openid'],
|
|
184
|
+
* cookie: { name: 'session', verify: verifySessionCookie },
|
|
185
|
+
* });
|
|
186
|
+
* if (!auth) return Response.json({ error: 'unauthorized' }, { status: 401 });
|
|
187
|
+
* // ... usa o SDK com a chave (servidor) em nome de auth.token.sub
|
|
188
|
+
* } catch (err) {
|
|
189
|
+
* const r = accessTokenErrorToHttp(err);
|
|
190
|
+
* return Response.json(r.body, { status: r.status, headers: r.headers });
|
|
191
|
+
* }
|
|
192
|
+
* }
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
declare function authenticateProductRequest<TSession = unknown>(request: HeadersSource, options: AuthenticateProductRequestOptions<TSession>): Promise<ProductRequestAuth<TSession> | null>;
|
|
196
|
+
/**
|
|
197
|
+
* Converte um erro de `verifyAccessToken`/`authenticateProductRequest` na
|
|
198
|
+
* resposta HTTP padrão (RFC 6750 §3): 401 `invalid_token` ou 403
|
|
199
|
+
* `insufficient_scope`, com `WWW-Authenticate`. Erros que não são de token
|
|
200
|
+
* viram 500 genérico (sem vazar detalhe).
|
|
201
|
+
*/
|
|
202
|
+
declare function accessTokenErrorToHttp(err: unknown): {
|
|
203
|
+
status: number;
|
|
204
|
+
headers: Record<string, string>;
|
|
205
|
+
body: {
|
|
206
|
+
error: string;
|
|
207
|
+
error_description: string;
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
type NonServerRuntime = 'browser' | 'react-native';
|
|
212
|
+
/** Detecta se o código está rodando fora de um servidor. `null` = servidor. */
|
|
213
|
+
declare function detectNonServerRuntime(): NonServerRuntime | null;
|
|
214
|
+
|
|
41
215
|
/**
|
|
42
216
|
* @neetru/sdk — biblioteca runtime para consumir o ecossistema Neetru.
|
|
43
217
|
*
|
|
@@ -72,6 +246,6 @@ declare function checkCoreVersionCompat(coreVersion: string): void;
|
|
|
72
246
|
*/
|
|
73
247
|
|
|
74
248
|
/** Versão do SDK — exportada explicitamente pra detecção em runtime. */
|
|
75
|
-
declare const VERSION: "3.
|
|
249
|
+
declare const VERSION: "3.8.0";
|
|
76
250
|
|
|
77
|
-
export { VERSION, checkCoreVersionCompat };
|
|
251
|
+
export { type AuthenticateProductRequestOptions, type HeadersSource, NEETRU_OIDC_ISSUER, type NonServerRuntime, type ProductRequestAuth, VERSION, type VerifiedAccessToken, type VerifyAccessTokenOptions, accessTokenErrorToHttp, authenticateProductRequest, checkCoreVersionCompat, detectNonServerRuntime, readBearerToken, readCookie, verifyAccessToken };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { createNeetruClient, getServerNeetruClient } from './auth.js';
|
|
2
2
|
export { NeetruAuthRequiredError, NeetruError, NeetruErrorCode } from './errors.js';
|
|
3
|
-
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, l as AuthNamespace, m as AuthStateListener, C as CatalogListOptions, n as CatalogListResponse, p as CheckoutIntentInfo, q as CheckoutIntentStatus, r as CheckoutNamespace, s as CheckoutStartInput, t as CheckoutStartResult, u as CheckoutTenantType, v as CompleteSignInResult, y as CreateTicketInput, D as DEFAULT_BASE_URL, z as DbBatchOp, B as DbChangeType, E as DbCollectionRef, F as DbDoc, G as DbDocRef, H as DbGetResult, I as DbListResult, J as DbNamespace, K as DbQuery, L as DbSqlLease, M as DbWhereFilter, O as
|
|
3
|
+
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, l as AuthNamespace, m as AuthStateListener, C as CatalogListOptions, n as CatalogListResponse, p as CheckoutIntentInfo, q as CheckoutIntentStatus, r as CheckoutNamespace, s as CheckoutStartInput, t as CheckoutStartResult, u as CheckoutTenantType, v as CompleteSignInResult, y as CreateTicketInput, D as DEFAULT_BASE_URL, z as DbBatchOp, B as DbChangeType, E as DbCollectionRef, F as DbDoc, G as DbDocRef, H as DbGetResult, I as DbListResult, J as DbNamespace, K as DbQuery, L as DbSqlLease, M as DbWhereFilter, O as EndUserTokenProvider, P as EntitlementCheck, Q as FieldSentinel, R as IncrementSentinel, S as ListNotificationsOptions, T as MockCheckout, U as MockNotifications, V as MockWebhooks, W as NEETRU_SENTINEL_KEY, X as NeetruClient, Y as NeetruClientConfig, Z as NeetruDb, $ as NeetruDbEngine, a0 as NeetruDbError, a1 as NeetruDbErrorCode, a2 as NeetruDbOptions, a3 as NeetruDbTransport, a4 as NeetruEnv, a5 as NeetruSqlClient, a6 as NeetruUser, a7 as NotificationScopeOptions, a8 as NotificationsNamespace, a9 as Product, aa as ProductNotification, ab as ProductNotificationSeverity, ac as ProductPlan, ad as ProductStatus, af as RedirectCallbackResult, ag as RegisterWebhookInput, ah as ResolvedConfig, ai as SendNotificationInput, aj as ServerTimestampSentinel, ak as SignInOptions, am as SupportNamespace, an as SupportSeverity, ao as SupportStatus, ap as SupportTicket, as as TelemetryEventAck, at as TelemetryEventInput, ax as UsageEventInput, ay as UsageNamespace, az as UsageQuota, aA as VerifyTokenOptions, aB as VerifyWebhookRequestOptions, aC as VerifyWebhookRequestResult, aD as WebhookEndpoint, aE as WebhookEvent, aF as WebhookScopeOptions, aG as WebhookTestResult, aH as WebhooksNamespace, aI as WithFieldSentinels, aK as createAiNamespace, aL as createCheckoutNamespace, aM as createNeetruDb, aN as createNotificationsNamespace, aP as createWebhooksNamespace, aR as increment, aS as isFieldSentinel, aT as isIncrementSentinel, aU as isServerTimestampSentinel, aV as serverTimestamp, aW as verifyWebhookRequest, aX as verifyWebhookSignature } from './types-bVztFQTI.js';
|
|
4
4
|
export { DEV_FIXTURE_USER, MockAi, MockAuth, MockAuthOptions, MockDb, MockEntitlements, MockSupport, MockUsage } from './mocks.js';
|
|
5
|
+
import { JWTPayload } from 'jose';
|
|
5
6
|
import 'drizzle-orm/node-postgres';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -38,6 +39,179 @@ import 'drizzle-orm/node-postgres';
|
|
|
38
39
|
*/
|
|
39
40
|
declare function checkCoreVersionCompat(coreVersion: string): void;
|
|
40
41
|
|
|
42
|
+
/**
|
|
43
|
+
* 3.8.0 — `verifyAccessToken`: validação SERVER-SIDE do access_token OIDC do
|
|
44
|
+
* usuário final, para a API do PRODUTO aceitar `Authorization: Bearer
|
|
45
|
+
* <access_token>` (app React Native / SPA) além do cookie de sessão.
|
|
46
|
+
*
|
|
47
|
+
* ## Fluxo canônico (decisão do dono, 2026-10-03)
|
|
48
|
+
*
|
|
49
|
+
* app/site ──Bearer access_token──▶ API do produto ──SDK + nrt_ (servidor)──▶ Core
|
|
50
|
+
*
|
|
51
|
+
* O app nunca carrega a chave `nrt_`. Ele faz login no auth.neetru.com (PKCE,
|
|
52
|
+
* client OIDC público do app) e manda o access_token pra API do produto, que
|
|
53
|
+
* valida aqui — sem ir ao Core por request.
|
|
54
|
+
*
|
|
55
|
+
* ## Formato real do token (conferido no Core, `src/lib/oidc/tokens.ts`)
|
|
56
|
+
*
|
|
57
|
+
* header: `{ alg: 'RS256', kid, typ: 'JWT' }`
|
|
58
|
+
* claims: `iss` = `https://auth.neetru.com` · `sub` = uid do usuário (ou
|
|
59
|
+
* `client:<client_id>` em client_credentials) · `aud` = `client_id`
|
|
60
|
+
* (string) · `client_id` · `scope` (string separada por espaço) ·
|
|
61
|
+
* `iat` · `exp` (15 min) · `jti`.
|
|
62
|
+
* JWKS: `https://auth.neetru.com/api/v1/oauth/.well-known/jwks`.
|
|
63
|
+
*
|
|
64
|
+
* O id_token usa a MESMA chave, `iss` e `aud` — o que o distingue é NÃO ter
|
|
65
|
+
* `jti`/`scope`/`client_id`. Por isso exigimos os três: um id_token (que vai
|
|
66
|
+
* para terceiros como prova de login) não serve de credencial de API.
|
|
67
|
+
*
|
|
68
|
+
* ## Revogação
|
|
69
|
+
*
|
|
70
|
+
* A validação é local (assinatura + claims), sem consulta ao Core. Um access
|
|
71
|
+
* token revogado continua aceito até expirar — no máximo 15 min (TTL do Core).
|
|
72
|
+
* Para encerrar a sessão de verdade, o app revoga o refresh_token no logout
|
|
73
|
+
* (o `@neetru/sdk/mobile` faz isso no `signOut`). O `/introspect` do Core é só
|
|
74
|
+
* para clients confidenciais do mesmo `client_id`, então não serve a uma API
|
|
75
|
+
* que aceita tokens de vários clients (web + iOS + Android).
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
/** Issuer canônico do Core em produção. */
|
|
79
|
+
declare const NEETRU_OIDC_ISSUER = "https://auth.neetru.com";
|
|
80
|
+
interface VerifyAccessTokenOptions {
|
|
81
|
+
/**
|
|
82
|
+
* `client_id` OIDC aceitos como `aud` — tipicamente o client web + o do app
|
|
83
|
+
* iOS + o do app Android DO MESMO PRODUTO. Obrigatório e não-vazio: sem isso
|
|
84
|
+
* um token emitido para o client de OUTRO produto passaria.
|
|
85
|
+
*/
|
|
86
|
+
audience: string | readonly string[];
|
|
87
|
+
/** Escopos que o token TEM que ter (todos). Ex.: `['openid']`. Default: nenhum. */
|
|
88
|
+
requiredScopes?: readonly string[];
|
|
89
|
+
/** Issuer esperado. Default `https://auth.neetru.com`. Só mude para staging/emulador. */
|
|
90
|
+
issuer?: string;
|
|
91
|
+
/** URL do JWKS. Default `<issuer>/api/v1/oauth/.well-known/jwks`. */
|
|
92
|
+
jwksUrl?: string;
|
|
93
|
+
/** TTL da instância de JWKS cacheada. Default 1h. */
|
|
94
|
+
jwksCacheTtlMs?: number;
|
|
95
|
+
/** Tolerância de relógio para `exp`/`iat`/`nbf`, em segundos. Default 5, máx 60. */
|
|
96
|
+
clockToleranceSec?: number;
|
|
97
|
+
/**
|
|
98
|
+
* Aceitar token de máquina (`client_credentials`, `sub` = `client:<id>`).
|
|
99
|
+
* Default `false` — a API do produto quer um USUÁRIO.
|
|
100
|
+
*/
|
|
101
|
+
allowClientCredentials?: boolean;
|
|
102
|
+
}
|
|
103
|
+
interface VerifiedAccessToken {
|
|
104
|
+
/** uid do usuário final (ou `client:<id>` se `allowClientCredentials`). */
|
|
105
|
+
sub: string;
|
|
106
|
+
/** `client_id` que pediu o token (web, iOS ou Android). */
|
|
107
|
+
clientId: string;
|
|
108
|
+
/** `aud` do token (= `clientId` no Core). */
|
|
109
|
+
audience: string;
|
|
110
|
+
/** Escopos concedidos. */
|
|
111
|
+
scopes: string[];
|
|
112
|
+
/** Id único do token (útil pra log/auditoria; NÃO é segredo). */
|
|
113
|
+
jti: string;
|
|
114
|
+
/** Emitido em (epoch s). */
|
|
115
|
+
issuedAt: number;
|
|
116
|
+
/** Expira em (epoch s). */
|
|
117
|
+
expiresAt: number;
|
|
118
|
+
/** `true` se é token de máquina (`client_credentials`). */
|
|
119
|
+
isClientCredentials: boolean;
|
|
120
|
+
/** Claims crus verificados. */
|
|
121
|
+
claims: JWTPayload;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Valida um access_token OIDC emitido pelo auth.neetru.com.
|
|
125
|
+
*
|
|
126
|
+
* Checa: assinatura RS256 contra o JWKS (cacheado) · `iss` · `exp` (com
|
|
127
|
+
* tolerância curta) · `aud ∈ audience` · formato de access token (`jti`,
|
|
128
|
+
* `scope`, `client_id` === `aud`) · usuário (não máquina) · `requiredScopes`.
|
|
129
|
+
*
|
|
130
|
+
* @throws {NeetruError} `invalid_config` (sem audience) · `token_expired` ·
|
|
131
|
+
* `token_invalid_signature` · `token_invalid_audience` · `token_invalid_issuer` ·
|
|
132
|
+
* `token_invalid` (não é access token / malformado / máquina) ·
|
|
133
|
+
* `insufficient_scope` (status 403).
|
|
134
|
+
*/
|
|
135
|
+
declare function verifyAccessToken(token: string, options: VerifyAccessTokenOptions): Promise<VerifiedAccessToken>;
|
|
136
|
+
/** Qualquer coisa com headers: `Request` (fetch/Next), `Headers`, ou objeto Node (`req.headers`). */
|
|
137
|
+
type HeadersSource = Headers | {
|
|
138
|
+
headers: Headers | Record<string, string | string[] | undefined>;
|
|
139
|
+
} | Record<string, string | string[] | undefined>;
|
|
140
|
+
/**
|
|
141
|
+
* Extrai o token de `Authorization: Bearer <token>`. `null` se ausente ou se o
|
|
142
|
+
* esquema não for Bearer.
|
|
143
|
+
*/
|
|
144
|
+
declare function readBearerToken(source: HeadersSource): string | null;
|
|
145
|
+
/** Lê um cookie pelo nome do header `Cookie`. */
|
|
146
|
+
declare function readCookie(source: HeadersSource, name: string): string | null;
|
|
147
|
+
interface AuthenticateProductRequestOptions<TSession> extends VerifyAccessTokenOptions {
|
|
148
|
+
/**
|
|
149
|
+
* Sessão por cookie do site (o caminho que o produto JÁ tem). Se a request
|
|
150
|
+
* não trouxer `Authorization: Bearer`, o helper lê o cookie `name` e chama
|
|
151
|
+
* `verify(valor)` — a validação do cookie continua sendo do produto.
|
|
152
|
+
*/
|
|
153
|
+
cookie?: {
|
|
154
|
+
name: string;
|
|
155
|
+
verify: (value: string) => Promise<TSession | null> | TSession | null;
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
type ProductRequestAuth<TSession> = {
|
|
159
|
+
kind: 'access_token';
|
|
160
|
+
token: VerifiedAccessToken;
|
|
161
|
+
} | {
|
|
162
|
+
kind: 'cookie';
|
|
163
|
+
session: TSession;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Autentica uma request na API do produto aceitando `Authorization: Bearer
|
|
167
|
+
* <access_token>` (app/SPA) **ou** o cookie de sessão do site.
|
|
168
|
+
*
|
|
169
|
+
* - Bearer presente → valida com `verifyAccessToken`. Inválido → LANÇA (não cai
|
|
170
|
+
* pro cookie: credencial ruim explícita nunca é "rebaixada" em silêncio).
|
|
171
|
+
* - Sem Bearer e com `cookie` configurado → `cookie.verify(valor)`.
|
|
172
|
+
* - Nada válido → `null` (o produto responde 401).
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```ts
|
|
176
|
+
* // app/api/v1/vendas/route.ts (Next.js, servidor)
|
|
177
|
+
* import { authenticateProductRequest, accessTokenErrorToHttp } from '@neetru/sdk';
|
|
178
|
+
* export async function GET(req: Request) {
|
|
179
|
+
* try {
|
|
180
|
+
* const auth = await authenticateProductRequest(req, {
|
|
181
|
+
* audience: [process.env.NEETRU_OIDC_CLIENT_ID_WEB!, process.env.NEETRU_OIDC_CLIENT_ID_IOS!,
|
|
182
|
+
* process.env.NEETRU_OIDC_CLIENT_ID_ANDROID!],
|
|
183
|
+
* requiredScopes: ['openid'],
|
|
184
|
+
* cookie: { name: 'session', verify: verifySessionCookie },
|
|
185
|
+
* });
|
|
186
|
+
* if (!auth) return Response.json({ error: 'unauthorized' }, { status: 401 });
|
|
187
|
+
* // ... usa o SDK com a chave (servidor) em nome de auth.token.sub
|
|
188
|
+
* } catch (err) {
|
|
189
|
+
* const r = accessTokenErrorToHttp(err);
|
|
190
|
+
* return Response.json(r.body, { status: r.status, headers: r.headers });
|
|
191
|
+
* }
|
|
192
|
+
* }
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
declare function authenticateProductRequest<TSession = unknown>(request: HeadersSource, options: AuthenticateProductRequestOptions<TSession>): Promise<ProductRequestAuth<TSession> | null>;
|
|
196
|
+
/**
|
|
197
|
+
* Converte um erro de `verifyAccessToken`/`authenticateProductRequest` na
|
|
198
|
+
* resposta HTTP padrão (RFC 6750 §3): 401 `invalid_token` ou 403
|
|
199
|
+
* `insufficient_scope`, com `WWW-Authenticate`. Erros que não são de token
|
|
200
|
+
* viram 500 genérico (sem vazar detalhe).
|
|
201
|
+
*/
|
|
202
|
+
declare function accessTokenErrorToHttp(err: unknown): {
|
|
203
|
+
status: number;
|
|
204
|
+
headers: Record<string, string>;
|
|
205
|
+
body: {
|
|
206
|
+
error: string;
|
|
207
|
+
error_description: string;
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
type NonServerRuntime = 'browser' | 'react-native';
|
|
212
|
+
/** Detecta se o código está rodando fora de um servidor. `null` = servidor. */
|
|
213
|
+
declare function detectNonServerRuntime(): NonServerRuntime | null;
|
|
214
|
+
|
|
41
215
|
/**
|
|
42
216
|
* @neetru/sdk — biblioteca runtime para consumir o ecossistema Neetru.
|
|
43
217
|
*
|
|
@@ -72,6 +246,6 @@ declare function checkCoreVersionCompat(coreVersion: string): void;
|
|
|
72
246
|
*/
|
|
73
247
|
|
|
74
248
|
/** Versão do SDK — exportada explicitamente pra detecção em runtime. */
|
|
75
|
-
declare const VERSION: "3.
|
|
249
|
+
declare const VERSION: "3.8.0";
|
|
76
250
|
|
|
77
|
-
export { VERSION, checkCoreVersionCompat };
|
|
251
|
+
export { type AuthenticateProductRequestOptions, type HeadersSource, NEETRU_OIDC_ISSUER, type NonServerRuntime, type ProductRequestAuth, VERSION, type VerifiedAccessToken, type VerifyAccessTokenOptions, accessTokenErrorToHttp, authenticateProductRequest, checkCoreVersionCompat, detectNonServerRuntime, readBearerToken, readCookie, verifyAccessToken };
|