@neetru/sdk 2.1.0 → 2.2.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +94 -1
  2. package/dist/auth.cjs +156 -7
  3. package/dist/auth.cjs.map +1 -1
  4. package/dist/auth.d.cts +5 -3
  5. package/dist/auth.d.ts +5 -3
  6. package/dist/auth.mjs +156 -8
  7. package/dist/auth.mjs.map +1 -1
  8. package/dist/catalog.cjs.map +1 -1
  9. package/dist/catalog.d.cts +2 -2
  10. package/dist/catalog.d.ts +2 -2
  11. package/dist/catalog.mjs.map +1 -1
  12. package/dist/checkout.cjs.map +1 -1
  13. package/dist/checkout.d.cts +2 -2
  14. package/dist/checkout.d.ts +2 -2
  15. package/dist/checkout.mjs.map +1 -1
  16. package/dist/{collection-ref-BBvTTXoG.d.cts → collection-ref-DqAAhuhX.d.cts} +56 -7
  17. package/dist/{collection-ref-BBvTTXoG.d.ts → collection-ref-DqAAhuhX.d.ts} +56 -7
  18. package/dist/db-react.d.cts +1 -1
  19. package/dist/db-react.d.ts +1 -1
  20. package/dist/db.cjs +29 -7
  21. package/dist/db.cjs.map +1 -1
  22. package/dist/db.d.cts +2 -2
  23. package/dist/db.d.ts +2 -2
  24. package/dist/db.mjs +29 -7
  25. package/dist/db.mjs.map +1 -1
  26. package/dist/entitlements.cjs.map +1 -1
  27. package/dist/entitlements.d.cts +2 -2
  28. package/dist/entitlements.d.ts +2 -2
  29. package/dist/entitlements.mjs.map +1 -1
  30. package/dist/errors.cjs.map +1 -1
  31. package/dist/errors.d.cts +1 -1
  32. package/dist/errors.d.ts +1 -1
  33. package/dist/errors.mjs.map +1 -1
  34. package/dist/index.cjs +172 -21
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +3 -3
  37. package/dist/index.d.ts +3 -3
  38. package/dist/index.mjs +172 -21
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/mocks.cjs +75 -14
  41. package/dist/mocks.cjs.map +1 -1
  42. package/dist/mocks.d.cts +22 -2
  43. package/dist/mocks.d.ts +22 -2
  44. package/dist/mocks.mjs +75 -14
  45. package/dist/mocks.mjs.map +1 -1
  46. package/dist/notifications.cjs.map +1 -1
  47. package/dist/notifications.d.cts +2 -2
  48. package/dist/notifications.d.ts +2 -2
  49. package/dist/notifications.mjs.map +1 -1
  50. package/dist/react.d.cts +2 -2
  51. package/dist/react.d.ts +2 -2
  52. package/dist/support.cjs.map +1 -1
  53. package/dist/support.d.cts +2 -2
  54. package/dist/support.d.ts +2 -2
  55. package/dist/support.mjs.map +1 -1
  56. package/dist/telemetry.cjs.map +1 -1
  57. package/dist/telemetry.d.cts +2 -2
  58. package/dist/telemetry.d.ts +2 -2
  59. package/dist/telemetry.mjs.map +1 -1
  60. package/dist/{types-B1jylbMC.d.ts → types-CvTje138.d.ts} +46 -2
  61. package/dist/{types-Kmt4y1FQ.d.cts → types-DlDxttiG.d.cts} +46 -2
  62. package/dist/usage.cjs.map +1 -1
  63. package/dist/usage.d.cts +2 -2
  64. package/dist/usage.d.ts +2 -2
  65. package/dist/usage.mjs.map +1 -1
  66. package/dist/webhooks.cjs.map +1 -1
  67. package/dist/webhooks.d.cts +2 -2
  68. package/dist/webhooks.d.ts +2 -2
  69. package/dist/webhooks.mjs.map +1 -1
  70. package/package.json +3 -2
@@ -1,4 +1,4 @@
1
- import { c as DbCollectionRef$1, S as SyncState, U as Unsubscribe, C as ConflictRecord, R as RealtimeTransport } from './collection-ref-BBvTTXoG.js';
1
+ import { c as DbCollectionRef$1, S as SyncState, U as Unsubscribe, C as ConflictRecord, R as RealtimeTransport } from './collection-ref-DqAAhuhX.js';
2
2
  import { DbQuery, DeltaFrame } from '@neetru/realtime-protocol';
3
3
  import { NodePgDatabase } from 'drizzle-orm/node-postgres';
4
4
  import { NeetruError } from './errors.js';
@@ -1200,6 +1200,50 @@ interface AuthNamespace {
1200
1200
  * com user atual. Retorna função de unsubscribe.
1201
1201
  */
1202
1202
  onAuthStateChanged(listener: AuthStateListener): () => void;
1203
+ /**
1204
+ * Valida um id_token JWT emitido por `auth.neetru.com` server-side.
1205
+ *
1206
+ * Usa JWKS local cacheado (1h TTL, configurável via `jwksCacheTtlMs`).
1207
+ * Ideal para Next.js route handlers, middleware e qualquer ambiente Node/Edge
1208
+ * server-side onde verificação rápida sem round-trip é necessária.
1209
+ *
1210
+ * @param token - JWT id_token obtido do cookie ou header Authorization.
1211
+ * @param options - Opções opcionais de verificação.
1212
+ * @returns `NeetruUser` com claims validados.
1213
+ *
1214
+ * @throws {NeetruError} com `.code`:
1215
+ * - `token_expired` — token expirado (`exp` no passado)
1216
+ * - `token_invalid_signature` — assinatura não verificada pela JWKS
1217
+ * - `token_invalid_audience` — `aud` não bate com o `clientId` configurado
1218
+ * - `token_invalid_issuer` — `iss` não é `https://auth.neetru.com`
1219
+ *
1220
+ * @example
1221
+ * ```ts
1222
+ * // Next.js route handler
1223
+ * import { createNeetruClient } from '@neetru/sdk';
1224
+ * const client = createNeetruClient({ apiKey: 'nrt_...' });
1225
+ *
1226
+ * export async function POST(req: Request) {
1227
+ * const token = req.cookies.get('neetru-session')?.value;
1228
+ * try {
1229
+ * const user = await client.auth.verifyToken(token);
1230
+ * // user.uid, user.email, user.isStaff etc disponíveis
1231
+ * } catch (err) {
1232
+ * return new Response('Unauthorized', { status: 401 });
1233
+ * }
1234
+ * }
1235
+ * ```
1236
+ */
1237
+ verifyToken(token: string, options?: VerifyTokenOptions): Promise<NeetruUser>;
1238
+ }
1239
+ /** Opções para `auth.verifyToken()`. */
1240
+ interface VerifyTokenOptions {
1241
+ /**
1242
+ * TTL do cache de JWKS em milissegundos. Default: 3600000 (1h).
1243
+ * Valores menores aumentam latência (mais fetches); maiores aumentam
1244
+ * o tempo de janela após rotação de chaves.
1245
+ */
1246
+ jwksCacheTtlMs?: number;
1203
1247
  }
