@neetru/sdk 1.2.0 → 2.1.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 (77) hide show
  1. package/CHANGELOG.md +284 -244
  2. package/README.md +194 -194
  3. package/dist/auth.cjs +3740 -345
  4. package/dist/auth.cjs.map +1 -1
  5. package/dist/auth.d.cts +5 -1
  6. package/dist/auth.d.ts +5 -1
  7. package/dist/auth.mjs +3740 -345
  8. package/dist/auth.mjs.map +1 -1
  9. package/dist/catalog.cjs.map +1 -1
  10. package/dist/catalog.d.cts +5 -1
  11. package/dist/catalog.d.ts +5 -1
  12. package/dist/catalog.mjs.map +1 -1
  13. package/dist/checkout.cjs.map +1 -1
  14. package/dist/checkout.d.cts +5 -1
  15. package/dist/checkout.d.ts +5 -1
  16. package/dist/checkout.mjs.map +1 -1
  17. package/dist/collection-ref-BBvTTXoG.d.cts +423 -0
  18. package/dist/collection-ref-BBvTTXoG.d.ts +423 -0
  19. package/dist/db-react.cjs +136 -0
  20. package/dist/db-react.cjs.map +1 -0
  21. package/dist/db-react.d.cts +99 -0
  22. package/dist/db-react.d.ts +99 -0
  23. package/dist/db-react.mjs +112 -0
  24. package/dist/db-react.mjs.map +1 -0
  25. package/dist/db.cjs +3599 -131
  26. package/dist/db.cjs.map +1 -1
  27. package/dist/db.d.cts +5 -8
  28. package/dist/db.d.ts +5 -8
  29. package/dist/db.mjs +3596 -131
  30. package/dist/db.mjs.map +1 -1
  31. package/dist/entitlements.cjs.map +1 -1
  32. package/dist/entitlements.d.cts +5 -1
  33. package/dist/entitlements.d.ts +5 -1
  34. package/dist/entitlements.mjs.map +1 -1
  35. package/dist/errors.cjs.map +1 -1
  36. package/dist/errors.mjs.map +1 -1
  37. package/dist/index.cjs +3957 -342
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/index.d.cts +13 -6
  40. package/dist/index.d.ts +13 -6
  41. package/dist/index.mjs +3877 -263
  42. package/dist/index.mjs.map +1 -1
  43. package/dist/mocks.cjs +183 -7
  44. package/dist/mocks.cjs.map +1 -1
  45. package/dist/mocks.d.cts +18 -5
  46. package/dist/mocks.d.ts +18 -5
  47. package/dist/mocks.mjs +183 -7
  48. package/dist/mocks.mjs.map +1 -1
  49. package/dist/notifications.cjs.map +1 -1
  50. package/dist/notifications.d.cts +5 -1
  51. package/dist/notifications.d.ts +5 -1
  52. package/dist/notifications.mjs.map +1 -1
  53. package/dist/react.cjs.map +1 -1
  54. package/dist/react.d.cts +5 -1
  55. package/dist/react.d.ts +5 -1
  56. package/dist/react.mjs.map +1 -1
  57. package/dist/support.cjs.map +1 -1
  58. package/dist/support.d.cts +5 -1
  59. package/dist/support.d.ts +5 -1
  60. package/dist/support.mjs.map +1 -1
  61. package/dist/telemetry.cjs.map +1 -1
  62. package/dist/telemetry.d.cts +5 -1
  63. package/dist/telemetry.d.ts +5 -1
  64. package/dist/telemetry.mjs.map +1 -1
  65. package/dist/types-B1jylbMC.d.ts +1364 -0
  66. package/dist/types-Kmt4y1FQ.d.cts +1364 -0
  67. package/dist/usage.cjs.map +1 -1
  68. package/dist/usage.d.cts +5 -1
  69. package/dist/usage.d.ts +5 -1
  70. package/dist/usage.mjs.map +1 -1
  71. package/dist/webhooks.cjs.map +1 -1
  72. package/dist/webhooks.d.cts +5 -1
  73. package/dist/webhooks.d.ts +5 -1
  74. package/dist/webhooks.mjs.map +1 -1
  75. package/package.json +133 -111
  76. package/dist/types-CQAfwqUS.d.cts +0 -654
  77. package/dist/types-CQAfwqUS.d.ts +0 -654
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/entitlements.ts"],"names":["err","message"],"mappings":"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","file":"entitlements.cjs","sourcesContent":["/**\n * Erros tipados do SDK.\n *\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\n * por `.code` (string estável) sem parsing de message.\n */\n\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\nexport type NeetruErrorCode =\n | 'invalid_config'\n | 'missing_api_key'\n | 'unauthorized'\n | 'forbidden'\n | 'not_found'\n | 'rate_limited'\n | 'validation_failed'\n | 'network_error'\n | 'invalid_response'\n | 'server_error'\n | 'unknown';\n\n/**\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\n *\n * @example\n * ```ts\n * try { await client.catalog.list(); }\n * catch (e) {\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\n * }\n * ```\n */\nexport class NeetruError extends Error {\n public readonly code: NeetruErrorCode | string;\n public readonly status?: number;\n public readonly requestId?: string;\n\n constructor(\n code: NeetruErrorCode | string,\n message: string,\n status?: number,\n requestId?: string,\n ) {\n super(message);\n this.name = 'NeetruError';\n this.code = code;\n this.status = status;\n this.requestId = requestId;\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\n Object.setPrototypeOf(this, NeetruError.prototype);\n }\n}\n","/**\n * HTTP transport interno do SDK.\n *\n * Responsabilidades:\n * - Construir URL absoluta a partir de `baseUrl` + path\n * - Injetar Bearer token quando `requireAuth=true`\n * - Mapear status HTTP → `NeetruError` com `code` estável\n * - Parse defensivo de JSON (não lança em body vazio em 204)\n * - Retry/backoff exponencial em `rate_limited` (429), `server_error` (5xx)\n * e `network_error` (timeout/falha de rede). Honra `Retry-After` quando\n * presente. Default 2 retries (3 tentativas no total). Caller opta-out\n * com `retries: 0`.\n */\nimport { NeetruError, type NeetruErrorCode } from './errors';\nimport type { ResolvedConfig } from './types';\n\n/** Opções da request HTTP. */\nexport interface HttpRequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n /** Path relativo (ex: `/api/v1/cli/catalog`). Concatenado a `baseUrl`. */\n path: string;\n /** Query string params (chave → valor primitivo). Valores `undefined` ignorados. */\n query?: Record<string, string | number | boolean | undefined>;\n /** Body JSON-serializável. Ignorado em GET/DELETE. */\n body?: unknown;\n /**\n * Se true, injeta `Authorization: Bearer <apiKey>`. Lança `missing_api_key`\n * se config.apiKey ausente. Default false.\n */\n requireAuth?: boolean;\n /** Cabeçalhos extras. */\n headers?: Record<string, string>;\n /**\n * Número de retries em códigos transientes (`rate_limited`, `server_error`,\n * `network_error`). Default 2 (= 3 tentativas total). Caller passa `0` pra\n * desativar (útil em operações não-idempotentes específicas).\n */\n retries?: number;\n}\n\nconst DEFAULT_RETRIES = 2;\nconst RETRYABLE_CODES = new Set<NeetruErrorCode>([\n 'rate_limited',\n 'server_error',\n 'network_error',\n]);\n\n/** Backoff exponencial com jitter ±20%. attempt: 0=primeira, 1=primeiro retry, ... */\nfunction backoffMs(attempt: number): number {\n const base = 200 * Math.pow(4, attempt); // 200ms, 800ms, 3.2s, ...\n const jitter = base * 0.2 * (Math.random() * 2 - 1);\n return Math.max(50, Math.round(base + jitter));\n}\n\n/**\n * Honra `Retry-After` header (segundos ou HTTP-date). Retorna ms ou null se\n * inválido. RFC 9110 §10.2.3.\n */\nfunction parseRetryAfter(value: string | null): number | null {\n if (!value) return null;\n const secs = Number(value);\n if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1000);\n const dateMs = Date.parse(value);\n if (Number.isFinite(dateMs)) {\n const delta = dateMs - Date.now();\n if (delta > 0) return delta;\n }\n return null;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Mapeamento status → code estável do NeetruError. */\nfunction statusToCode(status: number): NeetruErrorCode {\n if (status === 401) return 'unauthorized';\n if (status === 403) return 'forbidden';\n if (status === 404) return 'not_found';\n if (status === 422 || status === 400) return 'validation_failed';\n if (status === 429) return 'rate_limited';\n if (status >= 500) return 'server_error';\n return 'unknown';\n}\n\nfunction buildUrl(baseUrl: string, path: string, query?: HttpRequestOptions['query']): string {\n // Trim trailing slash em base e leading em path pra evitar `//`.\n const base = baseUrl.replace(/\\/+$/, '');\n const p = path.startsWith('/') ? path : `/${path}`;\n const url = new URL(`${base}${p}`);\n if (query) {\n for (const [k, v] of Object.entries(query)) {\n if (v === undefined) continue;\n url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n}\n\n/** Parse JSON defensivo — retorna `undefined` em body vazio. */\nasync function safeJson(res: Response): Promise<unknown> {\n const text = await res.text();\n if (!text) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Executa request HTTP. Em sucesso retorna body parseado; em erro lança\n * `NeetruError` com `code` derivado do status. Aplica retry/backoff\n * automático em códigos transientes (rate_limited/server_error/network_error)\n * conforme `opts.retries` (default 2 = 3 tentativas).\n */\nexport async function httpRequest<T>(\n config: ResolvedConfig,\n opts: HttpRequestOptions,\n): Promise<T> {\n const method = opts.method ?? 'GET';\n const url = buildUrl(config.baseUrl, opts.path, opts.query);\n const maxRetries = opts.retries ?? DEFAULT_RETRIES;\n\n const headers: Record<string, string> = {\n accept: 'application/json',\n ...opts.headers,\n };\n\n if (opts.requireAuth) {\n if (!config.apiKey) {\n throw new NeetruError(\n 'missing_api_key',\n 'This operation requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.',\n );\n }\n headers.authorization = `Bearer ${config.apiKey}`;\n }\n\n // Body só é serializado uma vez — reusado entre tentativas.\n const bodyString =\n opts.body !== undefined && method !== 'GET' && method !== 'DELETE'\n ? JSON.stringify(opts.body)\n : undefined;\n if (bodyString !== undefined) {\n headers['content-type'] = 'application/json';\n }\n\n let lastError: NeetruError | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const init: RequestInit = { method, headers };\n if (bodyString !== undefined) init.body = bodyString;\n // BUG-020 fix (2026-05-13): timeout default 30s. AbortSignal.timeout\n // requer Node 18+ ou browsers recentes.\n init.signal = AbortSignal.timeout(30_000);\n\n let res: Response;\n try {\n res = await config.fetch(url, init);\n } catch (err) {\n const message =\n err instanceof DOMException && err.name === 'TimeoutError'\n ? 'Network error: timeout after 30s'\n : `Network error: ${err instanceof Error ? err.message : 'fetch failed'}`;\n lastError = new NeetruError('network_error', message);\n if (attempt < maxRetries) {\n await sleep(backoffMs(attempt));\n continue;\n }\n throw lastError;\n }\n\n const requestId =\n res.headers.get('x-request-id') ?? res.headers.get('x-correlation-id') ?? undefined;\n\n if (res.ok) {\n const parsed = await safeJson(res);\n return parsed as T;\n }\n\n const body = (await safeJson(res)) as\n | { error?: { code?: string; message?: string } | string }\n | undefined;\n let code: string = statusToCode(res.status);\n let message = `HTTP ${res.status}`;\n if (body && typeof body === 'object' && 'error' in body) {\n const errField = body.error;\n if (typeof errField === 'string') {\n message = errField;\n } else if (errField && typeof errField === 'object') {\n if (typeof errField.code === 'string') code = errField.code;\n if (typeof errField.message === 'string') message = errField.message;\n }\n }\n const err = new NeetruError(code, message, res.status, requestId);\n lastError = err;\n\n const isRetryable = RETRYABLE_CODES.has(code as NeetruErrorCode);\n if (isRetryable && attempt < maxRetries) {\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\n const delay = retryAfter ?? backoffMs(attempt);\n await sleep(delay);\n continue;\n }\n throw err;\n }\n\n // Unreachable — loop sempre retorna ou lança. Safety net.\n throw lastError ?? new NeetruError('unknown', 'unexpected httpRequest exit');\n}\n","/**\n * Entitlements — verifica se o portador da apiKey pode usar feature X\n * do produto Y.\n *\n * Endpoint: `GET /api/v1/sdk/entitlements/check?slug=X&feature=Y`\n * Schema Firestore consultado pelo backend:\n * `entitlements/{userId}/products/{slug}` → `{ features: string[], plan, expiresAt }`\n *\n * v1.2 introduz cache LRU em memória (default 60s TTL, 100 entries). Cada\n * (productSlug, feature) pareando o `apiKey` é cacheado. Caller pode invalidar\n * via `__resetCache()` (test helper) ou via `cacheBust: true` na chamada.\n */\nimport { NeetruError } from './errors';\nimport { httpRequest } from './http';\nimport type { EntitlementCheck, ResolvedConfig } from './types';\n\ninterface RawEntitlementCheck {\n allowed?: boolean;\n productSlug?: string;\n feature?: string;\n reason?: string;\n}\n\nfunction toEntitlementCheck(raw: unknown): EntitlementCheck {\n if (!raw || typeof raw !== 'object') {\n throw new NeetruError('invalid_response', 'Entitlement response is not an object');\n }\n const r = raw as RawEntitlementCheck;\n if (typeof r.allowed !== 'boolean') {\n throw new NeetruError('invalid_response', 'Entitlement response missing `allowed` boolean');\n }\n return {\n allowed: r.allowed,\n productSlug: typeof r.productSlug === 'string' ? r.productSlug : '',\n feature: typeof r.feature === 'string' ? r.feature : '',\n reason: typeof r.reason === 'string' ? r.reason : undefined,\n };\n}\n\n/** TTL default — 60s. Pareando com tempo de propagação típico de mudança de plano. */\nconst CACHE_TTL_MS = 60_000;\n/** Máx entries por instância de namespace — LRU. */\nconst CACHE_MAX = 100;\n\ninterface CacheEntry {\n value: EntitlementCheck;\n expiresAt: number;\n}\n\nexport interface EntitlementsCheckOptions {\n /** Se true, ignora cache local e força ida ao servidor. Default false. */\n cacheBust?: boolean;\n}\n\nexport function createEntitlementsNamespace(config: ResolvedConfig) {\n // Map preserva ordem de inserção — readequa LRU manualmente em hit.\n const cache = new Map<string, CacheEntry>();\n\n function cacheKey(productSlug: string, feature: string): string {\n return `${productSlug}::${feature}`;\n }\n\n function readCache(key: string): EntitlementCheck | null {\n const entry = cache.get(key);\n if (!entry) return null;\n if (entry.expiresAt < Date.now()) {\n cache.delete(key);\n return null;\n }\n // LRU touch: reinsere no final.\n cache.delete(key);\n cache.set(key, entry);\n return entry.value;\n }\n\n function writeCache(key: string, value: EntitlementCheck): void {\n if (cache.size >= CACHE_MAX) {\n const oldest = cache.keys().next().value;\n if (oldest !== undefined) cache.delete(oldest);\n }\n cache.set(key, { value, expiresAt: Date.now() + CACHE_TTL_MS });\n }\n\n async function checkDetailed(\n productSlug: string,\n feature: string,\n opts: EntitlementsCheckOptions = {},\n ): Promise<EntitlementCheck> {\n if (!productSlug) throw new NeetruError('validation_failed', 'productSlug is required');\n if (!feature) throw new NeetruError('validation_failed', 'feature is required');\n\n const key = cacheKey(productSlug, feature);\n if (!opts.cacheBust) {\n const cached = readCache(key);\n if (cached) return cached;\n }\n\n const raw = await httpRequest<RawEntitlementCheck>(config, {\n method: 'GET',\n path: '/api/v1/sdk/entitlements/check',\n query: { slug: productSlug, feature },\n requireAuth: true,\n });\n const result = toEntitlementCheck(raw);\n writeCache(key, result);\n return result;\n }\n\n return {\n /**\n * Verifica se o caller pode usar `feature` no produto `productSlug`.\n * Retorno simples: `true` libera, `false` bloqueia. Cache 60s automático.\n *\n * Use `checkDetailed` se precisar do `reason` pra mensagem de upgrade.\n */\n async check(\n productSlug: string,\n feature: string,\n opts?: EntitlementsCheckOptions,\n ): Promise<boolean> {\n const result = await checkDetailed(productSlug, feature, opts);\n return result.allowed;\n },\n checkDetailed,\n /** Test helper: limpa o cache LRU. */\n __resetCache(): void {\n cache.clear();\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/entitlements.ts"],"names":["err","message"],"mappings":"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","file":"entitlements.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 * Entitlements — verifica se o portador da apiKey pode usar feature X\r\n * do produto Y.\r\n *\r\n * Endpoint: `GET /api/v1/sdk/entitlements/check?slug=X&feature=Y`\r\n * Schema Firestore consultado pelo backend:\r\n * `entitlements/{userId}/products/{slug}` → `{ features: string[], plan, expiresAt }`\r\n *\r\n * v1.2 introduz cache LRU em memória (default 60s TTL, 100 entries). Cada\r\n * (productSlug, feature) pareando o `apiKey` é cacheado. Caller pode invalidar\r\n * via `__resetCache()` (test helper) ou via `cacheBust: true` na chamada.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type { EntitlementCheck, ResolvedConfig } from './types';\r\n\r\ninterface RawEntitlementCheck {\r\n allowed?: boolean;\r\n productSlug?: string;\r\n feature?: string;\r\n reason?: string;\r\n}\r\n\r\nfunction toEntitlementCheck(raw: unknown): EntitlementCheck {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Entitlement response is not an object');\r\n }\r\n const r = raw as RawEntitlementCheck;\r\n if (typeof r.allowed !== 'boolean') {\r\n throw new NeetruError('invalid_response', 'Entitlement response missing `allowed` boolean');\r\n }\r\n return {\r\n allowed: r.allowed,\r\n productSlug: typeof r.productSlug === 'string' ? r.productSlug : '',\r\n feature: typeof r.feature === 'string' ? r.feature : '',\r\n reason: typeof r.reason === 'string' ? r.reason : undefined,\r\n };\r\n}\r\n\r\n/** TTL default — 60s. Pareando com tempo de propagação típico de mudança de plano. */\r\nconst CACHE_TTL_MS = 60_000;\r\n/** Máx entries por instância de namespace — LRU. */\r\nconst CACHE_MAX = 100;\r\n\r\ninterface CacheEntry {\r\n value: EntitlementCheck;\r\n expiresAt: number;\r\n}\r\n\r\nexport interface EntitlementsCheckOptions {\r\n /** Se true, ignora cache local e força ida ao servidor. Default false. */\r\n cacheBust?: boolean;\r\n}\r\n\r\nexport function createEntitlementsNamespace(config: ResolvedConfig) {\r\n // Map preserva ordem de inserção — readequa LRU manualmente em hit.\r\n const cache = new Map<string, CacheEntry>();\r\n\r\n function cacheKey(productSlug: string, feature: string): string {\r\n return `${productSlug}::${feature}`;\r\n }\r\n\r\n function readCache(key: string): EntitlementCheck | null {\r\n const entry = cache.get(key);\r\n if (!entry) return null;\r\n if (entry.expiresAt < Date.now()) {\r\n cache.delete(key);\r\n return null;\r\n }\r\n // LRU touch: reinsere no final.\r\n cache.delete(key);\r\n cache.set(key, entry);\r\n return entry.value;\r\n }\r\n\r\n function writeCache(key: string, value: EntitlementCheck): void {\r\n if (cache.size >= CACHE_MAX) {\r\n const oldest = cache.keys().next().value;\r\n if (oldest !== undefined) cache.delete(oldest);\r\n }\r\n cache.set(key, { value, expiresAt: Date.now() + CACHE_TTL_MS });\r\n }\r\n\r\n async function checkDetailed(\r\n productSlug: string,\r\n feature: string,\r\n opts: EntitlementsCheckOptions = {},\r\n ): Promise<EntitlementCheck> {\r\n if (!productSlug) throw new NeetruError('validation_failed', 'productSlug is required');\r\n if (!feature) throw new NeetruError('validation_failed', 'feature is required');\r\n\r\n const key = cacheKey(productSlug, feature);\r\n if (!opts.cacheBust) {\r\n const cached = readCache(key);\r\n if (cached) return cached;\r\n }\r\n\r\n const raw = await httpRequest<RawEntitlementCheck>(config, {\r\n method: 'GET',\r\n path: '/api/v1/sdk/entitlements/check',\r\n query: { slug: productSlug, feature },\r\n requireAuth: true,\r\n });\r\n const result = toEntitlementCheck(raw);\r\n writeCache(key, result);\r\n return result;\r\n }\r\n\r\n return {\r\n /**\r\n * Verifica se o caller pode usar `feature` no produto `productSlug`.\r\n * Retorno simples: `true` libera, `false` bloqueia. Cache 60s automático.\r\n *\r\n * Use `checkDetailed` se precisar do `reason` pra mensagem de upgrade.\r\n */\r\n async check(\r\n productSlug: string,\r\n feature: string,\r\n opts?: EntitlementsCheckOptions,\r\n ): Promise<boolean> {\r\n const result = await checkDetailed(productSlug, feature, opts);\r\n return result.allowed;\r\n },\r\n checkDetailed,\r\n /** Test helper: limpa o cache LRU. */\r\n __resetCache(): void {\r\n cache.clear();\r\n },\r\n };\r\n}\r\n"]}
@@ -1,4 +1,8 @@
1
- import { x as ResolvedConfig, E as EntitlementCheck } from './types-CQAfwqUS.cjs';
1
+ import { G as ResolvedConfig, E as EntitlementCheck } from './types-Kmt4y1FQ.cjs';
2
+ import './collection-ref-BBvTTXoG.cjs';
3
+ import '@neetru/realtime-protocol';
4
+ import 'drizzle-orm/node-postgres';
5
+ import './errors.cjs';
2
6
 
3
7
  interface EntitlementsCheckOptions {
4
8
  /** Se true, ignora cache local e força ida ao servidor. Default false. */
@@ -1,4 +1,8 @@
1
- import { x as ResolvedConfig, E as EntitlementCheck } from './types-CQAfwqUS.js';
1
+ import { G as ResolvedConfig, E as EntitlementCheck } from './types-B1jylbMC.js';
2
+ import './collection-ref-BBvTTXoG.js';
3
+ import '@neetru/realtime-protocol';
4
+ import 'drizzle-orm/node-postgres';
5
+ import './errors.js';
2
6
 
3
7
  interface EntitlementsCheckOptions {
4
8
  /** Se true, ignora cache local e força ida ao servidor. Default false. */
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/entitlements.ts"],"names":["err","message"],"mappings":"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","file":"entitlements.mjs","sourcesContent":["/**\n * Erros tipados do SDK.\n *\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\n * por `.code` (string estável) sem parsing de message.\n */\n\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\nexport type NeetruErrorCode =\n | 'invalid_config'\n | 'missing_api_key'\n | 'unauthorized'\n | 'forbidden'\n | 'not_found'\n | 'rate_limited'\n | 'validation_failed'\n | 'network_error'\n | 'invalid_response'\n | 'server_error'\n | 'unknown';\n\n/**\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\n *\n * @example\n * ```ts\n * try { await client.catalog.list(); }\n * catch (e) {\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\n * }\n * ```\n */\nexport class NeetruError extends Error {\n public readonly code: NeetruErrorCode | string;\n public readonly status?: number;\n public readonly requestId?: string;\n\n constructor(\n code: NeetruErrorCode | string,\n message: string,\n status?: number,\n requestId?: string,\n ) {\n super(message);\n this.name = 'NeetruError';\n this.code = code;\n this.status = status;\n this.requestId = requestId;\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\n Object.setPrototypeOf(this, NeetruError.prototype);\n }\n}\n","/**\n * HTTP transport interno do SDK.\n *\n * Responsabilidades:\n * - Construir URL absoluta a partir de `baseUrl` + path\n * - Injetar Bearer token quando `requireAuth=true`\n * - Mapear status HTTP → `NeetruError` com `code` estável\n * - Parse defensivo de JSON (não lança em body vazio em 204)\n * - Retry/backoff exponencial em `rate_limited` (429), `server_error` (5xx)\n * e `network_error` (timeout/falha de rede). Honra `Retry-After` quando\n * presente. Default 2 retries (3 tentativas no total). Caller opta-out\n * com `retries: 0`.\n */\nimport { NeetruError, type NeetruErrorCode } from './errors';\nimport type { ResolvedConfig } from './types';\n\n/** Opções da request HTTP. */\nexport interface HttpRequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n /** Path relativo (ex: `/api/v1/cli/catalog`). Concatenado a `baseUrl`. */\n path: string;\n /** Query string params (chave → valor primitivo). Valores `undefined` ignorados. */\n query?: Record<string, string | number | boolean | undefined>;\n /** Body JSON-serializável. Ignorado em GET/DELETE. */\n body?: unknown;\n /**\n * Se true, injeta `Authorization: Bearer <apiKey>`. Lança `missing_api_key`\n * se config.apiKey ausente. Default false.\n */\n requireAuth?: boolean;\n /** Cabeçalhos extras. */\n headers?: Record<string, string>;\n /**\n * Número de retries em códigos transientes (`rate_limited`, `server_error`,\n * `network_error`). Default 2 (= 3 tentativas total). Caller passa `0` pra\n * desativar (útil em operações não-idempotentes específicas).\n */\n retries?: number;\n}\n\nconst DEFAULT_RETRIES = 2;\nconst RETRYABLE_CODES = new Set<NeetruErrorCode>([\n 'rate_limited',\n 'server_error',\n 'network_error',\n]);\n\n/** Backoff exponencial com jitter ±20%. attempt: 0=primeira, 1=primeiro retry, ... */\nfunction backoffMs(attempt: number): number {\n const base = 200 * Math.pow(4, attempt); // 200ms, 800ms, 3.2s, ...\n const jitter = base * 0.2 * (Math.random() * 2 - 1);\n return Math.max(50, Math.round(base + jitter));\n}\n\n/**\n * Honra `Retry-After` header (segundos ou HTTP-date). Retorna ms ou null se\n * inválido. RFC 9110 §10.2.3.\n */\nfunction parseRetryAfter(value: string | null): number | null {\n if (!value) return null;\n const secs = Number(value);\n if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1000);\n const dateMs = Date.parse(value);\n if (Number.isFinite(dateMs)) {\n const delta = dateMs - Date.now();\n if (delta > 0) return delta;\n }\n return null;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Mapeamento status → code estável do NeetruError. */\nfunction statusToCode(status: number): NeetruErrorCode {\n if (status === 401) return 'unauthorized';\n if (status === 403) return 'forbidden';\n if (status === 404) return 'not_found';\n if (status === 422 || status === 400) return 'validation_failed';\n if (status === 429) return 'rate_limited';\n if (status >= 500) return 'server_error';\n return 'unknown';\n}\n\nfunction buildUrl(baseUrl: string, path: string, query?: HttpRequestOptions['query']): string {\n // Trim trailing slash em base e leading em path pra evitar `//`.\n const base = baseUrl.replace(/\\/+$/, '');\n const p = path.startsWith('/') ? path : `/${path}`;\n const url = new URL(`${base}${p}`);\n if (query) {\n for (const [k, v] of Object.entries(query)) {\n if (v === undefined) continue;\n url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n}\n\n/** Parse JSON defensivo — retorna `undefined` em body vazio. */\nasync function safeJson(res: Response): Promise<unknown> {\n const text = await res.text();\n if (!text) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Executa request HTTP. Em sucesso retorna body parseado; em erro lança\n * `NeetruError` com `code` derivado do status. Aplica retry/backoff\n * automático em códigos transientes (rate_limited/server_error/network_error)\n * conforme `opts.retries` (default 2 = 3 tentativas).\n */\nexport async function httpRequest<T>(\n config: ResolvedConfig,\n opts: HttpRequestOptions,\n): Promise<T> {\n const method = opts.method ?? 'GET';\n const url = buildUrl(config.baseUrl, opts.path, opts.query);\n const maxRetries = opts.retries ?? DEFAULT_RETRIES;\n\n const headers: Record<string, string> = {\n accept: 'application/json',\n ...opts.headers,\n };\n\n if (opts.requireAuth) {\n if (!config.apiKey) {\n throw new NeetruError(\n 'missing_api_key',\n 'This operation requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.',\n );\n }\n headers.authorization = `Bearer ${config.apiKey}`;\n }\n\n // Body só é serializado uma vez — reusado entre tentativas.\n const bodyString =\n opts.body !== undefined && method !== 'GET' && method !== 'DELETE'\n ? JSON.stringify(opts.body)\n : undefined;\n if (bodyString !== undefined) {\n headers['content-type'] = 'application/json';\n }\n\n let lastError: NeetruError | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const init: RequestInit = { method, headers };\n if (bodyString !== undefined) init.body = bodyString;\n // BUG-020 fix (2026-05-13): timeout default 30s. AbortSignal.timeout\n // requer Node 18+ ou browsers recentes.\n init.signal = AbortSignal.timeout(30_000);\n\n let res: Response;\n try {\n res = await config.fetch(url, init);\n } catch (err) {\n const message =\n err instanceof DOMException && err.name === 'TimeoutError'\n ? 'Network error: timeout after 30s'\n : `Network error: ${err instanceof Error ? err.message : 'fetch failed'}`;\n lastError = new NeetruError('network_error', message);\n if (attempt < maxRetries) {\n await sleep(backoffMs(attempt));\n continue;\n }\n throw lastError;\n }\n\n const requestId =\n res.headers.get('x-request-id') ?? res.headers.get('x-correlation-id') ?? undefined;\n\n if (res.ok) {\n const parsed = await safeJson(res);\n return parsed as T;\n }\n\n const body = (await safeJson(res)) as\n | { error?: { code?: string; message?: string } | string }\n | undefined;\n let code: string = statusToCode(res.status);\n let message = `HTTP ${res.status}`;\n if (body && typeof body === 'object' && 'error' in body) {\n const errField = body.error;\n if (typeof errField === 'string') {\n message = errField;\n } else if (errField && typeof errField === 'object') {\n if (typeof errField.code === 'string') code = errField.code;\n if (typeof errField.message === 'string') message = errField.message;\n }\n }\n const err = new NeetruError(code, message, res.status, requestId);\n lastError = err;\n\n const isRetryable = RETRYABLE_CODES.has(code as NeetruErrorCode);\n if (isRetryable && attempt < maxRetries) {\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\n const delay = retryAfter ?? backoffMs(attempt);\n await sleep(delay);\n continue;\n }\n throw err;\n }\n\n // Unreachable — loop sempre retorna ou lança. Safety net.\n throw lastError ?? new NeetruError('unknown', 'unexpected httpRequest exit');\n}\n","/**\n * Entitlements — verifica se o portador da apiKey pode usar feature X\n * do produto Y.\n *\n * Endpoint: `GET /api/v1/sdk/entitlements/check?slug=X&feature=Y`\n * Schema Firestore consultado pelo backend:\n * `entitlements/{userId}/products/{slug}` → `{ features: string[], plan, expiresAt }`\n *\n * v1.2 introduz cache LRU em memória (default 60s TTL, 100 entries). Cada\n * (productSlug, feature) pareando o `apiKey` é cacheado. Caller pode invalidar\n * via `__resetCache()` (test helper) ou via `cacheBust: true` na chamada.\n */\nimport { NeetruError } from './errors';\nimport { httpRequest } from './http';\nimport type { EntitlementCheck, ResolvedConfig } from './types';\n\ninterface RawEntitlementCheck {\n allowed?: boolean;\n productSlug?: string;\n feature?: string;\n reason?: string;\n}\n\nfunction toEntitlementCheck(raw: unknown): EntitlementCheck {\n if (!raw || typeof raw !== 'object') {\n throw new NeetruError('invalid_response', 'Entitlement response is not an object');\n }\n const r = raw as RawEntitlementCheck;\n if (typeof r.allowed !== 'boolean') {\n throw new NeetruError('invalid_response', 'Entitlement response missing `allowed` boolean');\n }\n return {\n allowed: r.allowed,\n productSlug: typeof r.productSlug === 'string' ? r.productSlug : '',\n feature: typeof r.feature === 'string' ? r.feature : '',\n reason: typeof r.reason === 'string' ? r.reason : undefined,\n };\n}\n\n/** TTL default — 60s. Pareando com tempo de propagação típico de mudança de plano. */\nconst CACHE_TTL_MS = 60_000;\n/** Máx entries por instância de namespace — LRU. */\nconst CACHE_MAX = 100;\n\ninterface CacheEntry {\n value: EntitlementCheck;\n expiresAt: number;\n}\n\nexport interface EntitlementsCheckOptions {\n /** Se true, ignora cache local e força ida ao servidor. Default false. */\n cacheBust?: boolean;\n}\n\nexport function createEntitlementsNamespace(config: ResolvedConfig) {\n // Map preserva ordem de inserção — readequa LRU manualmente em hit.\n const cache = new Map<string, CacheEntry>();\n\n function cacheKey(productSlug: string, feature: string): string {\n return `${productSlug}::${feature}`;\n }\n\n function readCache(key: string): EntitlementCheck | null {\n const entry = cache.get(key);\n if (!entry) return null;\n if (entry.expiresAt < Date.now()) {\n cache.delete(key);\n return null;\n }\n // LRU touch: reinsere no final.\n cache.delete(key);\n cache.set(key, entry);\n return entry.value;\n }\n\n function writeCache(key: string, value: EntitlementCheck): void {\n if (cache.size >= CACHE_MAX) {\n const oldest = cache.keys().next().value;\n if (oldest !== undefined) cache.delete(oldest);\n }\n cache.set(key, { value, expiresAt: Date.now() + CACHE_TTL_MS });\n }\n\n async function checkDetailed(\n productSlug: string,\n feature: string,\n opts: EntitlementsCheckOptions = {},\n ): Promise<EntitlementCheck> {\n if (!productSlug) throw new NeetruError('validation_failed', 'productSlug is required');\n if (!feature) throw new NeetruError('validation_failed', 'feature is required');\n\n const key = cacheKey(productSlug, feature);\n if (!opts.cacheBust) {\n const cached = readCache(key);\n if (cached) return cached;\n }\n\n const raw = await httpRequest<RawEntitlementCheck>(config, {\n method: 'GET',\n path: '/api/v1/sdk/entitlements/check',\n query: { slug: productSlug, feature },\n requireAuth: true,\n });\n const result = toEntitlementCheck(raw);\n writeCache(key, result);\n return result;\n }\n\n return {\n /**\n * Verifica se o caller pode usar `feature` no produto `productSlug`.\n * Retorno simples: `true` libera, `false` bloqueia. Cache 60s automático.\n *\n * Use `checkDetailed` se precisar do `reason` pra mensagem de upgrade.\n */\n async check(\n productSlug: string,\n feature: string,\n opts?: EntitlementsCheckOptions,\n ): Promise<boolean> {\n const result = await checkDetailed(productSlug, feature, opts);\n return result.allowed;\n },\n checkDetailed,\n /** Test helper: limpa o cache LRU. */\n __resetCache(): void {\n cache.clear();\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/entitlements.ts"],"names":["err","message"],"mappings":"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","file":"entitlements.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 * Entitlements — verifica se o portador da apiKey pode usar feature X\r\n * do produto Y.\r\n *\r\n * Endpoint: `GET /api/v1/sdk/entitlements/check?slug=X&feature=Y`\r\n * Schema Firestore consultado pelo backend:\r\n * `entitlements/{userId}/products/{slug}` → `{ features: string[], plan, expiresAt }`\r\n *\r\n * v1.2 introduz cache LRU em memória (default 60s TTL, 100 entries). Cada\r\n * (productSlug, feature) pareando o `apiKey` é cacheado. Caller pode invalidar\r\n * via `__resetCache()` (test helper) ou via `cacheBust: true` na chamada.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type { EntitlementCheck, ResolvedConfig } from './types';\r\n\r\ninterface RawEntitlementCheck {\r\n allowed?: boolean;\r\n productSlug?: string;\r\n feature?: string;\r\n reason?: string;\r\n}\r\n\r\nfunction toEntitlementCheck(raw: unknown): EntitlementCheck {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Entitlement response is not an object');\r\n }\r\n const r = raw as RawEntitlementCheck;\r\n if (typeof r.allowed !== 'boolean') {\r\n throw new NeetruError('invalid_response', 'Entitlement response missing `allowed` boolean');\r\n }\r\n return {\r\n allowed: r.allowed,\r\n productSlug: typeof r.productSlug === 'string' ? r.productSlug : '',\r\n feature: typeof r.feature === 'string' ? r.feature : '',\r\n reason: typeof r.reason === 'string' ? r.reason : undefined,\r\n };\r\n}\r\n\r\n/** TTL default — 60s. Pareando com tempo de propagação típico de mudança de plano. */\r\nconst CACHE_TTL_MS = 60_000;\r\n/** Máx entries por instância de namespace — LRU. */\r\nconst CACHE_MAX = 100;\r\n\r\ninterface CacheEntry {\r\n value: EntitlementCheck;\r\n expiresAt: number;\r\n}\r\n\r\nexport interface EntitlementsCheckOptions {\r\n /** Se true, ignora cache local e força ida ao servidor. Default false. */\r\n cacheBust?: boolean;\r\n}\r\n\r\nexport function createEntitlementsNamespace(config: ResolvedConfig) {\r\n // Map preserva ordem de inserção — readequa LRU manualmente em hit.\r\n const cache = new Map<string, CacheEntry>();\r\n\r\n function cacheKey(productSlug: string, feature: string): string {\r\n return `${productSlug}::${feature}`;\r\n }\r\n\r\n function readCache(key: string): EntitlementCheck | null {\r\n const entry = cache.get(key);\r\n if (!entry) return null;\r\n if (entry.expiresAt < Date.now()) {\r\n cache.delete(key);\r\n return null;\r\n }\r\n // LRU touch: reinsere no final.\r\n cache.delete(key);\r\n cache.set(key, entry);\r\n return entry.value;\r\n }\r\n\r\n function writeCache(key: string, value: EntitlementCheck): void {\r\n if (cache.size >= CACHE_MAX) {\r\n const oldest = cache.keys().next().value;\r\n if (oldest !== undefined) cache.delete(oldest);\r\n }\r\n cache.set(key, { value, expiresAt: Date.now() + CACHE_TTL_MS });\r\n }\r\n\r\n async function checkDetailed(\r\n productSlug: string,\r\n feature: string,\r\n opts: EntitlementsCheckOptions = {},\r\n ): Promise<EntitlementCheck> {\r\n if (!productSlug) throw new NeetruError('validation_failed', 'productSlug is required');\r\n if (!feature) throw new NeetruError('validation_failed', 'feature is required');\r\n\r\n const key = cacheKey(productSlug, feature);\r\n if (!opts.cacheBust) {\r\n const cached = readCache(key);\r\n if (cached) return cached;\r\n }\r\n\r\n const raw = await httpRequest<RawEntitlementCheck>(config, {\r\n method: 'GET',\r\n path: '/api/v1/sdk/entitlements/check',\r\n query: { slug: productSlug, feature },\r\n requireAuth: true,\r\n });\r\n const result = toEntitlementCheck(raw);\r\n writeCache(key, result);\r\n return result;\r\n }\r\n\r\n return {\r\n /**\r\n * Verifica se o caller pode usar `feature` no produto `productSlug`.\r\n * Retorno simples: `true` libera, `false` bloqueia. Cache 60s automático.\r\n *\r\n * Use `checkDetailed` se precisar do `reason` pra mensagem de upgrade.\r\n */\r\n async check(\r\n productSlug: string,\r\n feature: string,\r\n opts?: EntitlementsCheckOptions,\r\n ): Promise<boolean> {\r\n const result = await checkDetailed(productSlug, feature, opts);\r\n return result.allowed;\r\n },\r\n checkDetailed,\r\n /** Test helper: limpa o cache LRU. */\r\n __resetCache(): void {\r\n cache.clear();\r\n },\r\n };\r\n}\r\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts"],"names":[],"mappings":";;;AAgCO,IAAM,WAAA,GAAN,MAAM,YAAA,SAAoB,KAAA,CAAM;AAAA,EACrB,IAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EAEhB,WAAA,CACE,IAAA,EACA,OAAA,EACA,MAAA,EACA,SAAA,EACA;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,aAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAEjB,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,YAAA,CAAY,SAAS,CAAA;AAAA,EACnD;AACF","file":"errors.cjs","sourcesContent":["/**\n * Erros tipados do SDK.\n *\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\n * por `.code` (string estável) sem parsing de message.\n */\n\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\nexport type NeetruErrorCode =\n | 'invalid_config'\n | 'missing_api_key'\n | 'unauthorized'\n | 'forbidden'\n | 'not_found'\n | 'rate_limited'\n | 'validation_failed'\n | 'network_error'\n | 'invalid_response'\n | 'server_error'\n | 'unknown';\n\n/**\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\n *\n * @example\n * ```ts\n * try { await client.catalog.list(); }\n * catch (e) {\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\n * }\n * ```\n */\nexport class NeetruError extends Error {\n public readonly code: NeetruErrorCode | string;\n public readonly status?: number;\n public readonly requestId?: string;\n\n constructor(\n code: NeetruErrorCode | string,\n message: string,\n status?: number,\n requestId?: string,\n ) {\n super(message);\n this.name = 'NeetruError';\n this.code = code;\n this.status = status;\n this.requestId = requestId;\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\n Object.setPrototypeOf(this, NeetruError.prototype);\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts"],"names":[],"mappings":";;;AAgCO,IAAM,WAAA,GAAN,MAAM,YAAA,SAAoB,KAAA,CAAM;AAAA,EACrB,IAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EAEhB,WAAA,CACE,IAAA,EACA,OAAA,EACA,MAAA,EACA,SAAA,EACA;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,aAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAEjB,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,YAAA,CAAY,SAAS,CAAA;AAAA,EACnD;AACF","file":"errors.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"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts"],"names":[],"mappings":";AAgCO,IAAM,WAAA,GAAN,MAAM,YAAA,SAAoB,KAAA,CAAM;AAAA,EACrB,IAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EAEhB,WAAA,CACE,IAAA,EACA,OAAA,EACA,MAAA,EACA,SAAA,EACA;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,aAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAEjB,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,YAAA,CAAY,SAAS,CAAA;AAAA,EACnD;AACF","file":"errors.mjs","sourcesContent":["/**\n * Erros tipados do SDK.\n *\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\n * por `.code` (string estável) sem parsing de message.\n */\n\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\nexport type NeetruErrorCode =\n | 'invalid_config'\n | 'missing_api_key'\n | 'unauthorized'\n | 'forbidden'\n | 'not_found'\n | 'rate_limited'\n | 'validation_failed'\n | 'network_error'\n | 'invalid_response'\n | 'server_error'\n | 'unknown';\n\n/**\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\n *\n * @example\n * ```ts\n * try { await client.catalog.list(); }\n * catch (e) {\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\n * }\n * ```\n */\nexport class NeetruError extends Error {\n public readonly code: NeetruErrorCode | string;\n public readonly status?: number;\n public readonly requestId?: string;\n\n constructor(\n code: NeetruErrorCode | string,\n message: string,\n status?: number,\n requestId?: string,\n ) {\n super(message);\n this.name = 'NeetruError';\n this.code = code;\n this.status = status;\n this.requestId = requestId;\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\n Object.setPrototypeOf(this, NeetruError.prototype);\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts"],"names":[],"mappings":";AAgCO,IAAM,WAAA,GAAN,MAAM,YAAA,SAAoB,KAAA,CAAM;AAAA,EACrB,IAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EAEhB,WAAA,CACE,IAAA,EACA,OAAA,EACA,MAAA,EACA,SAAA,EACA;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,aAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAEjB,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,YAAA,CAAY,SAAS,CAAA;AAAA,EACnD;AACF","file":"errors.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"]}