1204
1248
  interface UsageEventInput {
1205
1249
  /** Nome do evento, ex: `report_generated`, `api_call`. */
@@ -1361,4 +1405,4 @@ interface CatalogListOptions {
1361
1405
  includeDrafts?: boolean;
1362
1406
  }
1363
1407
 
1364
- export { type WebhookEvent as $, type AuthNamespace as A, type ProductPlan as B, type CatalogListOptions as C, DEFAULT_BASE_URL as D, type EntitlementCheck as E, type ProductStatus as F, type ResolvedConfig as G, type SignInOptions as H, type SqlOptions as I, type SupportNamespace as J, type SupportSeverity as K, type ListNotificationsOptions as L, MockCheckout as M, type NeetruClient as N, type SupportStatus as O, type Product as P, type SupportTicket as Q, type RegisterWebhookInput as R, type SendNotificationInput as S, type TelemetryEventAck as T, type TelemetryEventInput as U, type TelemetryLogAck as V, type TelemetryLogInput as W, type UsageEventInput as X, type UsageNamespace as Y, type UsageQuota as Z, type WebhookEndpoint as _, type AuthStateListener as a, type WebhookTestResult as a0, type WebhooksNamespace as a1, createCheckoutNamespace as a2, createNeetruDb as a3, createNotificationsNamespace as a4, createRestSyncTransport as a5, createWebhooksNamespace as a6, getWebSocketRealtimeClient as a7, verifyWebhookSignature as a8, type CatalogListResponse as b, type CheckoutIntentInfo as c, type CheckoutIntentStatus as d, type CheckoutNamespace as e, type CheckoutStartInput as f, type CheckoutStartResult as g, type CheckoutTenantType as h, type CreateTicketInput as i, type DbNamespace as j, type DbSqlLease as k, type DbWhereFilter as l, MockNotifications as m, MockWebhooks as n, type NeetruClientConfig as o, type NeetruDb as p, type NeetruDbEngine as q, NeetruDbError as r, type NeetruDbErrorCode as s, type NeetruDbOptions as t, type NeetruEnv as u, type NeetruSqlClient as v, type NeetruUser as w, type NotificationsNamespace as x, type ProductNotification as y, type ProductNotificationSeverity as z };
1408
+ export { type WebhookEndpoint as $, type AuthNamespace as A, type ProductPlan as B, type CatalogListOptions as C, DEFAULT_BASE_URL as D, type EntitlementCheck as E, type ProductStatus as F, type ResolvedConfig as G, type SignInOptions as H, type SqlOptions as I, type SupportNamespace as J, type SupportSeverity as K, type ListNotificationsOptions as L, MockCheckout as M, type NeetruClient as N, type SupportStatus as O, type Product as P, type SupportTicket as Q, type RegisterWebhookInput as R, type SendNotificationInput as S, type TelemetryEventAck as T, type TelemetryEventInput as U, type TelemetryLogAck as V, type TelemetryLogInput as W, type UsageEventInput as X, type UsageNamespace as Y, type UsageQuota as Z, type VerifyTokenOptions as _, type AuthStateListener as a, type WebhookEvent as a0, type WebhookTestResult as a1, type WebhooksNamespace as a2, createCheckoutNamespace as a3, createNeetruDb as a4, createNotificationsNamespace as a5, createRestSyncTransport as a6, createWebhooksNamespace as a7, getWebSocketRealtimeClient as a8, verifyWebhookSignature as a9, type CatalogListResponse as b, type CheckoutIntentInfo as c, type CheckoutIntentStatus as d, type CheckoutNamespace as e, type CheckoutStartInput as f, type CheckoutStartResult as g, type CheckoutTenantType as h, type CreateTicketInput as i, type DbNamespace as j, type DbSqlLease as k, type DbWhereFilter as l, MockNotifications as m, MockWebhooks as n, type NeetruClientConfig as o, type NeetruDb as p, type NeetruDbEngine as q, NeetruDbError as r, type NeetruDbErrorCode as s, type NeetruDbOptions as t, type NeetruEnv as u, type NeetruSqlClient as v, type NeetruUser as w, type NotificationsNamespace as x, type ProductNotification as y, type ProductNotificationSeverity as z };
@@ -1,4 +1,4 @@
1
- import { c as DbCollectionRef$1, S as SyncState, U as Unsubscribe, C as ConflictRecord, R as RealtimeTransport } from './collection-ref-BBvTTXoG.cjs';
1
+ import { c as DbCollectionRef$1, S as SyncState, U as Unsubscribe, C as ConflictRecord, R as RealtimeTransport } from './collection-ref-DqAAhuhX.cjs';
2
2
  import { DbQuery, DeltaFrame } from '@neetru/realtime-protocol';
3
3
  import { NodePgDatabase } from 'drizzle-orm/node-postgres';
4
4
  import { NeetruError } from './errors.cjs';
@@ -1200,6 +1200,50 @@ interface AuthNamespace {
1200
1200
  * com user atual. Retorna função de unsubscribe.
1201
1201
  */
1202
1202
  onAuthStateChanged(listener: AuthStateListener): () => void;
1203
+ /**
1204
+ * Valida um id_token JWT emitido por `auth.neetru.com` server-side.
1205
+ *
1206
+ * Usa JWKS local cacheado (1h TTL, configurável via `jwksCacheTtlMs`).
1207
+ * Ideal para Next.js route handlers, middleware e qualquer ambiente Node/Edge
1208
+ * server-side onde verificação rápida sem round-trip é necessária.
1209
+ *
1210
+ * @param token - JWT id_token obtido do cookie ou header Authorization.
1211
+ * @param options - Opções opcionais de verificação.
1212
+ * @returns `NeetruUser` com claims validados.
1213
+ *
1214
+ * @throws {NeetruError} com `.code`:
1215
+ * - `token_expired` — token expirado (`exp` no passado)
1216
+ * - `token_invalid_signature` — assinatura não verificada pela JWKS
1217
+ * - `token_invalid_audience` — `aud` não bate com o `clientId` configurado
1218
+ * - `token_invalid_issuer` — `iss` não é `https://auth.neetru.com`
1219
+ *
1220
+ * @example
1221
+ * ```ts
1222
+ * // Next.js route handler
1223
+ * import { createNeetruClient } from '@neetru/sdk';
1224
+ * const client = createNeetruClient({ apiKey: 'nrt_...' });
1225
+ *
1226
+ * export async function POST(req: Request) {
1227
+ * const token = req.cookies.get('neetru-session')?.value;
1228
+ * try {
1229
+ * const user = await client.auth.verifyToken(token);
1230
+ * // user.uid, user.email, user.isStaff etc disponíveis
1231
+ * } catch (err) {
1232
+ * return new Response('Unauthorized', { status: 401 });
1233
+ * }
1234
+ * }
1235
+ * ```
1236
+ */
1237
+ verifyToken(token: string, options?: VerifyTokenOptions): Promise<NeetruUser>;
1238
+ }
1239
+ /** Opções para `auth.verifyToken()`. */
1240
+ interface VerifyTokenOptions {
1241
+ /**
1242
+ * TTL do cache de JWKS em milissegundos. Default: 3600000 (1h).
1243
+ * Valores menores aumentam latência (mais fetches); maiores aumentam
1244
+ * o tempo de janela após rotação de chaves.
1245
+ */
1246
+ jwksCacheTtlMs?: number;
1203
1247
  }
1204
1248
  interface UsageEventInput {
1205
1249
  /** Nome do evento, ex: `report_generated`, `api_call`. */
@@ -1361,4 +1405,4 @@ interface CatalogListOptions {
1361
1405
  includeDrafts?: boolean;
1362
1406
  }
1363
1407
 
1364
- export { type WebhookEvent as $, type AuthNamespace as A, type ProductPlan as B, type CatalogListOptions as C, DEFAULT_BASE_URL as D, type EntitlementCheck as E, type ProductStatus as F, type ResolvedConfig as G, type SignInOptions as H, type SqlOptions as I, type SupportNamespace as J, type SupportSeverity as K, type ListNotificationsOptions as L, MockCheckout as M, type NeetruClient as N, type SupportStatus as O, type Product as P, type SupportTicket as Q, type RegisterWebhookInput as R, type SendNotificationInput as S, type TelemetryEventAck as T, type TelemetryEventInput as U, type TelemetryLogAck as V, type TelemetryLogInput as W, type UsageEventInput as X, type UsageNamespace as Y, type UsageQuota as Z, type WebhookEndpoint as _, type AuthStateListener as a, type WebhookTestResult as a0, type WebhooksNamespace as a1, createCheckoutNamespace as a2, createNeetruDb as a3, createNotificationsNamespace as a4, createRestSyncTransport as a5, createWebhooksNamespace as a6, getWebSocketRealtimeClient as a7, verifyWebhookSignature as a8, type CatalogListResponse as b, type CheckoutIntentInfo as c, type CheckoutIntentStatus as d, type CheckoutNamespace as e, type CheckoutStartInput as f, type CheckoutStartResult as g, type CheckoutTenantType as h, type CreateTicketInput as i, type DbNamespace as j, type DbSqlLease as k, type DbWhereFilter as l, MockNotifications as m, MockWebhooks as n, type NeetruClientConfig as o, type NeetruDb as p, type NeetruDbEngine as q, NeetruDbError as r, type NeetruDbErrorCode as s, type NeetruDbOptions as t, type NeetruEnv as u, type NeetruSqlClient as v, type NeetruUser as w, type NotificationsNamespace as x, type ProductNotification as y, type ProductNotificationSeverity as z };
1408
+ export { type WebhookEndpoint as $, type AuthNamespace as A, type ProductPlan as B, type CatalogListOptions as C, DEFAULT_BASE_URL as D, type EntitlementCheck as E, type ProductStatus as F, type ResolvedConfig as G, type SignInOptions as H, type SqlOptions as I, type SupportNamespace as J, type SupportSeverity as K, type ListNotificationsOptions as L, MockCheckout as M, type NeetruClient as N, type SupportStatus as O, type Product as P, type SupportTicket as Q, type RegisterWebhookInput as R, type SendNotificationInput as S, type TelemetryEventAck as T, type TelemetryEventInput as U, type TelemetryLogAck as V, type TelemetryLogInput as W, type UsageEventInput as X, type UsageNamespace as Y, type UsageQuota as Z, type VerifyTokenOptions as _, type AuthStateListener as a, type WebhookEvent as a0, type WebhookTestResult as a1, type WebhooksNamespace as a2, createCheckoutNamespace as a3, createNeetruDb as a4, createNotificationsNamespace as a5, createRestSyncTransport as a6, createWebhooksNamespace as a7, getWebSocketRealtimeClient as a8, verifyWebhookSignature as a9, type CatalogListResponse as b, type CheckoutIntentInfo as c, type CheckoutIntentStatus as d, type CheckoutNamespace as e, type CheckoutStartInput as f, type CheckoutStartResult as g, type CheckoutTenantType as h, type CreateTicketInput as i, type DbNamespace as j, type DbSqlLease as k, type DbWhereFilter as l, MockNotifications as m, MockWebhooks as n, type NeetruClientConfig as o, type NeetruDb as p, type NeetruDbEngine as q, NeetruDbError as r, type NeetruDbErrorCode as s, type NeetruDbOptions as t, type NeetruEnv as u, type NeetruSqlClient as v, type NeetruUser as w, type NotificationsNamespace as x, type ProductNotification as y, type ProductNotificationSeverity as z };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/usage.ts"],"names":["err","message"],"mappings":"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","file":"usage.cjs","sourcesContent":["/**\r\n * Erros tipados do SDK.\r\n *\r\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\r\n * por `.code` (string estável) sem parsing de message.\r\n */\r\n\r\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\r\nexport type NeetruErrorCode =\r\n | 'invalid_config'\r\n | 'missing_api_key'\r\n | 'unauthorized'\r\n | 'forbidden'\r\n | 'not_found'\r\n | 'rate_limited'\r\n | 'validation_failed'\r\n | 'network_error'\r\n | 'invalid_response'\r\n | 'server_error'\r\n | 'unknown';\r\n\r\n/**\r\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\r\n *\r\n * @example\r\n * ```ts\r\n * try { await client.catalog.list(); }\r\n * catch (e) {\r\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\r\n * }\r\n * ```\r\n */\r\nexport class NeetruError extends Error {\r\n public readonly code: NeetruErrorCode | string;\r\n public readonly status?: number;\r\n public readonly requestId?: string;\r\n\r\n constructor(\r\n code: NeetruErrorCode | string,\r\n message: string,\r\n status?: number,\r\n requestId?: string,\r\n ) {\r\n super(message);\r\n this.name = 'NeetruError';\r\n this.code = code;\r\n this.status = status;\r\n this.requestId = requestId;\r\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\r\n Object.setPrototypeOf(this, NeetruError.prototype);\r\n }\r\n}\r\n","/**\r\n * HTTP transport interno do SDK.\r\n *\r\n * Responsabilidades:\r\n * - Construir URL absoluta a partir de `baseUrl` + path\r\n * - Injetar Bearer token quando `requireAuth=true`\r\n * - Mapear status HTTP → `NeetruError` com `code` estável\r\n * - Parse defensivo de JSON (não lança em body vazio em 204)\r\n * - Retry/backoff exponencial em `rate_limited` (429), `server_error` (5xx)\r\n * e `network_error` (timeout/falha de rede). Honra `Retry-After` quando\r\n * presente. Default 2 retries (3 tentativas no total). Caller opta-out\r\n * com `retries: 0`.\r\n */\r\nimport { NeetruError, type NeetruErrorCode } from './errors';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n/** Opções da request HTTP. */\r\nexport interface HttpRequestOptions {\r\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\r\n /** Path relativo (ex: `/api/v1/cli/catalog`). Concatenado a `baseUrl`. */\r\n path: string;\r\n /** Query string params (chave → valor primitivo). Valores `undefined` ignorados. */\r\n query?: Record<string, string | number | boolean | undefined>;\r\n /** Body JSON-serializável. Ignorado em GET/DELETE. */\r\n body?: unknown;\r\n /**\r\n * Se true, injeta `Authorization: Bearer <apiKey>`. Lança `missing_api_key`\r\n * se config.apiKey ausente. Default false.\r\n */\r\n requireAuth?: boolean;\r\n /** Cabeçalhos extras. */\r\n headers?: Record<string, string>;\r\n /**\r\n * Número de retries em códigos transientes (`rate_limited`, `server_error`,\r\n * `network_error`). Default 2 (= 3 tentativas total). Caller passa `0` pra\r\n * desativar (útil em operações não-idempotentes específicas).\r\n */\r\n retries?: number;\r\n}\r\n\r\nconst DEFAULT_RETRIES = 2;\r\nconst RETRYABLE_CODES = new Set<NeetruErrorCode>([\r\n 'rate_limited',\r\n 'server_error',\r\n 'network_error',\r\n]);\r\n\r\n/** Backoff exponencial com jitter ±20%. attempt: 0=primeira, 1=primeiro retry, ... */\r\nfunction backoffMs(attempt: number): number {\r\n const base = 200 * Math.pow(4, attempt); // 200ms, 800ms, 3.2s, ...\r\n const jitter = base * 0.2 * (Math.random() * 2 - 1);\r\n return Math.max(50, Math.round(base + jitter));\r\n}\r\n\r\n/**\r\n * Honra `Retry-After` header (segundos ou HTTP-date). Retorna ms ou null se\r\n * inválido. RFC 9110 §10.2.3.\r\n */\r\nfunction parseRetryAfter(value: string | null): number | null {\r\n if (!value) return null;\r\n const secs = Number(value);\r\n if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1000);\r\n const dateMs = Date.parse(value);\r\n if (Number.isFinite(dateMs)) {\r\n const delta = dateMs - Date.now();\r\n if (delta > 0) return delta;\r\n }\r\n return null;\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\n/** Mapeamento status → code estável do NeetruError. */\r\nfunction statusToCode(status: number): NeetruErrorCode {\r\n if (status === 401) return 'unauthorized';\r\n if (status === 403) return 'forbidden';\r\n if (status === 404) return 'not_found';\r\n if (status === 422 || status === 400) return 'validation_failed';\r\n if (status === 429) return 'rate_limited';\r\n if (status >= 500) return 'server_error';\r\n return 'unknown';\r\n}\r\n\r\nfunction buildUrl(baseUrl: string, path: string, query?: HttpRequestOptions['query']): string {\r\n // Trim trailing slash em base e leading em path pra evitar `//`.\r\n const base = baseUrl.replace(/\\/+$/, '');\r\n const p = path.startsWith('/') ? path : `/${path}`;\r\n const url = new URL(`${base}${p}`);\r\n if (query) {\r\n for (const [k, v] of Object.entries(query)) {\r\n if (v === undefined) continue;\r\n url.searchParams.set(k, String(v));\r\n }\r\n }\r\n return url.toString();\r\n}\r\n\r\n/** Parse JSON defensivo — retorna `undefined` em body vazio. */\r\nasync function safeJson(res: Response): Promise<unknown> {\r\n const text = await res.text();\r\n if (!text) return undefined;\r\n try {\r\n return JSON.parse(text);\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Executa request HTTP. Em sucesso retorna body parseado; em erro lança\r\n * `NeetruError` com `code` derivado do status. Aplica retry/backoff\r\n * automático em códigos transientes (rate_limited/server_error/network_error)\r\n * conforme `opts.retries` (default 2 = 3 tentativas).\r\n */\r\nexport async function httpRequest<T>(\r\n config: ResolvedConfig,\r\n opts: HttpRequestOptions,\r\n): Promise<T> {\r\n const method = opts.method ?? 'GET';\r\n const url = buildUrl(config.baseUrl, opts.path, opts.query);\r\n const maxRetries = opts.retries ?? DEFAULT_RETRIES;\r\n\r\n const headers: Record<string, string> = {\r\n accept: 'application/json',\r\n ...opts.headers,\r\n };\r\n\r\n if (opts.requireAuth) {\r\n if (!config.apiKey) {\r\n throw new NeetruError(\r\n 'missing_api_key',\r\n 'This operation requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.',\r\n );\r\n }\r\n headers.authorization = `Bearer ${config.apiKey}`;\r\n }\r\n\r\n // Body só é serializado uma vez — reusado entre tentativas.\r\n const bodyString =\r\n opts.body !== undefined && method !== 'GET' && method !== 'DELETE'\r\n ? JSON.stringify(opts.body)\r\n : undefined;\r\n if (bodyString !== undefined) {\r\n headers['content-type'] = 'application/json';\r\n }\r\n\r\n let lastError: NeetruError | null = null;\r\n\r\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\r\n const init: RequestInit = { method, headers };\r\n if (bodyString !== undefined) init.body = bodyString;\r\n // BUG-020 fix (2026-05-13): timeout default 30s. AbortSignal.timeout\r\n // requer Node 18+ ou browsers recentes.\r\n init.signal = AbortSignal.timeout(30_000);\r\n\r\n let res: Response;\r\n try {\r\n res = await config.fetch(url, init);\r\n } catch (err) {\r\n const message =\r\n err instanceof DOMException && err.name === 'TimeoutError'\r\n ? 'Network error: timeout after 30s'\r\n : `Network error: ${err instanceof Error ? err.message : 'fetch failed'}`;\r\n lastError = new NeetruError('network_error', message);\r\n if (attempt < maxRetries) {\r\n await sleep(backoffMs(attempt));\r\n continue;\r\n }\r\n throw lastError;\r\n }\r\n\r\n const requestId =\r\n res.headers.get('x-request-id') ?? res.headers.get('x-correlation-id') ?? undefined;\r\n\r\n if (res.ok) {\r\n const parsed = await safeJson(res);\r\n return parsed as T;\r\n }\r\n\r\n const body = (await safeJson(res)) as\r\n | { error?: { code?: string; message?: string } | string }\r\n | undefined;\r\n let code: string = statusToCode(res.status);\r\n let message = `HTTP ${res.status}`;\r\n if (body && typeof body === 'object' && 'error' in body) {\r\n const errField = body.error;\r\n if (typeof errField === 'string') {\r\n message = errField;\r\n } else if (errField && typeof errField === 'object') {\r\n if (typeof errField.code === 'string') code = errField.code;\r\n if (typeof errField.message === 'string') message = errField.message;\r\n }\r\n }\r\n const err = new NeetruError(code, message, res.status, requestId);\r\n lastError = err;\r\n\r\n const isRetryable = RETRYABLE_CODES.has(code as NeetruErrorCode);\r\n if (isRetryable && attempt < maxRetries) {\r\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\r\n const delay = retryAfter ?? backoffMs(attempt);\r\n await sleep(delay);\r\n continue;\r\n }\r\n throw err;\r\n }\r\n\r\n // Unreachable — loop sempre retorna ou lança. Safety net.\r\n throw lastError ?? new NeetruError('unknown', 'unexpected httpRequest exit');\r\n}\r\n","/**\r\n * Usage namespace — track usage events e ler quotas (v0.2).\r\n *\r\n * Endpoints consumidos (em prod):\r\n * - `POST /sdk/v1/usage/record` — record event\r\n * - `GET /sdk/v1/usage/quota?metric=X` — ler quota da metric\r\n *\r\n * Comportamento por env:\r\n * - `dev` → MockUsage (in-memory, retornado pelo factory).\r\n * - `workspace`/`prod` → HTTP real.\r\n *\r\n * Diferença vs `telemetry`: telemetry é evento analítico (event sourcing pra\r\n * BigQuery). usage é meterado (consumo cobrado), com quota explícita por plano.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type { ResolvedConfig, UsageNamespace, UsageQuota } from './types';\r\n\r\ninterface RawUsageAck {\r\n ok?: boolean;\r\n recordId?: string;\r\n}\r\n\r\ninterface RawUsageQuota {\r\n metric?: string;\r\n used?: number;\r\n limit?: number;\r\n resetsAt?: string;\r\n plan?: string;\r\n}\r\n\r\nfunction toQuota(metric: string, raw: unknown): UsageQuota {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Quota response is not an object');\r\n }\r\n const r = raw as RawUsageQuota;\r\n if (typeof r.used !== 'number' || typeof r.limit !== 'number') {\r\n throw new NeetruError('invalid_response', 'Quota response missing used/limit numbers');\r\n }\r\n return {\r\n metric: typeof r.metric === 'string' ? r.metric : metric,\r\n used: r.used,\r\n limit: r.limit,\r\n resetsAt: typeof r.resetsAt === 'string' ? r.resetsAt : undefined,\r\n plan: typeof r.plan === 'string' ? r.plan : undefined,\r\n };\r\n}\r\n\r\nexport function createUsageNamespace(config: ResolvedConfig): UsageNamespace {\r\n return {\r\n /**\r\n * Persiste um evento de usage. Em dev (mocks ativos via factory) só loga.\r\n * Em workspace/prod chama POST /sdk/v1/usage/record.\r\n */\r\n async track(\r\n event: string,\r\n properties?: Record<string, string | number | boolean | null>,\r\n ): Promise<{ ok: true }> {\r\n if (!event || typeof event !== 'string') {\r\n throw new NeetruError('validation_failed', 'event name is required');\r\n }\r\n if (event.length > 128) {\r\n throw new NeetruError('validation_failed', 'event name max 128 chars');\r\n }\r\n\r\n const body: Record<string, unknown> = { event };\r\n if (properties && typeof properties === 'object') body.properties = properties;\r\n\r\n const raw = await httpRequest<RawUsageAck>(config, {\r\n method: 'POST',\r\n path: '/sdk/v1/usage/record',\r\n body,\r\n requireAuth: true,\r\n });\r\n\r\n if (!raw || raw.ok !== true) {\r\n throw new NeetruError('invalid_response', 'Usage record response missing ok');\r\n }\r\n return { ok: true };\r\n },\r\n\r\n /**\r\n * Lê quota atual de uma métrica. Cacheável (caller decide), SDK não cacheia.\r\n */\r\n async getQuota(metric: string): Promise<UsageQuota> {\r\n if (!metric || typeof metric !== 'string') {\r\n throw new NeetruError('validation_failed', 'metric is required');\r\n }\r\n const raw = await httpRequest<RawUsageQuota>(config, {\r\n method: 'GET',\r\n path: '/sdk/v1/usage/quota',\r\n query: { metric },\r\n requireAuth: true,\r\n });\r\n return toQuota(metric, raw);\r\n },\r\n\r\n /**\r\n * v0.3 — Reporta consumo metered. Hit no endpoint canônico Sprint 7.\r\n */\r\n async report(\r\n resource: string,\r\n qty: number = 1,\r\n options?: { productId?: string; tenantId?: string },\r\n ) {\r\n if (!resource || typeof resource !== 'string') {\r\n throw new NeetruError('validation_failed', 'resource is required');\r\n }\r\n if (!Number.isFinite(qty) || qty <= 0) {\r\n throw new NeetruError('validation_failed', 'qty must be positive integer');\r\n }\r\n const productId = options?.productId ?? config.productId;\r\n const tenantId = options?.tenantId ?? config.tenantId;\r\n if (!productId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productId required (pass to options or set on createNeetruClient)',\r\n );\r\n }\r\n if (!tenantId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'tenantId required (pass to options or set on createNeetruClient)',\r\n );\r\n }\r\n\r\n const raw = await httpRequest<{\r\n ok?: boolean;\r\n counterId?: string;\r\n value?: number;\r\n limit?: number;\r\n remaining?: number;\r\n status?: string;\r\n }>(config, {\r\n method: 'POST',\r\n path: '/sdk/v1/usage/record',\r\n body: { productId, tenantId, resource, qty: Math.floor(qty) },\r\n requireAuth: true,\r\n });\r\n if (!raw || raw.ok !== true) {\r\n throw new NeetruError('invalid_response', 'usage.report response missing ok');\r\n }\r\n return {\r\n ok: true as const,\r\n counterId: raw.counterId,\r\n value: raw.value,\r\n limit: raw.limit,\r\n remaining: raw.remaining,\r\n status: raw.status,\r\n };\r\n },\r\n\r\n /**\r\n * v0.3 — Verifica entitlement de um resource via GET /sdk/v1/entitlements.\r\n */\r\n async check(\r\n resource: string,\r\n options?: { productId?: string; tenantId?: string },\r\n ) {\r\n if (!resource || typeof resource !== 'string') {\r\n throw new NeetruError('validation_failed', 'resource is required');\r\n }\r\n const productId = options?.productId ?? config.productId;\r\n const tenantId = options?.tenantId ?? config.tenantId;\r\n if (!productId || !tenantId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productId and tenantId required',\r\n );\r\n }\r\n const raw = await httpRequest<{\r\n allowed?: boolean;\r\n reason?: string;\r\n remaining?: number;\r\n limit?: number;\r\n planId?: string | null;\r\n planFeatures?: string[];\r\n }>(config, {\r\n method: 'GET',\r\n path: '/sdk/v1/entitlements',\r\n query: { productId, tenantId, feature: resource },\r\n requireAuth: true,\r\n });\r\n if (!raw || typeof raw.allowed !== 'boolean') {\r\n throw new NeetruError('invalid_response', 'usage.check response missing allowed');\r\n }\r\n return {\r\n allowed: raw.allowed,\r\n reason: raw.reason,\r\n remaining: raw.remaining,\r\n limit: raw.limit,\r\n planId: raw.planId,\r\n planFeatures: raw.planFeatures,\r\n };\r\n },\r\n };\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/usage.ts"],"names":["err","message"],"mappings":"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","file":"usage.cjs","sourcesContent":["/**\r\n * Erros tipados do SDK.\r\n *\r\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\r\n * por `.code` (string estável) sem parsing de message.\r\n */\r\n\r\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\r\nexport type NeetruErrorCode =\r\n | 'invalid_config'\r\n | 'missing_api_key'\r\n | 'unauthorized'\r\n | 'forbidden'\r\n | 'not_found'\r\n | 'rate_limited'\r\n | 'validation_failed'\r\n | 'network_error'\r\n | 'invalid_response'\r\n | 'server_error'\r\n | 'token_expired'\r\n | 'token_invalid_signature'\r\n | 'token_invalid_audience'\r\n | 'token_invalid_issuer'\r\n | 'unknown';\r\n\r\n/**\r\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\r\n *\r\n * @example\r\n * ```ts\r\n * try { await client.catalog.list(); }\r\n * catch (e) {\r\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\r\n * }\r\n * ```\r\n */\r\nexport class NeetruError extends Error {\r\n public readonly code: NeetruErrorCode | string;\r\n public readonly status?: number;\r\n public readonly requestId?: string;\r\n\r\n constructor(\r\n code: NeetruErrorCode | string,\r\n message: string,\r\n status?: number,\r\n requestId?: string,\r\n ) {\r\n super(message);\r\n this.name = 'NeetruError';\r\n this.code = code;\r\n this.status = status;\r\n this.requestId = requestId;\r\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\r\n Object.setPrototypeOf(this, NeetruError.prototype);\r\n }\r\n}\r\n","/**\r\n * HTTP transport interno do SDK.\r\n *\r\n * Responsabilidades:\r\n * - Construir URL absoluta a partir de `baseUrl` + path\r\n * - Injetar Bearer token quando `requireAuth=true`\r\n * - Mapear status HTTP → `NeetruError` com `code` estável\r\n * - Parse defensivo de JSON (não lança em body vazio em 204)\r\n * - Retry/backoff exponencial em `rate_limited` (429), `server_error` (5xx)\r\n * e `network_error` (timeout/falha de rede). Honra `Retry-After` quando\r\n * presente. Default 2 retries (3 tentativas no total). Caller opta-out\r\n * com `retries: 0`.\r\n */\r\nimport { NeetruError, type NeetruErrorCode } from './errors';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n/** Opções da request HTTP. */\r\nexport interface HttpRequestOptions {\r\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\r\n /** Path relativo (ex: `/api/v1/cli/catalog`). Concatenado a `baseUrl`. */\r\n path: string;\r\n /** Query string params (chave → valor primitivo). Valores `undefined` ignorados. */\r\n query?: Record<string, string | number | boolean | undefined>;\r\n /** Body JSON-serializável. Ignorado em GET/DELETE. */\r\n body?: unknown;\r\n /**\r\n * Se true, injeta `Authorization: Bearer <apiKey>`. Lança `missing_api_key`\r\n * se config.apiKey ausente. Default false.\r\n */\r\n requireAuth?: boolean;\r\n /** Cabeçalhos extras. */\r\n headers?: Record<string, string>;\r\n /**\r\n * Número de retries em códigos transientes (`rate_limited`, `server_error`,\r\n * `network_error`). Default 2 (= 3 tentativas total). Caller passa `0` pra\r\n * desativar (útil em operações não-idempotentes específicas).\r\n */\r\n retries?: number;\r\n}\r\n\r\nconst DEFAULT_RETRIES = 2;\r\nconst RETRYABLE_CODES = new Set<NeetruErrorCode>([\r\n 'rate_limited',\r\n 'server_error',\r\n 'network_error',\r\n]);\r\n\r\n/** Backoff exponencial com jitter ±20%. attempt: 0=primeira, 1=primeiro retry, ... */\r\nfunction backoffMs(attempt: number): number {\r\n const base = 200 * Math.pow(4, attempt); // 200ms, 800ms, 3.2s, ...\r\n const jitter = base * 0.2 * (Math.random() * 2 - 1);\r\n return Math.max(50, Math.round(base + jitter));\r\n}\r\n\r\n/**\r\n * Honra `Retry-After` header (segundos ou HTTP-date). Retorna ms ou null se\r\n * inválido. RFC 9110 §10.2.3.\r\n */\r\nfunction parseRetryAfter(value: string | null): number | null {\r\n if (!value) return null;\r\n const secs = Number(value);\r\n if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1000);\r\n const dateMs = Date.parse(value);\r\n if (Number.isFinite(dateMs)) {\r\n const delta = dateMs - Date.now();\r\n if (delta > 0) return delta;\r\n }\r\n return null;\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\n/** Mapeamento status → code estável do NeetruError. */\r\nfunction statusToCode(status: number): NeetruErrorCode {\r\n if (status === 401) return 'unauthorized';\r\n if (status === 403) return 'forbidden';\r\n if (status === 404) return 'not_found';\r\n if (status === 422 || status === 400) return 'validation_failed';\r\n if (status === 429) return 'rate_limited';\r\n if (status >= 500) return 'server_error';\r\n return 'unknown';\r\n}\r\n\r\nfunction buildUrl(baseUrl: string, path: string, query?: HttpRequestOptions['query']): string {\r\n // Trim trailing slash em base e leading em path pra evitar `//`.\r\n const base = baseUrl.replace(/\\/+$/, '');\r\n const p = path.startsWith('/') ? path : `/${path}`;\r\n const url = new URL(`${base}${p}`);\r\n if (query) {\r\n for (const [k, v] of Object.entries(query)) {\r\n if (v === undefined) continue;\r\n url.searchParams.set(k, String(v));\r\n }\r\n }\r\n return url.toString();\r\n}\r\n\r\n/** Parse JSON defensivo — retorna `undefined` em body vazio. */\r\nasync function safeJson(res: Response): Promise<unknown> {\r\n const text = await res.text();\r\n if (!text) return undefined;\r\n try {\r\n return JSON.parse(text);\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Executa request HTTP. Em sucesso retorna body parseado; em erro lança\r\n * `NeetruError` com `code` derivado do status. Aplica retry/backoff\r\n * automático em códigos transientes (rate_limited/server_error/network_error)\r\n * conforme `opts.retries` (default 2 = 3 tentativas).\r\n */\r\nexport async function httpRequest<T>(\r\n config: ResolvedConfig,\r\n opts: HttpRequestOptions,\r\n): Promise<T> {\r\n const method = opts.method ?? 'GET';\r\n const url = buildUrl(config.baseUrl, opts.path, opts.query);\r\n const maxRetries = opts.retries ?? DEFAULT_RETRIES;\r\n\r\n const headers: Record<string, string> = {\r\n accept: 'application/json',\r\n ...opts.headers,\r\n };\r\n\r\n if (opts.requireAuth) {\r\n if (!config.apiKey) {\r\n throw new NeetruError(\r\n 'missing_api_key',\r\n 'This operation requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.',\r\n );\r\n }\r\n headers.authorization = `Bearer ${config.apiKey}`;\r\n }\r\n\r\n // Body só é serializado uma vez — reusado entre tentativas.\r\n const bodyString =\r\n opts.body !== undefined && method !== 'GET' && method !== 'DELETE'\r\n ? JSON.stringify(opts.body)\r\n : undefined;\r\n if (bodyString !== undefined) {\r\n headers['content-type'] = 'application/json';\r\n }\r\n\r\n let lastError: NeetruError | null = null;\r\n\r\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\r\n const init: RequestInit = { method, headers };\r\n if (bodyString !== undefined) init.body = bodyString;\r\n // BUG-020 fix (2026-05-13): timeout default 30s. AbortSignal.timeout\r\n // requer Node 18+ ou browsers recentes.\r\n init.signal = AbortSignal.timeout(30_000);\r\n\r\n let res: Response;\r\n try {\r\n res = await config.fetch(url, init);\r\n } catch (err) {\r\n const message =\r\n err instanceof DOMException && err.name === 'TimeoutError'\r\n ? 'Network error: timeout after 30s'\r\n : `Network error: ${err instanceof Error ? err.message : 'fetch failed'}`;\r\n lastError = new NeetruError('network_error', message);\r\n if (attempt < maxRetries) {\r\n await sleep(backoffMs(attempt));\r\n continue;\r\n }\r\n throw lastError;\r\n }\r\n\r\n const requestId =\r\n res.headers.get('x-request-id') ?? res.headers.get('x-correlation-id') ?? undefined;\r\n\r\n if (res.ok) {\r\n const parsed = await safeJson(res);\r\n return parsed as T;\r\n }\r\n\r\n const body = (await safeJson(res)) as\r\n | { error?: { code?: string; message?: string } | string }\r\n | undefined;\r\n let code: string = statusToCode(res.status);\r\n let message = `HTTP ${res.status}`;\r\n if (body && typeof body === 'object' && 'error' in body) {\r\n const errField = body.error;\r\n if (typeof errField === 'string') {\r\n message = errField;\r\n } else if (errField && typeof errField === 'object') {\r\n if (typeof errField.code === 'string') code = errField.code;\r\n if (typeof errField.message === 'string') message = errField.message;\r\n }\r\n }\r\n const err = new NeetruError(code, message, res.status, requestId);\r\n lastError = err;\r\n\r\n const isRetryable = RETRYABLE_CODES.has(code as NeetruErrorCode);\r\n if (isRetryable && attempt < maxRetries) {\r\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\r\n const delay = retryAfter ?? backoffMs(attempt);\r\n await sleep(delay);\r\n continue;\r\n }\r\n throw err;\r\n }\r\n\r\n // Unreachable — loop sempre retorna ou lança. Safety net.\r\n throw lastError ?? new NeetruError('unknown', 'unexpected httpRequest exit');\r\n}\r\n","/**\r\n * Usage namespace — track usage events e ler quotas (v0.2).\r\n *\r\n * Endpoints consumidos (em prod):\r\n * - `POST /sdk/v1/usage/record` — record event\r\n * - `GET /sdk/v1/usage/quota?metric=X` — ler quota da metric\r\n *\r\n * Comportamento por env:\r\n * - `dev` → MockUsage (in-memory, retornado pelo factory).\r\n * - `workspace`/`prod` → HTTP real.\r\n *\r\n * Diferença vs `telemetry`: telemetry é evento analítico (event sourcing pra\r\n * BigQuery). usage é meterado (consumo cobrado), com quota explícita por plano.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type { ResolvedConfig, UsageNamespace, UsageQuota } from './types';\r\n\r\ninterface RawUsageAck {\r\n ok?: boolean;\r\n recordId?: string;\r\n}\r\n\r\ninterface RawUsageQuota {\r\n metric?: string;\r\n used?: number;\r\n limit?: number;\r\n resetsAt?: string;\r\n plan?: string;\r\n}\r\n\r\nfunction toQuota(metric: string, raw: unknown): UsageQuota {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Quota response is not an object');\r\n }\r\n const r = raw as RawUsageQuota;\r\n if (typeof r.used !== 'number' || typeof r.limit !== 'number') {\r\n throw new NeetruError('invalid_response', 'Quota response missing used/limit numbers');\r\n }\r\n return {\r\n metric: typeof r.metric === 'string' ? r.metric : metric,\r\n used: r.used,\r\n limit: r.limit,\r\n resetsAt: typeof r.resetsAt === 'string' ? r.resetsAt : undefined,\r\n plan: typeof r.plan === 'string' ? r.plan : undefined,\r\n };\r\n}\r\n\r\nexport function createUsageNamespace(config: ResolvedConfig): UsageNamespace {\r\n return {\r\n /**\r\n * Persiste um evento de usage. Em dev (mocks ativos via factory) só loga.\r\n * Em workspace/prod chama POST /sdk/v1/usage/record.\r\n */\r\n async track(\r\n event: string,\r\n properties?: Record<string, string | number | boolean | null>,\r\n ): Promise<{ ok: true }> {\r\n if (!event || typeof event !== 'string') {\r\n throw new NeetruError('validation_failed', 'event name is required');\r\n }\r\n if (event.length > 128) {\r\n throw new NeetruError('validation_failed', 'event name max 128 chars');\r\n }\r\n\r\n const body: Record<string, unknown> = { event };\r\n if (properties && typeof properties === 'object') body.properties = properties;\r\n\r\n const raw = await httpRequest<RawUsageAck>(config, {\r\n method: 'POST',\r\n path: '/sdk/v1/usage/record',\r\n body,\r\n requireAuth: true,\r\n });\r\n\r\n if (!raw || raw.ok !== true) {\r\n throw new NeetruError('invalid_response', 'Usage record response missing ok');\r\n }\r\n return { ok: true };\r\n },\r\n\r\n /**\r\n * Lê quota atual de uma métrica. Cacheável (caller decide), SDK não cacheia.\r\n */\r\n async getQuota(metric: string): Promise<UsageQuota> {\r\n if (!metric || typeof metric !== 'string') {\r\n throw new NeetruError('validation_failed', 'metric is required');\r\n }\r\n const raw = await httpRequest<RawUsageQuota>(config, {\r\n method: 'GET',\r\n path: '/sdk/v1/usage/quota',\r\n query: { metric },\r\n requireAuth: true,\r\n });\r\n return toQuota(metric, raw);\r\n },\r\n\r\n /**\r\n * v0.3 — Reporta consumo metered. Hit no endpoint canônico Sprint 7.\r\n */\r\n async report(\r\n resource: string,\r\n qty: number = 1,\r\n options?: { productId?: string; tenantId?: string },\r\n ) {\r\n if (!resource || typeof resource !== 'string') {\r\n throw new NeetruError('validation_failed', 'resource is required');\r\n }\r\n if (!Number.isFinite(qty) || qty <= 0) {\r\n throw new NeetruError('validation_failed', 'qty must be positive integer');\r\n }\r\n const productId = options?.productId ?? config.productId;\r\n const tenantId = options?.tenantId ?? config.tenantId;\r\n if (!productId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productId required (pass to options or set on createNeetruClient)',\r\n );\r\n }\r\n if (!tenantId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'tenantId required (pass to options or set on createNeetruClient)',\r\n );\r\n }\r\n\r\n const raw = await httpRequest<{\r\n ok?: boolean;\r\n counterId?: string;\r\n value?: number;\r\n limit?: number;\r\n remaining?: number;\r\n status?: string;\r\n }>(config, {\r\n method: 'POST',\r\n path: '/sdk/v1/usage/record',\r\n body: { productId, tenantId, resource, qty: Math.floor(qty) },\r\n requireAuth: true,\r\n });\r\n if (!raw || raw.ok !== true) {\r\n throw new NeetruError('invalid_response', 'usage.report response missing ok');\r\n }\r\n return {\r\n ok: true as const,\r\n counterId: raw.counterId,\r\n value: raw.value,\r\n limit: raw.limit,\r\n remaining: raw.remaining,\r\n status: raw.status,\r\n };\r\n },\r\n\r\n /**\r\n * v0.3 — Verifica entitlement de um resource via GET /sdk/v1/entitlements.\r\n */\r\n async check(\r\n resource: string,\r\n options?: { productId?: string; tenantId?: string },\r\n ) {\r\n if (!resource || typeof resource !== 'string') {\r\n throw new NeetruError('validation_failed', 'resource is required');\r\n }\r\n const productId = options?.productId ?? config.productId;\r\n const tenantId = options?.tenantId ?? config.tenantId;\r\n if (!productId || !tenantId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productId and tenantId required',\r\n );\r\n }\r\n const raw = await httpRequest<{\r\n allowed?: boolean;\r\n reason?: string;\r\n remaining?: number;\r\n limit?: number;\r\n planId?: string | null;\r\n planFeatures?: string[];\r\n }>(config, {\r\n method: 'GET',\r\n path: '/sdk/v1/entitlements',\r\n query: { productId, tenantId, feature: resource },\r\n requireAuth: true,\r\n });\r\n if (!raw || typeof raw.allowed !== 'boolean') {\r\n throw new NeetruError('invalid_response', 'usage.check response missing allowed');\r\n }\r\n return {\r\n allowed: raw.allowed,\r\n reason: raw.reason,\r\n remaining: raw.remaining,\r\n limit: raw.limit,\r\n planId: raw.planId,\r\n planFeatures: raw.planFeatures,\r\n };\r\n },\r\n };\r\n}\r\n"]}
package/dist/usage.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { G as ResolvedConfig, Y as UsageNamespace } from './types-Kmt4y1FQ.cjs';
2
- import './collection-ref-BBvTTXoG.cjs';
1
+ import { G as ResolvedConfig, Y as UsageNamespace } from './types-DlDxttiG.cjs';
2
+ import './collection-ref-DqAAhuhX.cjs';
3
3
  import '@neetru/realtime-protocol';
4
4
  import 'drizzle-orm/node-postgres';
5
5
  import './errors.cjs';
package/dist/usage.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { G as ResolvedConfig, Y as UsageNamespace } from './types-B1jylbMC.js';
2
- import './collection-ref-BBvTTXoG.js';
1
+ import { G as ResolvedConfig, Y as UsageNamespace } from './types-CvTje138.js';
2
+ import './collection-ref-DqAAhuhX.js';
3
3
  import '@neetru/realtime-protocol';
4
4
  import 'drizzle-orm/node-postgres';
5
5
  import './errors.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/usage.ts"],"names":["err","message"],"mappings":"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","file":"usage.mjs","sourcesContent":["/**\r\n * Erros tipados do SDK.\r\n *\r\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\r\n * por `.code` (string estável) sem parsing de message.\r\n */\r\n\r\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\r\nexport type NeetruErrorCode =\r\n | 'invalid_config'\r\n | 'missing_api_key'\r\n | 'unauthorized'\r\n | 'forbidden'\r\n | 'not_found'\r\n | 'rate_limited'\r\n | 'validation_failed'\r\n | 'network_error'\r\n | 'invalid_response'\r\n | 'server_error'\r\n | 'unknown';\r\n\r\n/**\r\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\r\n *\r\n * @example\r\n * ```ts\r\n * try { await client.catalog.list(); }\r\n * catch (e) {\r\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\r\n * }\r\n * ```\r\n */\r\nexport class NeetruError extends Error {\r\n public readonly code: NeetruErrorCode | string;\r\n public readonly status?: number;\r\n public readonly requestId?: string;\r\n\r\n constructor(\r\n code: NeetruErrorCode | string,\r\n message: string,\r\n status?: number,\r\n requestId?: string,\r\n ) {\r\n super(message);\r\n this.name = 'NeetruError';\r\n this.code = code;\r\n this.status = status;\r\n this.requestId = requestId;\r\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\r\n Object.setPrototypeOf(this, NeetruError.prototype);\r\n }\r\n}\r\n","/**\r\n * HTTP transport interno do SDK.\r\n *\r\n * Responsabilidades:\r\n * - Construir URL absoluta a partir de `baseUrl` + path\r\n * - Injetar Bearer token quando `requireAuth=true`\r\n * - Mapear status HTTP → `NeetruError` com `code` estável\r\n * - Parse defensivo de JSON (não lança em body vazio em 204)\r\n * - Retry/backoff exponencial em `rate_limited` (429), `server_error` (5xx)\r\n * e `network_error` (timeout/falha de rede). Honra `Retry-After` quando\r\n * presente. Default 2 retries (3 tentativas no total). Caller opta-out\r\n * com `retries: 0`.\r\n */\r\nimport { NeetruError, type NeetruErrorCode } from './errors';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n/** Opções da request HTTP. */\r\nexport interface HttpRequestOptions {\r\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\r\n /** Path relativo (ex: `/api/v1/cli/catalog`). Concatenado a `baseUrl`. */\r\n path: string;\r\n /** Query string params (chave → valor primitivo). Valores `undefined` ignorados. */\r\n query?: Record<string, string | number | boolean | undefined>;\r\n /** Body JSON-serializável. Ignorado em GET/DELETE. */\r\n body?: unknown;\r\n /**\r\n * Se true, injeta `Authorization: Bearer <apiKey>`. Lança `missing_api_key`\r\n * se config.apiKey ausente. Default false.\r\n */\r\n requireAuth?: boolean;\r\n /** Cabeçalhos extras. */\r\n headers?: Record<string, string>;\r\n /**\r\n * Número de retries em códigos transientes (`rate_limited`, `server_error`,\r\n * `network_error`). Default 2 (= 3 tentativas total). Caller passa `0` pra\r\n * desativar (útil em operações não-idempotentes específicas).\r\n */\r\n retries?: number;\r\n}\r\n\r\nconst DEFAULT_RETRIES = 2;\r\nconst RETRYABLE_CODES = new Set<NeetruErrorCode>([\r\n 'rate_limited',\r\n 'server_error',\r\n 'network_error',\r\n]);\r\n\r\n/** Backoff exponencial com jitter ±20%. attempt: 0=primeira, 1=primeiro retry, ... */\r\nfunction backoffMs(attempt: number): number {\r\n const base = 200 * Math.pow(4, attempt); // 200ms, 800ms, 3.2s, ...\r\n const jitter = base * 0.2 * (Math.random() * 2 - 1);\r\n return Math.max(50, Math.round(base + jitter));\r\n}\r\n\r\n/**\r\n * Honra `Retry-After` header (segundos ou HTTP-date). Retorna ms ou null se\r\n * inválido. RFC 9110 §10.2.3.\r\n */\r\nfunction parseRetryAfter(value: string | null): number | null {\r\n if (!value) return null;\r\n const secs = Number(value);\r\n if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1000);\r\n const dateMs = Date.parse(value);\r\n if (Number.isFinite(dateMs)) {\r\n const delta = dateMs - Date.now();\r\n if (delta > 0) return delta;\r\n }\r\n return null;\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\n/** Mapeamento status → code estável do NeetruError. */\r\nfunction statusToCode(status: number): NeetruErrorCode {\r\n if (status === 401) return 'unauthorized';\r\n if (status === 403) return 'forbidden';\r\n if (status === 404) return 'not_found';\r\n if (status === 422 || status === 400) return 'validation_failed';\r\n if (status === 429) return 'rate_limited';\r\n if (status >= 500) return 'server_error';\r\n return 'unknown';\r\n}\r\n\r\nfunction buildUrl(baseUrl: string, path: string, query?: HttpRequestOptions['query']): string {\r\n // Trim trailing slash em base e leading em path pra evitar `//`.\r\n const base = baseUrl.replace(/\\/+$/, '');\r\n const p = path.startsWith('/') ? path : `/${path}`;\r\n const url = new URL(`${base}${p}`);\r\n if (query) {\r\n for (const [k, v] of Object.entries(query)) {\r\n if (v === undefined) continue;\r\n url.searchParams.set(k, String(v));\r\n }\r\n }\r\n return url.toString();\r\n}\r\n\r\n/** Parse JSON defensivo — retorna `undefined` em body vazio. */\r\nasync function safeJson(res: Response): Promise<unknown> {\r\n const text = await res.text();\r\n if (!text) return undefined;\r\n try {\r\n return JSON.parse(text);\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Executa request HTTP. Em sucesso retorna body parseado; em erro lança\r\n * `NeetruError` com `code` derivado do status. Aplica retry/backoff\r\n * automático em códigos transientes (rate_limited/server_error/network_error)\r\n * conforme `opts.retries` (default 2 = 3 tentativas).\r\n */\r\nexport async function httpRequest<T>(\r\n config: ResolvedConfig,\r\n opts: HttpRequestOptions,\r\n): Promise<T> {\r\n const method = opts.method ?? 'GET';\r\n const url = buildUrl(config.baseUrl, opts.path, opts.query);\r\n const maxRetries = opts.retries ?? DEFAULT_RETRIES;\r\n\r\n const headers: Record<string, string> = {\r\n accept: 'application/json',\r\n ...opts.headers,\r\n };\r\n\r\n if (opts.requireAuth) {\r\n if (!config.apiKey) {\r\n throw new NeetruError(\r\n 'missing_api_key',\r\n 'This operation requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.',\r\n );\r\n }\r\n headers.authorization = `Bearer ${config.apiKey}`;\r\n }\r\n\r\n // Body só é serializado uma vez — reusado entre tentativas.\r\n const bodyString =\r\n opts.body !== undefined && method !== 'GET' && method !== 'DELETE'\r\n ? JSON.stringify(opts.body)\r\n : undefined;\r\n if (bodyString !== undefined) {\r\n headers['content-type'] = 'application/json';\r\n }\r\n\r\n let lastError: NeetruError | null = null;\r\n\r\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\r\n const init: RequestInit = { method, headers };\r\n if (bodyString !== undefined) init.body = bodyString;\r\n // BUG-020 fix (2026-05-13): timeout default 30s. AbortSignal.timeout\r\n // requer Node 18+ ou browsers recentes.\r\n init.signal = AbortSignal.timeout(30_000);\r\n\r\n let res: Response;\r\n try {\r\n res = await config.fetch(url, init);\r\n } catch (err) {\r\n const message =\r\n err instanceof DOMException && err.name === 'TimeoutError'\r\n ? 'Network error: timeout after 30s'\r\n : `Network error: ${err instanceof Error ? err.message : 'fetch failed'}`;\r\n lastError = new NeetruError('network_error', message);\r\n if (attempt < maxRetries) {\r\n await sleep(backoffMs(attempt));\r\n continue;\r\n }\r\n throw lastError;\r\n }\r\n\r\n const requestId =\r\n res.headers.get('x-request-id') ?? res.headers.get('x-correlation-id') ?? undefined;\r\n\r\n if (res.ok) {\r\n const parsed = await safeJson(res);\r\n return parsed as T;\r\n }\r\n\r\n const body = (await safeJson(res)) as\r\n | { error?: { code?: string; message?: string } | string }\r\n | undefined;\r\n let code: string = statusToCode(res.status);\r\n let message = `HTTP ${res.status}`;\r\n if (body && typeof body === 'object' && 'error' in body) {\r\n const errField = body.error;\r\n if (typeof errField === 'string') {\r\n message = errField;\r\n } else if (errField && typeof errField === 'object') {\r\n if (typeof errField.code === 'string') code = errField.code;\r\n if (typeof errField.message === 'string') message = errField.message;\r\n }\r\n }\r\n const err = new NeetruError(code, message, res.status, requestId);\r\n lastError = err;\r\n\r\n const isRetryable = RETRYABLE_CODES.has(code as NeetruErrorCode);\r\n if (isRetryable && attempt < maxRetries) {\r\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\r\n const delay = retryAfter ?? backoffMs(attempt);\r\n await sleep(delay);\r\n continue;\r\n }\r\n throw err;\r\n }\r\n\r\n // Unreachable — loop sempre retorna ou lança. Safety net.\r\n throw lastError ?? new NeetruError('unknown', 'unexpected httpRequest exit');\r\n}\r\n","/**\r\n * Usage namespace — track usage events e ler quotas (v0.2).\r\n *\r\n * Endpoints consumidos (em prod):\r\n * - `POST /sdk/v1/usage/record` — record event\r\n * - `GET /sdk/v1/usage/quota?metric=X` — ler quota da metric\r\n *\r\n * Comportamento por env:\r\n * - `dev` → MockUsage (in-memory, retornado pelo factory).\r\n * - `workspace`/`prod` → HTTP real.\r\n *\r\n * Diferença vs `telemetry`: telemetry é evento analítico (event sourcing pra\r\n * BigQuery). usage é meterado (consumo cobrado), com quota explícita por plano.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type { ResolvedConfig, UsageNamespace, UsageQuota } from './types';\r\n\r\ninterface RawUsageAck {\r\n ok?: boolean;\r\n recordId?: string;\r\n}\r\n\r\ninterface RawUsageQuota {\r\n metric?: string;\r\n used?: number;\r\n limit?: number;\r\n resetsAt?: string;\r\n plan?: string;\r\n}\r\n\r\nfunction toQuota(metric: string, raw: unknown): UsageQuota {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Quota response is not an object');\r\n }\r\n const r = raw as RawUsageQuota;\r\n if (typeof r.used !== 'number' || typeof r.limit !== 'number') {\r\n throw new NeetruError('invalid_response', 'Quota response missing used/limit numbers');\r\n }\r\n return {\r\n metric: typeof r.metric === 'string' ? r.metric : metric,\r\n used: r.used,\r\n limit: r.limit,\r\n resetsAt: typeof r.resetsAt === 'string' ? r.resetsAt : undefined,\r\n plan: typeof r.plan === 'string' ? r.plan : undefined,\r\n };\r\n}\r\n\r\nexport function createUsageNamespace(config: ResolvedConfig): UsageNamespace {\r\n return {\r\n /**\r\n * Persiste um evento de usage. Em dev (mocks ativos via factory) só loga.\r\n * Em workspace/prod chama POST /sdk/v1/usage/record.\r\n */\r\n async track(\r\n event: string,\r\n properties?: Record<string, string | number | boolean | null>,\r\n ): Promise<{ ok: true }> {\r\n if (!event || typeof event !== 'string') {\r\n throw new NeetruError('validation_failed', 'event name is required');\r\n }\r\n if (event.length > 128) {\r\n throw new NeetruError('validation_failed', 'event name max 128 chars');\r\n }\r\n\r\n const body: Record<string, unknown> = { event };\r\n if (properties && typeof properties === 'object') body.properties = properties;\r\n\r\n const raw = await httpRequest<RawUsageAck>(config, {\r\n method: 'POST',\r\n path: '/sdk/v1/usage/record',\r\n body,\r\n requireAuth: true,\r\n });\r\n\r\n if (!raw || raw.ok !== true) {\r\n throw new NeetruError('invalid_response', 'Usage record response missing ok');\r\n }\r\n return { ok: true };\r\n },\r\n\r\n /**\r\n * Lê quota atual de uma métrica. Cacheável (caller decide), SDK não cacheia.\r\n */\r\n async getQuota(metric: string): Promise<UsageQuota> {\r\n if (!metric || typeof metric !== 'string') {\r\n throw new NeetruError('validation_failed', 'metric is required');\r\n }\r\n const raw = await httpRequest<RawUsageQuota>(config, {\r\n method: 'GET',\r\n path: '/sdk/v1/usage/quota',\r\n query: { metric },\r\n requireAuth: true,\r\n });\r\n return toQuota(metric, raw);\r\n },\r\n\r\n /**\r\n * v0.3 — Reporta consumo metered. Hit no endpoint canônico Sprint 7.\r\n */\r\n async report(\r\n resource: string,\r\n qty: number = 1,\r\n options?: { productId?: string; tenantId?: string },\r\n ) {\r\n if (!resource || typeof resource !== 'string') {\r\n throw new NeetruError('validation_failed', 'resource is required');\r\n }\r\n if (!Number.isFinite(qty) || qty <= 0) {\r\n throw new NeetruError('validation_failed', 'qty must be positive integer');\r\n }\r\n const productId = options?.productId ?? config.productId;\r\n const tenantId = options?.tenantId ?? config.tenantId;\r\n if (!productId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productId required (pass to options or set on createNeetruClient)',\r\n );\r\n }\r\n if (!tenantId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'tenantId required (pass to options or set on createNeetruClient)',\r\n );\r\n }\r\n\r\n const raw = await httpRequest<{\r\n ok?: boolean;\r\n counterId?: string;\r\n value?: number;\r\n limit?: number;\r\n remaining?: number;\r\n status?: string;\r\n }>(config, {\r\n method: 'POST',\r\n path: '/sdk/v1/usage/record',\r\n body: { productId, tenantId, resource, qty: Math.floor(qty) },\r\n requireAuth: true,\r\n });\r\n if (!raw || raw.ok !== true) {\r\n throw new NeetruError('invalid_response', 'usage.report response missing ok');\r\n }\r\n return {\r\n ok: true as const,\r\n counterId: raw.counterId,\r\n value: raw.value,\r\n limit: raw.limit,\r\n remaining: raw.remaining,\r\n status: raw.status,\r\n };\r\n },\r\n\r\n /**\r\n * v0.3 — Verifica entitlement de um resource via GET /sdk/v1/entitlements.\r\n */\r\n async check(\r\n resource: string,\r\n options?: { productId?: string; tenantId?: string },\r\n ) {\r\n if (!resource || typeof resource !== 'string') {\r\n throw new NeetruError('validation_failed', 'resource is required');\r\n }\r\n const productId = options?.productId ?? config.productId;\r\n const tenantId = options?.tenantId ?? config.tenantId;\r\n if (!productId || !tenantId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productId and tenantId required',\r\n );\r\n }\r\n const raw = await httpRequest<{\r\n allowed?: boolean;\r\n reason?: string;\r\n remaining?: number;\r\n limit?: number;\r\n planId?: string | null;\r\n planFeatures?: string[];\r\n }>(config, {\r\n method: 'GET',\r\n path: '/sdk/v1/entitlements',\r\n query: { productId, tenantId, feature: resource },\r\n requireAuth: true,\r\n });\r\n if (!raw || typeof raw.allowed !== 'boolean') {\r\n throw new NeetruError('invalid_response', 'usage.check response missing allowed');\r\n }\r\n return {\r\n allowed: raw.allowed,\r\n reason: raw.reason,\r\n remaining: raw.remaining,\r\n limit: raw.limit,\r\n planId: raw.planId,\r\n planFeatures: raw.planFeatures,\r\n };\r\n },\r\n };\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/usage.ts"],"names":["err","message"],"mappings":"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","file":"usage.mjs","sourcesContent":["/**\r\n * Erros tipados do SDK.\r\n *\r\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\r\n * por `.code` (string estável) sem parsing de message.\r\n */\r\n\r\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\r\nexport type NeetruErrorCode =\r\n | 'invalid_config'\r\n | 'missing_api_key'\r\n | 'unauthorized'\r\n | 'forbidden'\r\n | 'not_found'\r\n | 'rate_limited'\r\n | 'validation_failed'\r\n | 'network_error'\r\n | 'invalid_response'\r\n | 'server_error'\r\n | 'token_expired'\r\n | 'token_invalid_signature'\r\n | 'token_invalid_audience'\r\n | 'token_invalid_issuer'\r\n | 'unknown';\r\n\r\n/**\r\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\r\n *\r\n * @example\r\n * ```ts\r\n * try { await client.catalog.list(); }\r\n * catch (e) {\r\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\r\n * }\r\n * ```\r\n */\r\nexport class NeetruError extends Error {\r\n public readonly code: NeetruErrorCode | string;\r\n public readonly status?: number;\r\n public readonly requestId?: string;\r\n\r\n constructor(\r\n code: NeetruErrorCode | string,\r\n message: string,\r\n status?: number,\r\n requestId?: string,\r\n ) {\r\n super(message);\r\n this.name = 'NeetruError';\r\n this.code = code;\r\n this.status = status;\r\n this.requestId = requestId;\r\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\r\n Object.setPrototypeOf(this, NeetruError.prototype);\r\n }\r\n}\r\n","/**\r\n * HTTP transport interno do SDK.\r\n *\r\n * Responsabilidades:\r\n * - Construir URL absoluta a partir de `baseUrl` + path\r\n * - Injetar Bearer token quando `requireAuth=true`\r\n * - Mapear status HTTP → `NeetruError` com `code` estável\r\n * - Parse defensivo de JSON (não lança em body vazio em 204)\r\n * - Retry/backoff exponencial em `rate_limited` (429), `server_error` (5xx)\r\n * e `network_error` (timeout/falha de rede). Honra `Retry-After` quando\r\n * presente. Default 2 retries (3 tentativas no total). Caller opta-out\r\n * com `retries: 0`.\r\n */\r\nimport { NeetruError, type NeetruErrorCode } from './errors';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n/** Opções da request HTTP. */\r\nexport interface HttpRequestOptions {\r\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\r\n /** Path relativo (ex: `/api/v1/cli/catalog`). Concatenado a `baseUrl`. */\r\n path: string;\r\n /** Query string params (chave → valor primitivo). Valores `undefined` ignorados. */\r\n query?: Record<string, string | number | boolean | undefined>;\r\n /** Body JSON-serializável. Ignorado em GET/DELETE. */\r\n body?: unknown;\r\n /**\r\n * Se true, injeta `Authorization: Bearer <apiKey>`. Lança `missing_api_key`\r\n * se config.apiKey ausente. Default false.\r\n */\r\n requireAuth?: boolean;\r\n /** Cabeçalhos extras. */\r\n headers?: Record<string, string>;\r\n /**\r\n * Número de retries em códigos transientes (`rate_limited`, `server_error`,\r\n * `network_error`). Default 2 (= 3 tentativas total). Caller passa `0` pra\r\n * desativar (útil em operações não-idempotentes específicas).\r\n */\r\n retries?: number;\r\n}\r\n\r\nconst DEFAULT_RETRIES = 2;\r\nconst RETRYABLE_CODES = new Set<NeetruErrorCode>([\r\n 'rate_limited',\r\n 'server_error',\r\n 'network_error',\r\n]);\r\n\r\n/** Backoff exponencial com jitter ±20%. attempt: 0=primeira, 1=primeiro retry, ... */\r\nfunction backoffMs(attempt: number): number {\r\n const base = 200 * Math.pow(4, attempt); // 200ms, 800ms, 3.2s, ...\r\n const jitter = base * 0.2 * (Math.random() * 2 - 1);\r\n return Math.max(50, Math.round(base + jitter));\r\n}\r\n\r\n/**\r\n * Honra `Retry-After` header (segundos ou HTTP-date). Retorna ms ou null se\r\n * inválido. RFC 9110 §10.2.3.\r\n */\r\nfunction parseRetryAfter(value: string | null): number | null {\r\n if (!value) return null;\r\n const secs = Number(value);\r\n if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1000);\r\n const dateMs = Date.parse(value);\r\n if (Number.isFinite(dateMs)) {\r\n const delta = dateMs - Date.now();\r\n if (delta > 0) return delta;\r\n }\r\n return null;\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\n/** Mapeamento status → code estável do NeetruError. */\r\nfunction statusToCode(status: number): NeetruErrorCode {\r\n if (status === 401) return 'unauthorized';\r\n if (status === 403) return 'forbidden';\r\n if (status === 404) return 'not_found';\r\n if (status === 422 || status === 400) return 'validation_failed';\r\n if (status === 429) return 'rate_limited';\r\n if (status >= 500) return 'server_error';\r\n return 'unknown';\r\n}\r\n\r\nfunction buildUrl(baseUrl: string, path: string, query?: HttpRequestOptions['query']): string {\r\n // Trim trailing slash em base e leading em path pra evitar `//`.\r\n const base = baseUrl.replace(/\\/+$/, '');\r\n const p = path.startsWith('/') ? path : `/${path}`;\r\n const url = new URL(`${base}${p}`);\r\n if (query) {\r\n for (const [k, v] of Object.entries(query)) {\r\n if (v === undefined) continue;\r\n url.searchParams.set(k, String(v));\r\n }\r\n }\r\n return url.toString();\r\n}\r\n\r\n/** Parse JSON defensivo — retorna `undefined` em body vazio. */\r\nasync function safeJson(res: Response): Promise<unknown> {\r\n const text = await res.text();\r\n if (!text) return undefined;\r\n try {\r\n return JSON.parse(text);\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Executa request HTTP. Em sucesso retorna body parseado; em erro lança\r\n * `NeetruError` com `code` derivado do status. Aplica retry/backoff\r\n * automático em códigos transientes (rate_limited/server_error/network_error)\r\n * conforme `opts.retries` (default 2 = 3 tentativas).\r\n */\r\nexport async function httpRequest<T>(\r\n config: ResolvedConfig,\r\n opts: HttpRequestOptions,\r\n): Promise<T> {\r\n const method = opts.method ?? 'GET';\r\n const url = buildUrl(config.baseUrl, opts.path, opts.query);\r\n const maxRetries = opts.retries ?? DEFAULT_RETRIES;\r\n\r\n const headers: Record<string, string> = {\r\n accept: 'application/json',\r\n ...opts.headers,\r\n };\r\n\r\n if (opts.requireAuth) {\r\n if (!config.apiKey) {\r\n throw new NeetruError(\r\n 'missing_api_key',\r\n 'This operation requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.',\r\n );\r\n }\r\n headers.authorization = `Bearer ${config.apiKey}`;\r\n }\r\n\r\n // Body só é serializado uma vez — reusado entre tentativas.\r\n const bodyString =\r\n opts.body !== undefined && method !== 'GET' && method !== 'DELETE'\r\n ? JSON.stringify(opts.body)\r\n : undefined;\r\n if (bodyString !== undefined) {\r\n headers['content-type'] = 'application/json';\r\n }\r\n\r\n let lastError: NeetruError | null = null;\r\n\r\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\r\n const init: RequestInit = { method, headers };\r\n if (bodyString !== undefined) init.body = bodyString;\r\n // BUG-020 fix (2026-05-13): timeout default 30s. AbortSignal.timeout\r\n // requer Node 18+ ou browsers recentes.\r\n init.signal = AbortSignal.timeout(30_000);\r\n\r\n let res: Response;\r\n try {\r\n res = await config.fetch(url, init);\r\n } catch (err) {\r\n const message =\r\n err instanceof DOMException && err.name === 'TimeoutError'\r\n ? 'Network error: timeout after 30s'\r\n : `Network error: ${err instanceof Error ? err.message : 'fetch failed'}`;\r\n lastError = new NeetruError('network_error', message);\r\n if (attempt < maxRetries) {\r\n await sleep(backoffMs(attempt));\r\n continue;\r\n }\r\n throw lastError;\r\n }\r\n\r\n const requestId =\r\n res.headers.get('x-request-id') ?? res.headers.get('x-correlation-id') ?? undefined;\r\n\r\n if (res.ok) {\r\n const parsed = await safeJson(res);\r\n return parsed as T;\r\n }\r\n\r\n const body = (await safeJson(res)) as\r\n | { error?: { code?: string; message?: string } | string }\r\n | undefined;\r\n let code: string = statusToCode(res.status);\r\n let message = `HTTP ${res.status}`;\r\n if (body && typeof body === 'object' && 'error' in body) {\r\n const errField = body.error;\r\n if (typeof errField === 'string') {\r\n message = errField;\r\n } else if (errField && typeof errField === 'object') {\r\n if (typeof errField.code === 'string') code = errField.code;\r\n if (typeof errField.message === 'string') message = errField.message;\r\n }\r\n }\r\n const err = new NeetruError(code, message, res.status, requestId);\r\n lastError = err;\r\n\r\n const isRetryable = RETRYABLE_CODES.has(code as NeetruErrorCode);\r\n if (isRetryable && attempt < maxRetries) {\r\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\r\n const delay = retryAfter ?? backoffMs(attempt);\r\n await sleep(delay);\r\n continue;\r\n }\r\n throw err;\r\n }\r\n\r\n // Unreachable — loop sempre retorna ou lança. Safety net.\r\n throw lastError ?? new NeetruError('unknown', 'unexpected httpRequest exit');\r\n}\r\n","/**\r\n * Usage namespace — track usage events e ler quotas (v0.2).\r\n *\r\n * Endpoints consumidos (em prod):\r\n * - `POST /sdk/v1/usage/record` — record event\r\n * - `GET /sdk/v1/usage/quota?metric=X` — ler quota da metric\r\n *\r\n * Comportamento por env:\r\n * - `dev` → MockUsage (in-memory, retornado pelo factory).\r\n * - `workspace`/`prod` → HTTP real.\r\n *\r\n * Diferença vs `telemetry`: telemetry é evento analítico (event sourcing pra\r\n * BigQuery). usage é meterado (consumo cobrado), com quota explícita por plano.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type { ResolvedConfig, UsageNamespace, UsageQuota } from './types';\r\n\r\ninterface RawUsageAck {\r\n ok?: boolean;\r\n recordId?: string;\r\n}\r\n\r\ninterface RawUsageQuota {\r\n metric?: string;\r\n used?: number;\r\n limit?: number;\r\n resetsAt?: string;\r\n plan?: string;\r\n}\r\n\r\nfunction toQuota(metric: string, raw: unknown): UsageQuota {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Quota response is not an object');\r\n }\r\n const r = raw as RawUsageQuota;\r\n if (typeof r.used !== 'number' || typeof r.limit !== 'number') {\r\n throw new NeetruError('invalid_response', 'Quota response missing used/limit numbers');\r\n }\r\n return {\r\n metric: typeof r.metric === 'string' ? r.metric : metric,\r\n used: r.used,\r\n limit: r.limit,\r\n resetsAt: typeof r.resetsAt === 'string' ? r.resetsAt : undefined,\r\n plan: typeof r.plan === 'string' ? r.plan : undefined,\r\n };\r\n}\r\n\r\nexport function createUsageNamespace(config: ResolvedConfig): UsageNamespace {\r\n return {\r\n /**\r\n * Persiste um evento de usage. Em dev (mocks ativos via factory) só loga.\r\n * Em workspace/prod chama POST /sdk/v1/usage/record.\r\n */\r\n async track(\r\n event: string,\r\n properties?: Record<string, string | number | boolean | null>,\r\n ): Promise<{ ok: true }> {\r\n if (!event || typeof event !== 'string') {\r\n throw new NeetruError('validation_failed', 'event name is required');\r\n }\r\n if (event.length > 128) {\r\n throw new NeetruError('validation_failed', 'event name max 128 chars');\r\n }\r\n\r\n const body: Record<string, unknown> = { event };\r\n if (properties && typeof properties === 'object') body.properties = properties;\r\n\r\n const raw = await httpRequest<RawUsageAck>(config, {\r\n method: 'POST',\r\n path: '/sdk/v1/usage/record',\r\n body,\r\n requireAuth: true,\r\n });\r\n\r\n if (!raw || raw.ok !== true) {\r\n throw new NeetruError('invalid_response', 'Usage record response missing ok');\r\n }\r\n return { ok: true };\r\n },\r\n\r\n /**\r\n * Lê quota atual de uma métrica. Cacheável (caller decide), SDK não cacheia.\r\n */\r\n async getQuota(metric: string): Promise<UsageQuota> {\r\n if (!metric || typeof metric !== 'string') {\r\n throw new NeetruError('validation_failed', 'metric is required');\r\n }\r\n const raw = await httpRequest<RawUsageQuota>(config, {\r\n method: 'GET',\r\n path: '/sdk/v1/usage/quota',\r\n query: { metric },\r\n requireAuth: true,\r\n });\r\n return toQuota(metric, raw);\r\n },\r\n\r\n /**\r\n * v0.3 — Reporta consumo metered. Hit no endpoint canônico Sprint 7.\r\n */\r\n async report(\r\n resource: string,\r\n qty: number = 1,\r\n options?: { productId?: string; tenantId?: string },\r\n ) {\r\n if (!resource || typeof resource !== 'string') {\r\n throw new NeetruError('validation_failed', 'resource is required');\r\n }\r\n if (!Number.isFinite(qty) || qty <= 0) {\r\n throw new NeetruError('validation_failed', 'qty must be positive integer');\r\n }\r\n const productId = options?.productId ?? config.productId;\r\n const tenantId = options?.tenantId ?? config.tenantId;\r\n if (!productId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productId required (pass to options or set on createNeetruClient)',\r\n );\r\n }\r\n if (!tenantId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'tenantId required (pass to options or set on createNeetruClient)',\r\n );\r\n }\r\n\r\n const raw = await httpRequest<{\r\n ok?: boolean;\r\n counterId?: string;\r\n value?: number;\r\n limit?: number;\r\n remaining?: number;\r\n status?: string;\r\n }>(config, {\r\n method: 'POST',\r\n path: '/sdk/v1/usage/record',\r\n body: { productId, tenantId, resource, qty: Math.floor(qty) },\r\n requireAuth: true,\r\n });\r\n if (!raw || raw.ok !== true) {\r\n throw new NeetruError('invalid_response', 'usage.report response missing ok');\r\n }\r\n return {\r\n ok: true as const,\r\n counterId: raw.counterId,\r\n value: raw.value,\r\n limit: raw.limit,\r\n remaining: raw.remaining,\r\n status: raw.status,\r\n };\r\n },\r\n\r\n /**\r\n * v0.3 — Verifica entitlement de um resource via GET /sdk/v1/entitlements.\r\n */\r\n async check(\r\n resource: string,\r\n options?: { productId?: string; tenantId?: string },\r\n ) {\r\n if (!resource || typeof resource !== 'string') {\r\n throw new NeetruError('validation_failed', 'resource is required');\r\n }\r\n const productId = options?.productId ?? config.productId;\r\n const tenantId = options?.tenantId ?? config.tenantId;\r\n if (!productId || !tenantId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productId and tenantId required',\r\n );\r\n }\r\n const raw = await httpRequest<{\r\n allowed?: boolean;\r\n reason?: string;\r\n remaining?: number;\r\n limit?: number;\r\n planId?: string | null;\r\n planFeatures?: string[];\r\n }>(config, {\r\n method: 'GET',\r\n path: '/sdk/v1/entitlements',\r\n query: { productId, tenantId, feature: resource },\r\n requireAuth: true,\r\n });\r\n if (!raw || typeof raw.allowed !== 'boolean') {\r\n throw new NeetruError('invalid_response', 'usage.check response missing allowed');\r\n }\r\n return {\r\n allowed: raw.allowed,\r\n reason: raw.reason,\r\n remaining: raw.remaining,\r\n limit: raw.limit,\r\n planId: raw.planId,\r\n planFeatures: raw.planFeatures,\r\n };\r\n },\r\n };\r\n}\r\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/webhooks.ts"],"names":["err","message"],"mappings":"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","file":"webhooks.cjs","sourcesContent":["/**\r\n * Erros tipados do SDK.\r\n *\r\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\r\n * por `.code` (string estável) sem parsing de message.\r\n */\r\n\r\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\r\nexport type NeetruErrorCode =\r\n | 'invalid_config'\r\n | 'missing_api_key'\r\n | 'unauthorized'\r\n | 'forbidden'\r\n | 'not_found'\r\n | 'rate_limited'\r\n | 'validation_failed'\r\n | 'network_error'\r\n | 'invalid_response'\r\n | 'server_error'\r\n | 'unknown';\r\n\r\n/**\r\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\r\n *\r\n * @example\r\n * ```ts\r\n * try { await client.catalog.list(); }\r\n * catch (e) {\r\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\r\n * }\r\n * ```\r\n */\r\nexport class NeetruError extends Error {\r\n public readonly code: NeetruErrorCode | string;\r\n public readonly status?: number;\r\n public readonly requestId?: string;\r\n\r\n constructor(\r\n code: NeetruErrorCode | string,\r\n message: string,\r\n status?: number,\r\n requestId?: string,\r\n ) {\r\n super(message);\r\n this.name = 'NeetruError';\r\n this.code = code;\r\n this.status = status;\r\n this.requestId = requestId;\r\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\r\n Object.setPrototypeOf(this, NeetruError.prototype);\r\n }\r\n}\r\n","/**\r\n * HTTP transport interno do SDK.\r\n *\r\n * Responsabilidades:\r\n * - Construir URL absoluta a partir de `baseUrl` + path\r\n * - Injetar Bearer token quando `requireAuth=true`\r\n * - Mapear status HTTP → `NeetruError` com `code` estável\r\n * - Parse defensivo de JSON (não lança em body vazio em 204)\r\n * - Retry/backoff exponencial em `rate_limited` (429), `server_error` (5xx)\r\n * e `network_error` (timeout/falha de rede). Honra `Retry-After` quando\r\n * presente. Default 2 retries (3 tentativas no total). Caller opta-out\r\n * com `retries: 0`.\r\n */\r\nimport { NeetruError, type NeetruErrorCode } from './errors';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n/** Opções da request HTTP. */\r\nexport interface HttpRequestOptions {\r\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\r\n /** Path relativo (ex: `/api/v1/cli/catalog`). Concatenado a `baseUrl`. */\r\n path: string;\r\n /** Query string params (chave → valor primitivo). Valores `undefined` ignorados. */\r\n query?: Record<string, string | number | boolean | undefined>;\r\n /** Body JSON-serializável. Ignorado em GET/DELETE. */\r\n body?: unknown;\r\n /**\r\n * Se true, injeta `Authorization: Bearer <apiKey>`. Lança `missing_api_key`\r\n * se config.apiKey ausente. Default false.\r\n */\r\n requireAuth?: boolean;\r\n /** Cabeçalhos extras. */\r\n headers?: Record<string, string>;\r\n /**\r\n * Número de retries em códigos transientes (`rate_limited`, `server_error`,\r\n * `network_error`). Default 2 (= 3 tentativas total). Caller passa `0` pra\r\n * desativar (útil em operações não-idempotentes específicas).\r\n */\r\n retries?: number;\r\n}\r\n\r\nconst DEFAULT_RETRIES = 2;\r\nconst RETRYABLE_CODES = new Set<NeetruErrorCode>([\r\n 'rate_limited',\r\n 'server_error',\r\n 'network_error',\r\n]);\r\n\r\n/** Backoff exponencial com jitter ±20%. attempt: 0=primeira, 1=primeiro retry, ... */\r\nfunction backoffMs(attempt: number): number {\r\n const base = 200 * Math.pow(4, attempt); // 200ms, 800ms, 3.2s, ...\r\n const jitter = base * 0.2 * (Math.random() * 2 - 1);\r\n return Math.max(50, Math.round(base + jitter));\r\n}\r\n\r\n/**\r\n * Honra `Retry-After` header (segundos ou HTTP-date). Retorna ms ou null se\r\n * inválido. RFC 9110 §10.2.3.\r\n */\r\nfunction parseRetryAfter(value: string | null): number | null {\r\n if (!value) return null;\r\n const secs = Number(value);\r\n if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1000);\r\n const dateMs = Date.parse(value);\r\n if (Number.isFinite(dateMs)) {\r\n const delta = dateMs - Date.now();\r\n if (delta > 0) return delta;\r\n }\r\n return null;\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\n/** Mapeamento status → code estável do NeetruError. */\r\nfunction statusToCode(status: number): NeetruErrorCode {\r\n if (status === 401) return 'unauthorized';\r\n if (status === 403) return 'forbidden';\r\n if (status === 404) return 'not_found';\r\n if (status === 422 || status === 400) return 'validation_failed';\r\n if (status === 429) return 'rate_limited';\r\n if (status >= 500) return 'server_error';\r\n return 'unknown';\r\n}\r\n\r\nfunction buildUrl(baseUrl: string, path: string, query?: HttpRequestOptions['query']): string {\r\n // Trim trailing slash em base e leading em path pra evitar `//`.\r\n const base = baseUrl.replace(/\\/+$/, '');\r\n const p = path.startsWith('/') ? path : `/${path}`;\r\n const url = new URL(`${base}${p}`);\r\n if (query) {\r\n for (const [k, v] of Object.entries(query)) {\r\n if (v === undefined) continue;\r\n url.searchParams.set(k, String(v));\r\n }\r\n }\r\n return url.toString();\r\n}\r\n\r\n/** Parse JSON defensivo — retorna `undefined` em body vazio. */\r\nasync function safeJson(res: Response): Promise<unknown> {\r\n const text = await res.text();\r\n if (!text) return undefined;\r\n try {\r\n return JSON.parse(text);\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Executa request HTTP. Em sucesso retorna body parseado; em erro lança\r\n * `NeetruError` com `code` derivado do status. Aplica retry/backoff\r\n * automático em códigos transientes (rate_limited/server_error/network_error)\r\n * conforme `opts.retries` (default 2 = 3 tentativas).\r\n */\r\nexport async function httpRequest<T>(\r\n config: ResolvedConfig,\r\n opts: HttpRequestOptions,\r\n): Promise<T> {\r\n const method = opts.method ?? 'GET';\r\n const url = buildUrl(config.baseUrl, opts.path, opts.query);\r\n const maxRetries = opts.retries ?? DEFAULT_RETRIES;\r\n\r\n const headers: Record<string, string> = {\r\n accept: 'application/json',\r\n ...opts.headers,\r\n };\r\n\r\n if (opts.requireAuth) {\r\n if (!config.apiKey) {\r\n throw new NeetruError(\r\n 'missing_api_key',\r\n 'This operation requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.',\r\n );\r\n }\r\n headers.authorization = `Bearer ${config.apiKey}`;\r\n }\r\n\r\n // Body só é serializado uma vez — reusado entre tentativas.\r\n const bodyString =\r\n opts.body !== undefined && method !== 'GET' && method !== 'DELETE'\r\n ? JSON.stringify(opts.body)\r\n : undefined;\r\n if (bodyString !== undefined) {\r\n headers['content-type'] = 'application/json';\r\n }\r\n\r\n let lastError: NeetruError | null = null;\r\n\r\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\r\n const init: RequestInit = { method, headers };\r\n if (bodyString !== undefined) init.body = bodyString;\r\n // BUG-020 fix (2026-05-13): timeout default 30s. AbortSignal.timeout\r\n // requer Node 18+ ou browsers recentes.\r\n init.signal = AbortSignal.timeout(30_000);\r\n\r\n let res: Response;\r\n try {\r\n res = await config.fetch(url, init);\r\n } catch (err) {\r\n const message =\r\n err instanceof DOMException && err.name === 'TimeoutError'\r\n ? 'Network error: timeout after 30s'\r\n : `Network error: ${err instanceof Error ? err.message : 'fetch failed'}`;\r\n lastError = new NeetruError('network_error', message);\r\n if (attempt < maxRetries) {\r\n await sleep(backoffMs(attempt));\r\n continue;\r\n }\r\n throw lastError;\r\n }\r\n\r\n const requestId =\r\n res.headers.get('x-request-id') ?? res.headers.get('x-correlation-id') ?? undefined;\r\n\r\n if (res.ok) {\r\n const parsed = await safeJson(res);\r\n return parsed as T;\r\n }\r\n\r\n const body = (await safeJson(res)) as\r\n | { error?: { code?: string; message?: string } | string }\r\n | undefined;\r\n let code: string = statusToCode(res.status);\r\n let message = `HTTP ${res.status}`;\r\n if (body && typeof body === 'object' && 'error' in body) {\r\n const errField = body.error;\r\n if (typeof errField === 'string') {\r\n message = errField;\r\n } else if (errField && typeof errField === 'object') {\r\n if (typeof errField.code === 'string') code = errField.code;\r\n if (typeof errField.message === 'string') message = errField.message;\r\n }\r\n }\r\n const err = new NeetruError(code, message, res.status, requestId);\r\n lastError = err;\r\n\r\n const isRetryable = RETRYABLE_CODES.has(code as NeetruErrorCode);\r\n if (isRetryable && attempt < maxRetries) {\r\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\r\n const delay = retryAfter ?? backoffMs(attempt);\r\n await sleep(delay);\r\n continue;\r\n }\r\n throw err;\r\n }\r\n\r\n // Unreachable — loop sempre retorna ou lança. Safety net.\r\n throw lastError ?? new NeetruError('unknown', 'unexpected httpRequest exit');\r\n}\r\n","/**\r\n * Webhooks namespace (v1.2) — produtos SaaS registram endpoints HTTP no Core\r\n * pra receber notificações de eventos.\r\n *\r\n * Casos típicos:\r\n * - `subscription.activated` quando cliente conclui checkout\r\n * - `subscription.cancelled` / `subscription.payment_failed`\r\n * - `usage.quota_exceeded` quando produto bate teto mensal\r\n * - `account.suspended` quando staff Neetru suspende uma conta\r\n *\r\n * Pull-vs-push: o SDK existente é pull-only (`getQuota`, etc). Webhooks\r\n * fecham o gap pra eventos assíncronos sem o produto precisar fazer polling.\r\n *\r\n * Segurança:\r\n * - Endpoint do produto recebe HMAC SHA-256 em header `X-Neetru-Signature`\r\n * usando `secret` opcional do registro. Sem `secret`, header ausente —\r\n * produto deve usar HTTPS + IP allowlist.\r\n * - Replay protection: header `X-Neetru-Timestamp` (ms) — produto deve\r\n * rejeitar > 5min de skew.\r\n * - Retry: Core retenta 3x com backoff exponencial (1s, 5s, 25s) se 5xx\r\n * ou timeout. Após 3 falhas → marca endpoint `degraded` por 1h.\r\n *\r\n * Endpoints REST (em prod):\r\n * - `POST /api/sdk/v1/webhooks` — registra novo endpoint\r\n * - `GET /api/sdk/v1/webhooks` — lista endpoints do produto\r\n * - `DELETE /api/sdk/v1/webhooks/{id}` — remove endpoint\r\n * - `POST /api/sdk/v1/webhooks/{id}/test` — dispara evento de teste\r\n *\r\n * Mock em `NEETRU_ENV=dev`: tudo in-memory, sem rede.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n/** Eventos Neetru que produtos podem assinar. Lista expansível por minor bump. */\r\nexport type WebhookEvent =\r\n | 'subscription.activated'\r\n | 'subscription.cancelled'\r\n | 'subscription.payment_failed'\r\n | 'subscription.trial_ending'\r\n | 'usage.quota_exceeded'\r\n | 'account.suspended'\r\n | 'account.reactivated'\r\n | 'support.ticket_replied';\r\n\r\nexport interface WebhookEndpoint {\r\n id: string;\r\n url: string;\r\n events: WebhookEvent[];\r\n /** Quando true, `X-Neetru-Signature` é enviado em cada dispatch. */\r\n hasSecret: boolean;\r\n status: 'active' | 'degraded' | 'disabled';\r\n /** ISO timestamp do último dispatch bem-sucedido. */\r\n lastDeliveryAt?: string;\r\n /** Quantos dispatches falharam consecutivos (resetado em sucesso). */\r\n consecutiveFailures?: number;\r\n createdAt: string;\r\n}\r\n\r\nexport interface RegisterWebhookInput {\r\n url: string;\r\n events: WebhookEvent[];\r\n /**\r\n * Secret pra HMAC SHA-256 (mín 16 chars). Recomendado.\r\n * Quando ausente, dispatches vão sem assinatura — produto deve ter\r\n * IP allowlist ou outra defesa.\r\n */\r\n secret?: string;\r\n}\r\n\r\nexport interface WebhookTestResult {\r\n ok: boolean;\r\n statusCode?: number;\r\n durationMs?: number;\r\n error?: string;\r\n}\r\n\r\nexport interface WebhooksNamespace {\r\n /** Registra um novo endpoint. */\r\n register(input: RegisterWebhookInput): Promise<WebhookEndpoint>;\r\n /** Lista endpoints registrados pelo produto. */\r\n list(): Promise<WebhookEndpoint[]>;\r\n /** Remove um endpoint. */\r\n unregister(id: string): Promise<{ ok: true }>;\r\n /** Dispara evento de teste pra validar conectividade. */\r\n test(id: string): Promise<WebhookTestResult>;\r\n}\r\n\r\n/**\r\n * Verifica assinatura HMAC SHA-256 de payload de webhook recebido pelo\r\n * produto consumer. Constant-time compare pra resistir a timing attack.\r\n *\r\n * @param payload Corpo cru da request (string ou Buffer). NÃO use o objeto\r\n * parseado — JSON.stringify pode diferir do que foi assinado.\r\n * @param signature Header `X-Neetru-Signature` recebido (formato `sha256=<hex>`).\r\n * @param secret Secret registrado em `webhooks.register({ secret })`.\r\n * @returns true se assinatura confere, false caso contrário.\r\n *\r\n * @example\r\n * ```ts\r\n * // Express handler\r\n * app.post('/webhooks/neetru', express.raw({ type: 'application/json' }), (req, res) => {\r\n * const sig = req.header('X-Neetru-Signature');\r\n * if (!verifyWebhookSignature(req.body, sig, process.env.WEBHOOK_SECRET!)) {\r\n * return res.status(401).end();\r\n * }\r\n * const event = JSON.parse(req.body.toString('utf8'));\r\n * // ... handle event\r\n * res.json({ ok: true });\r\n * });\r\n * ```\r\n */\r\nexport function verifyWebhookSignature(\r\n payload: string | Uint8Array,\r\n signature: string | null | undefined,\r\n secret: string,\r\n): boolean {\r\n if (!signature || !secret) return false;\r\n // Aceita \"sha256=<hex>\" ou \"<hex>\" cru.\r\n const sigHex = signature.startsWith('sha256=') ? signature.slice(7) : signature;\r\n if (!/^[0-9a-f]+$/i.test(sigHex)) return false;\r\n\r\n // Crypto API: Node tem `node:crypto`, browsers têm WebCrypto. Aqui usamos\r\n // node:crypto (SDK roda majoritariamente server-side em produto Node). Se\r\n // o consumer for browser puro precisando verificar, basta importar o\r\n // namespace direto e usar WebCrypto — não é o caso típico, então não\r\n // pagamos o custo de bundle.\r\n let nodeCrypto: typeof import('node:crypto');\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-require-imports\r\n nodeCrypto = require('node:crypto');\r\n } catch {\r\n if (typeof console !== 'undefined') {\r\n console.warn(\r\n '[neetru-sdk] verifyWebhookSignature requires Node crypto. In browser, use WebCrypto subtle.verify directly.',\r\n );\r\n }\r\n return false;\r\n }\r\n\r\n const computed = nodeCrypto.createHmac('sha256', secret).update(payload).digest('hex');\r\n const a = Buffer.from(computed, 'hex');\r\n const b = Buffer.from(sigHex.toLowerCase(), 'hex');\r\n if (a.length !== b.length) return false;\r\n return nodeCrypto.timingSafeEqual(a, b);\r\n}\r\n\r\n// ─── HTTP impl ──────────────────────────────────────────────────────────────\r\n\r\nconst VALID_EVENTS: readonly WebhookEvent[] = [\r\n 'subscription.activated',\r\n 'subscription.cancelled',\r\n 'subscription.payment_failed',\r\n 'subscription.trial_ending',\r\n 'usage.quota_exceeded',\r\n 'account.suspended',\r\n 'account.reactivated',\r\n 'support.ticket_replied',\r\n];\r\n\r\nfunction toEndpoint(raw: unknown): WebhookEndpoint {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Webhook response is not an object');\r\n }\r\n const r = raw as Record<string, unknown>;\r\n if (typeof r.id !== 'string') {\r\n throw new NeetruError('invalid_response', 'Webhook missing id');\r\n }\r\n return {\r\n id: r.id,\r\n url: typeof r.url === 'string' ? r.url : '',\r\n events: Array.isArray(r.events)\r\n ? (r.events as unknown[]).filter((e): e is WebhookEvent =>\r\n VALID_EVENTS.includes(e as WebhookEvent),\r\n )\r\n : [],\r\n hasSecret: r.hasSecret === true,\r\n status:\r\n r.status === 'active' || r.status === 'degraded' || r.status === 'disabled'\r\n ? r.status\r\n : 'active',\r\n lastDeliveryAt: typeof r.lastDeliveryAt === 'string' ? r.lastDeliveryAt : undefined,\r\n consecutiveFailures:\r\n typeof r.consecutiveFailures === 'number' ? r.consecutiveFailures : undefined,\r\n createdAt: typeof r.createdAt === 'string' ? r.createdAt : new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction validateInput(input: RegisterWebhookInput): void {\r\n if (!input.url || typeof input.url !== 'string') {\r\n throw new NeetruError('validation_failed', 'url é obrigatória');\r\n }\r\n try {\r\n const parsed = new URL(input.url);\r\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\r\n throw new Error('invalid protocol');\r\n }\r\n // Em prod, http: é warning (não bloqueia) — testes locais podem usar\r\n } catch {\r\n throw new NeetruError('validation_failed', `url inválida: ${input.url}`);\r\n }\r\n if (!Array.isArray(input.events) || input.events.length === 0) {\r\n throw new NeetruError('validation_failed', 'events deve ter pelo menos 1 evento');\r\n }\r\n for (const ev of input.events) {\r\n if (!VALID_EVENTS.includes(ev)) {\r\n throw new NeetruError('validation_failed', `evento desconhecido: ${ev}`);\r\n }\r\n }\r\n if (input.secret !== undefined && input.secret.length < 16) {\r\n throw new NeetruError('validation_failed', 'secret deve ter ≥16 chars (recomendado 32+)');\r\n }\r\n}\r\n\r\nexport function createWebhooksNamespace(config: ResolvedConfig): WebhooksNamespace {\r\n return {\r\n async register(input) {\r\n validateInput(input);\r\n const raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/webhooks',\r\n body: input,\r\n requireAuth: true,\r\n });\r\n return toEndpoint(raw);\r\n },\r\n async list() {\r\n const raw = await httpRequest<{ endpoints?: unknown[] }>(config, {\r\n method: 'GET',\r\n path: '/api/sdk/v1/webhooks',\r\n requireAuth: true,\r\n });\r\n const list = Array.isArray(raw?.endpoints) ? raw.endpoints : [];\r\n return list.map(toEndpoint);\r\n },\r\n async unregister(id) {\r\n if (!id) throw new NeetruError('validation_failed', 'id obrigatório');\r\n await httpRequest<unknown>(config, {\r\n method: 'DELETE',\r\n path: `/api/sdk/v1/webhooks/${encodeURIComponent(id)}`,\r\n requireAuth: true,\r\n });\r\n return { ok: true };\r\n },\r\n async test(id) {\r\n if (!id) throw new NeetruError('validation_failed', 'id obrigatório');\r\n const raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: `/api/sdk/v1/webhooks/${encodeURIComponent(id)}/test`,\r\n requireAuth: true,\r\n });\r\n if (!raw || typeof raw !== 'object') {\r\n return { ok: false, error: 'invalid response' };\r\n }\r\n const r = raw as Record<string, unknown>;\r\n return {\r\n ok: r.ok === true,\r\n statusCode: typeof r.statusCode === 'number' ? r.statusCode : undefined,\r\n durationMs: typeof r.durationMs === 'number' ? r.durationMs : undefined,\r\n error: typeof r.error === 'string' ? r.error : undefined,\r\n };\r\n },\r\n };\r\n}\r\n\r\n// ─── Mock impl (dev / tests) ────────────────────────────────────────────────\r\n\r\nexport class MockWebhooks implements WebhooksNamespace {\r\n private endpoints = new Map<string, WebhookEndpoint>();\r\n private nextId = 1;\r\n\r\n async register(input: RegisterWebhookInput): Promise<WebhookEndpoint> {\r\n validateInput(input);\r\n const id = `mock_wh_${this.nextId++}`;\r\n const endpoint: WebhookEndpoint = {\r\n id,\r\n url: input.url,\r\n events: input.events,\r\n hasSecret: !!input.secret,\r\n status: 'active',\r\n createdAt: new Date().toISOString(),\r\n };\r\n this.endpoints.set(id, endpoint);\r\n return endpoint;\r\n }\r\n\r\n async list(): Promise<WebhookEndpoint[]> {\r\n return [...this.endpoints.values()];\r\n }\r\n\r\n async unregister(id: string): Promise<{ ok: true }> {\r\n if (!this.endpoints.has(id)) {\r\n throw new NeetruError('not_found', `Webhook ${id} não encontrado`);\r\n }\r\n this.endpoints.delete(id);\r\n return { ok: true };\r\n }\r\n\r\n async test(id: string): Promise<WebhookTestResult> {\r\n if (!this.endpoints.has(id)) {\r\n throw new NeetruError('not_found', `Webhook ${id} não encontrado`);\r\n }\r\n return { ok: true, statusCode: 200, durationMs: 42 };\r\n }\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/webhooks.ts"],"names":["err","message"],"mappings":"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","file":"webhooks.cjs","sourcesContent":["/**\r\n * Erros tipados do SDK.\r\n *\r\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\r\n * por `.code` (string estável) sem parsing de message.\r\n */\r\n\r\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\r\nexport type NeetruErrorCode =\r\n | 'invalid_config'\r\n | 'missing_api_key'\r\n | 'unauthorized'\r\n | 'forbidden'\r\n | 'not_found'\r\n | 'rate_limited'\r\n | 'validation_failed'\r\n | 'network_error'\r\n | 'invalid_response'\r\n | 'server_error'\r\n | 'token_expired'\r\n | 'token_invalid_signature'\r\n | 'token_invalid_audience'\r\n | 'token_invalid_issuer'\r\n | 'unknown';\r\n\r\n/**\r\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\r\n *\r\n * @example\r\n * ```ts\r\n * try { await client.catalog.list(); }\r\n * catch (e) {\r\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\r\n * }\r\n * ```\r\n */\r\nexport class NeetruError extends Error {\r\n public readonly code: NeetruErrorCode | string;\r\n public readonly status?: number;\r\n public readonly requestId?: string;\r\n\r\n constructor(\r\n code: NeetruErrorCode | string,\r\n message: string,\r\n status?: number,\r\n requestId?: string,\r\n ) {\r\n super(message);\r\n this.name = 'NeetruError';\r\n this.code = code;\r\n this.status = status;\r\n this.requestId = requestId;\r\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\r\n Object.setPrototypeOf(this, NeetruError.prototype);\r\n }\r\n}\r\n","/**\r\n * HTTP transport interno do SDK.\r\n *\r\n * Responsabilidades:\r\n * - Construir URL absoluta a partir de `baseUrl` + path\r\n * - Injetar Bearer token quando `requireAuth=true`\r\n * - Mapear status HTTP → `NeetruError` com `code` estável\r\n * - Parse defensivo de JSON (não lança em body vazio em 204)\r\n * - Retry/backoff exponencial em `rate_limited` (429), `server_error` (5xx)\r\n * e `network_error` (timeout/falha de rede). Honra `Retry-After` quando\r\n * presente. Default 2 retries (3 tentativas no total). Caller opta-out\r\n * com `retries: 0`.\r\n */\r\nimport { NeetruError, type NeetruErrorCode } from './errors';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n/** Opções da request HTTP. */\r\nexport interface HttpRequestOptions {\r\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\r\n /** Path relativo (ex: `/api/v1/cli/catalog`). Concatenado a `baseUrl`. */\r\n path: string;\r\n /** Query string params (chave → valor primitivo). Valores `undefined` ignorados. */\r\n query?: Record<string, string | number | boolean | undefined>;\r\n /** Body JSON-serializável. Ignorado em GET/DELETE. */\r\n body?: unknown;\r\n /**\r\n * Se true, injeta `Authorization: Bearer <apiKey>`. Lança `missing_api_key`\r\n * se config.apiKey ausente. Default false.\r\n */\r\n requireAuth?: boolean;\r\n /** Cabeçalhos extras. */\r\n headers?: Record<string, string>;\r\n /**\r\n * Número de retries em códigos transientes (`rate_limited`, `server_error`,\r\n * `network_error`). Default 2 (= 3 tentativas total). Caller passa `0` pra\r\n * desativar (útil em operações não-idempotentes específicas).\r\n */\r\n retries?: number;\r\n}\r\n\r\nconst DEFAULT_RETRIES = 2;\r\nconst RETRYABLE_CODES = new Set<NeetruErrorCode>([\r\n 'rate_limited',\r\n 'server_error',\r\n 'network_error',\r\n]);\r\n\r\n/** Backoff exponencial com jitter ±20%. attempt: 0=primeira, 1=primeiro retry, ... */\r\nfunction backoffMs(attempt: number): number {\r\n const base = 200 * Math.pow(4, attempt); // 200ms, 800ms, 3.2s, ...\r\n const jitter = base * 0.2 * (Math.random() * 2 - 1);\r\n return Math.max(50, Math.round(base + jitter));\r\n}\r\n\r\n/**\r\n * Honra `Retry-After` header (segundos ou HTTP-date). Retorna ms ou null se\r\n * inválido. RFC 9110 §10.2.3.\r\n */\r\nfunction parseRetryAfter(value: string | null): number | null {\r\n if (!value) return null;\r\n const secs = Number(value);\r\n if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1000);\r\n const dateMs = Date.parse(value);\r\n if (Number.isFinite(dateMs)) {\r\n const delta = dateMs - Date.now();\r\n if (delta > 0) return delta;\r\n }\r\n return null;\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\n/** Mapeamento status → code estável do NeetruError. */\r\nfunction statusToCode(status: number): NeetruErrorCode {\r\n if (status === 401) return 'unauthorized';\r\n if (status === 403) return 'forbidden';\r\n if (status === 404) return 'not_found';\r\n if (status === 422 || status === 400) return 'validation_failed';\r\n if (status === 429) return 'rate_limited';\r\n if (status >= 500) return 'server_error';\r\n return 'unknown';\r\n}\r\n\r\nfunction buildUrl(baseUrl: string, path: string, query?: HttpRequestOptions['query']): string {\r\n // Trim trailing slash em base e leading em path pra evitar `//`.\r\n const base = baseUrl.replace(/\\/+$/, '');\r\n const p = path.startsWith('/') ? path : `/${path}`;\r\n const url = new URL(`${base}${p}`);\r\n if (query) {\r\n for (const [k, v] of Object.entries(query)) {\r\n if (v === undefined) continue;\r\n url.searchParams.set(k, String(v));\r\n }\r\n }\r\n return url.toString();\r\n}\r\n\r\n/** Parse JSON defensivo — retorna `undefined` em body vazio. */\r\nasync function safeJson(res: Response): Promise<unknown> {\r\n const text = await res.text();\r\n if (!text) return undefined;\r\n try {\r\n return JSON.parse(text);\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Executa request HTTP. Em sucesso retorna body parseado; em erro lança\r\n * `NeetruError` com `code` derivado do status. Aplica retry/backoff\r\n * automático em códigos transientes (rate_limited/server_error/network_error)\r\n * conforme `opts.retries` (default 2 = 3 tentativas).\r\n */\r\nexport async function httpRequest<T>(\r\n config: ResolvedConfig,\r\n opts: HttpRequestOptions,\r\n): Promise<T> {\r\n const method = opts.method ?? 'GET';\r\n const url = buildUrl(config.baseUrl, opts.path, opts.query);\r\n const maxRetries = opts.retries ?? DEFAULT_RETRIES;\r\n\r\n const headers: Record<string, string> = {\r\n accept: 'application/json',\r\n ...opts.headers,\r\n };\r\n\r\n if (opts.requireAuth) {\r\n if (!config.apiKey) {\r\n throw new NeetruError(\r\n 'missing_api_key',\r\n 'This operation requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.',\r\n );\r\n }\r\n headers.authorization = `Bearer ${config.apiKey}`;\r\n }\r\n\r\n // Body só é serializado uma vez — reusado entre tentativas.\r\n const bodyString =\r\n opts.body !== undefined && method !== 'GET' && method !== 'DELETE'\r\n ? JSON.stringify(opts.body)\r\n : undefined;\r\n if (bodyString !== undefined) {\r\n headers['content-type'] = 'application/json';\r\n }\r\n\r\n let lastError: NeetruError | null = null;\r\n\r\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\r\n const init: RequestInit = { method, headers };\r\n if (bodyString !== undefined) init.body = bodyString;\r\n // BUG-020 fix (2026-05-13): timeout default 30s. AbortSignal.timeout\r\n // requer Node 18+ ou browsers recentes.\r\n init.signal = AbortSignal.timeout(30_000);\r\n\r\n let res: Response;\r\n try {\r\n res = await config.fetch(url, init);\r\n } catch (err) {\r\n const message =\r\n err instanceof DOMException && err.name === 'TimeoutError'\r\n ? 'Network error: timeout after 30s'\r\n : `Network error: ${err instanceof Error ? err.message : 'fetch failed'}`;\r\n lastError = new NeetruError('network_error', message);\r\n if (attempt < maxRetries) {\r\n await sleep(backoffMs(attempt));\r\n continue;\r\n }\r\n throw lastError;\r\n }\r\n\r\n const requestId =\r\n res.headers.get('x-request-id') ?? res.headers.get('x-correlation-id') ?? undefined;\r\n\r\n if (res.ok) {\r\n const parsed = await safeJson(res);\r\n return parsed as T;\r\n }\r\n\r\n const body = (await safeJson(res)) as\r\n | { error?: { code?: string; message?: string } | string }\r\n | undefined;\r\n let code: string = statusToCode(res.status);\r\n let message = `HTTP ${res.status}`;\r\n if (body && typeof body === 'object' && 'error' in body) {\r\n const errField = body.error;\r\n if (typeof errField === 'string') {\r\n message = errField;\r\n } else if (errField && typeof errField === 'object') {\r\n if (typeof errField.code === 'string') code = errField.code;\r\n if (typeof errField.message === 'string') message = errField.message;\r\n }\r\n }\r\n const err = new NeetruError(code, message, res.status, requestId);\r\n lastError = err;\r\n\r\n const isRetryable = RETRYABLE_CODES.has(code as NeetruErrorCode);\r\n if (isRetryable && attempt < maxRetries) {\r\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\r\n const delay = retryAfter ?? backoffMs(attempt);\r\n await sleep(delay);\r\n continue;\r\n }\r\n throw err;\r\n }\r\n\r\n // Unreachable — loop sempre retorna ou lança. Safety net.\r\n throw lastError ?? new NeetruError('unknown', 'unexpected httpRequest exit');\r\n}\r\n","/**\r\n * Webhooks namespace (v1.2) — produtos SaaS registram endpoints HTTP no Core\r\n * pra receber notificações de eventos.\r\n *\r\n * Casos típicos:\r\n * - `subscription.activated` quando cliente conclui checkout\r\n * - `subscription.cancelled` / `subscription.payment_failed`\r\n * - `usage.quota_exceeded` quando produto bate teto mensal\r\n * - `account.suspended` quando staff Neetru suspende uma conta\r\n *\r\n * Pull-vs-push: o SDK existente é pull-only (`getQuota`, etc). Webhooks\r\n * fecham o gap pra eventos assíncronos sem o produto precisar fazer polling.\r\n *\r\n * Segurança:\r\n * - Endpoint do produto recebe HMAC SHA-256 em header `X-Neetru-Signature`\r\n * usando `secret` opcional do registro. Sem `secret`, header ausente —\r\n * produto deve usar HTTPS + IP allowlist.\r\n * - Replay protection: header `X-Neetru-Timestamp` (ms) — produto deve\r\n * rejeitar > 5min de skew.\r\n * - Retry: Core retenta 3x com backoff exponencial (1s, 5s, 25s) se 5xx\r\n * ou timeout. Após 3 falhas → marca endpoint `degraded` por 1h.\r\n *\r\n * Endpoints REST (em prod):\r\n * - `POST /api/sdk/v1/webhooks` — registra novo endpoint\r\n * - `GET /api/sdk/v1/webhooks` — lista endpoints do produto\r\n * - `DELETE /api/sdk/v1/webhooks/{id}` — remove endpoint\r\n * - `POST /api/sdk/v1/webhooks/{id}/test` — dispara evento de teste\r\n *\r\n * Mock em `NEETRU_ENV=dev`: tudo in-memory, sem rede.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n/** Eventos Neetru que produtos podem assinar. Lista expansível por minor bump. */\r\nexport type WebhookEvent =\r\n | 'subscription.activated'\r\n | 'subscription.cancelled'\r\n | 'subscription.payment_failed'\r\n | 'subscription.trial_ending'\r\n | 'usage.quota_exceeded'\r\n | 'account.suspended'\r\n | 'account.reactivated'\r\n | 'support.ticket_replied';\r\n\r\nexport interface WebhookEndpoint {\r\n id: string;\r\n url: string;\r\n events: WebhookEvent[];\r\n /** Quando true, `X-Neetru-Signature` é enviado em cada dispatch. */\r\n hasSecret: boolean;\r\n status: 'active' | 'degraded' | 'disabled';\r\n /** ISO timestamp do último dispatch bem-sucedido. */\r\n lastDeliveryAt?: string;\r\n /** Quantos dispatches falharam consecutivos (resetado em sucesso). */\r\n consecutiveFailures?: number;\r\n createdAt: string;\r\n}\r\n\r\nexport interface RegisterWebhookInput {\r\n url: string;\r\n events: WebhookEvent[];\r\n /**\r\n * Secret pra HMAC SHA-256 (mín 16 chars). Recomendado.\r\n * Quando ausente, dispatches vão sem assinatura — produto deve ter\r\n * IP allowlist ou outra defesa.\r\n */\r\n secret?: string;\r\n}\r\n\r\nexport interface WebhookTestResult {\r\n ok: boolean;\r\n statusCode?: number;\r\n durationMs?: number;\r\n error?: string;\r\n}\r\n\r\nexport interface WebhooksNamespace {\r\n /** Registra um novo endpoint. */\r\n register(input: RegisterWebhookInput): Promise<WebhookEndpoint>;\r\n /** Lista endpoints registrados pelo produto. */\r\n list(): Promise<WebhookEndpoint[]>;\r\n /** Remove um endpoint. */\r\n unregister(id: string): Promise<{ ok: true }>;\r\n /** Dispara evento de teste pra validar conectividade. */\r\n test(id: string): Promise<WebhookTestResult>;\r\n}\r\n\r\n/**\r\n * Verifica assinatura HMAC SHA-256 de payload de webhook recebido pelo\r\n * produto consumer. Constant-time compare pra resistir a timing attack.\r\n *\r\n * @param payload Corpo cru da request (string ou Buffer). NÃO use o objeto\r\n * parseado — JSON.stringify pode diferir do que foi assinado.\r\n * @param signature Header `X-Neetru-Signature` recebido (formato `sha256=<hex>`).\r\n * @param secret Secret registrado em `webhooks.register({ secret })`.\r\n * @returns true se assinatura confere, false caso contrário.\r\n *\r\n * @example\r\n * ```ts\r\n * // Express handler\r\n * app.post('/webhooks/neetru', express.raw({ type: 'application/json' }), (req, res) => {\r\n * const sig = req.header('X-Neetru-Signature');\r\n * if (!verifyWebhookSignature(req.body, sig, process.env.WEBHOOK_SECRET!)) {\r\n * return res.status(401).end();\r\n * }\r\n * const event = JSON.parse(req.body.toString('utf8'));\r\n * // ... handle event\r\n * res.json({ ok: true });\r\n * });\r\n * ```\r\n */\r\nexport function verifyWebhookSignature(\r\n payload: string | Uint8Array,\r\n signature: string | null | undefined,\r\n secret: string,\r\n): boolean {\r\n if (!signature || !secret) return false;\r\n // Aceita \"sha256=<hex>\" ou \"<hex>\" cru.\r\n const sigHex = signature.startsWith('sha256=') ? signature.slice(7) : signature;\r\n if (!/^[0-9a-f]+$/i.test(sigHex)) return false;\r\n\r\n // Crypto API: Node tem `node:crypto`, browsers têm WebCrypto. Aqui usamos\r\n // node:crypto (SDK roda majoritariamente server-side em produto Node). Se\r\n // o consumer for browser puro precisando verificar, basta importar o\r\n // namespace direto e usar WebCrypto — não é o caso típico, então não\r\n // pagamos o custo de bundle.\r\n let nodeCrypto: typeof import('node:crypto');\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-require-imports\r\n nodeCrypto = require('node:crypto');\r\n } catch {\r\n if (typeof console !== 'undefined') {\r\n console.warn(\r\n '[neetru-sdk] verifyWebhookSignature requires Node crypto. In browser, use WebCrypto subtle.verify directly.',\r\n );\r\n }\r\n return false;\r\n }\r\n\r\n const computed = nodeCrypto.createHmac('sha256', secret).update(payload).digest('hex');\r\n const a = Buffer.from(computed, 'hex');\r\n const b = Buffer.from(sigHex.toLowerCase(), 'hex');\r\n if (a.length !== b.length) return false;\r\n return nodeCrypto.timingSafeEqual(a, b);\r\n}\r\n\r\n// ─── HTTP impl ──────────────────────────────────────────────────────────────\r\n\r\nconst VALID_EVENTS: readonly WebhookEvent[] = [\r\n 'subscription.activated',\r\n 'subscription.cancelled',\r\n 'subscription.payment_failed',\r\n 'subscription.trial_ending',\r\n 'usage.quota_exceeded',\r\n 'account.suspended',\r\n 'account.reactivated',\r\n 'support.ticket_replied',\r\n];\r\n\r\nfunction toEndpoint(raw: unknown): WebhookEndpoint {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Webhook response is not an object');\r\n }\r\n const r = raw as Record<string, unknown>;\r\n if (typeof r.id !== 'string') {\r\n throw new NeetruError('invalid_response', 'Webhook missing id');\r\n }\r\n return {\r\n id: r.id,\r\n url: typeof r.url === 'string' ? r.url : '',\r\n events: Array.isArray(r.events)\r\n ? (r.events as unknown[]).filter((e): e is WebhookEvent =>\r\n VALID_EVENTS.includes(e as WebhookEvent),\r\n )\r\n : [],\r\n hasSecret: r.hasSecret === true,\r\n status:\r\n r.status === 'active' || r.status === 'degraded' || r.status === 'disabled'\r\n ? r.status\r\n : 'active',\r\n lastDeliveryAt: typeof r.lastDeliveryAt === 'string' ? r.lastDeliveryAt : undefined,\r\n consecutiveFailures:\r\n typeof r.consecutiveFailures === 'number' ? r.consecutiveFailures : undefined,\r\n createdAt: typeof r.createdAt === 'string' ? r.createdAt : new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction validateInput(input: RegisterWebhookInput): void {\r\n if (!input.url || typeof input.url !== 'string') {\r\n throw new NeetruError('validation_failed', 'url é obrigatória');\r\n }\r\n try {\r\n const parsed = new URL(input.url);\r\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\r\n throw new Error('invalid protocol');\r\n }\r\n // Em prod, http: é warning (não bloqueia) — testes locais podem usar\r\n } catch {\r\n throw new NeetruError('validation_failed', `url inválida: ${input.url}`);\r\n }\r\n if (!Array.isArray(input.events) || input.events.length === 0) {\r\n throw new NeetruError('validation_failed', 'events deve ter pelo menos 1 evento');\r\n }\r\n for (const ev of input.events) {\r\n if (!VALID_EVENTS.includes(ev)) {\r\n throw new NeetruError('validation_failed', `evento desconhecido: ${ev}`);\r\n }\r\n }\r\n if (input.secret !== undefined && input.secret.length < 16) {\r\n throw new NeetruError('validation_failed', 'secret deve ter ≥16 chars (recomendado 32+)');\r\n }\r\n}\r\n\r\nexport function createWebhooksNamespace(config: ResolvedConfig): WebhooksNamespace {\r\n return {\r\n async register(input) {\r\n validateInput(input);\r\n const raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/webhooks',\r\n body: input,\r\n requireAuth: true,\r\n });\r\n return toEndpoint(raw);\r\n },\r\n async list() {\r\n const raw = await httpRequest<{ endpoints?: unknown[] }>(config, {\r\n method: 'GET',\r\n path: '/api/sdk/v1/webhooks',\r\n requireAuth: true,\r\n });\r\n const list = Array.isArray(raw?.endpoints) ? raw.endpoints : [];\r\n return list.map(toEndpoint);\r\n },\r\n async unregister(id) {\r\n if (!id) throw new NeetruError('validation_failed', 'id obrigatório');\r\n await httpRequest<unknown>(config, {\r\n method: 'DELETE',\r\n path: `/api/sdk/v1/webhooks/${encodeURIComponent(id)}`,\r\n requireAuth: true,\r\n });\r\n return { ok: true };\r\n },\r\n async test(id) {\r\n if (!id) throw new NeetruError('validation_failed', 'id obrigatório');\r\n const raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: `/api/sdk/v1/webhooks/${encodeURIComponent(id)}/test`,\r\n requireAuth: true,\r\n });\r\n if (!raw || typeof raw !== 'object') {\r\n return { ok: false, error: 'invalid response' };\r\n }\r\n const r = raw as Record<string, unknown>;\r\n return {\r\n ok: r.ok === true,\r\n statusCode: typeof r.statusCode === 'number' ? r.statusCode : undefined,\r\n durationMs: typeof r.durationMs === 'number' ? r.durationMs : undefined,\r\n error: typeof r.error === 'string' ? r.error : undefined,\r\n };\r\n },\r\n };\r\n}\r\n\r\n// ─── Mock impl (dev / tests) ────────────────────────────────────────────────\r\n\r\nexport class MockWebhooks implements WebhooksNamespace {\r\n private endpoints = new Map<string, WebhookEndpoint>();\r\n private nextId = 1;\r\n\r\n async register(input: RegisterWebhookInput): Promise<WebhookEndpoint> {\r\n validateInput(input);\r\n const id = `mock_wh_${this.nextId++}`;\r\n const endpoint: WebhookEndpoint = {\r\n id,\r\n url: input.url,\r\n events: input.events,\r\n hasSecret: !!input.secret,\r\n status: 'active',\r\n createdAt: new Date().toISOString(),\r\n };\r\n this.endpoints.set(id, endpoint);\r\n return endpoint;\r\n }\r\n\r\n async list(): Promise<WebhookEndpoint[]> {\r\n return [...this.endpoints.values()];\r\n }\r\n\r\n async unregister(id: string): Promise<{ ok: true }> {\r\n if (!this.endpoints.has(id)) {\r\n throw new NeetruError('not_found', `Webhook ${id} não encontrado`);\r\n }\r\n this.endpoints.delete(id);\r\n return { ok: true };\r\n }\r\n\r\n async test(id: string): Promise<WebhookTestResult> {\r\n if (!this.endpoints.has(id)) {\r\n throw new NeetruError('not_found', `Webhook ${id} não encontrado`);\r\n }\r\n return { ok: true, statusCode: 200, durationMs: 42 };\r\n }\r\n}\r\n"]}
@@ -1,5 +1,5 @@
1
- export { n as MockWebhooks, R as RegisterWebhookInput, _ as WebhookEndpoint, $ as WebhookEvent, a0 as WebhookTestResult, a1 as WebhooksNamespace, a6 as createWebhooksNamespace, a8 as verifyWebhookSignature } from './types-Kmt4y1FQ.cjs';
2
- import './collection-ref-BBvTTXoG.cjs';
1
+ export { n as MockWebhooks, R as RegisterWebhookInput, $ as WebhookEndpoint, a0 as WebhookEvent, a1 as WebhookTestResult, a2 as WebhooksNamespace, a7 as createWebhooksNamespace, a9 as verifyWebhookSignature } from './types-DlDxttiG.cjs';
2
+ import './collection-ref-DqAAhuhX.cjs';
3
3
  import '@neetru/realtime-protocol';
4
4
  import 'drizzle-orm/node-postgres';
5
5
  import './errors.cjs';
@@ -1,5 +1,5 @@
1
- export { n as MockWebhooks, R as RegisterWebhookInput, _ as WebhookEndpoint, $ as WebhookEvent, a0 as WebhookTestResult, a1 as WebhooksNamespace, a6 as createWebhooksNamespace, a8 as verifyWebhookSignature } from './types-B1jylbMC.js';
2
- import './collection-ref-BBvTTXoG.js';
1
+ export { n as MockWebhooks, R as RegisterWebhookInput, $ as WebhookEndpoint, a0 as WebhookEvent, a1 as WebhookTestResult, a2 as WebhooksNamespace, a7 as createWebhooksNamespace, a9 as verifyWebhookSignature } from './types-CvTje138.js';
2
+ import './collection-ref-DqAAhuhX.js';
3
3
  import '@neetru/realtime-protocol';
4
4
  import 'drizzle-orm/node-postgres';
5
5
  import './errors.js';