@neetru/sdk 3.4.6 → 3.5.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 (88) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/ai.cjs +17 -13
  3. package/dist/ai.cjs.map +1 -1
  4. package/dist/ai.d.cts +1 -1
  5. package/dist/ai.d.ts +1 -1
  6. package/dist/ai.mjs +17 -13
  7. package/dist/ai.mjs.map +1 -1
  8. package/dist/auth.cjs +57 -23
  9. package/dist/auth.cjs.map +1 -1
  10. package/dist/auth.d.cts +2 -2
  11. package/dist/auth.d.ts +2 -2
  12. package/dist/auth.mjs +57 -23
  13. package/dist/auth.mjs.map +1 -1
  14. package/dist/catalog.cjs +19 -4
  15. package/dist/catalog.cjs.map +1 -1
  16. package/dist/catalog.d.cts +1 -1
  17. package/dist/catalog.d.ts +1 -1
  18. package/dist/catalog.mjs +19 -4
  19. package/dist/catalog.mjs.map +1 -1
  20. package/dist/checkout.cjs +11 -3
  21. package/dist/checkout.cjs.map +1 -1
  22. package/dist/checkout.d.cts +1 -1
  23. package/dist/checkout.d.ts +1 -1
  24. package/dist/checkout.mjs +11 -3
  25. package/dist/checkout.mjs.map +1 -1
  26. package/dist/db-react.d.cts +1 -1
  27. package/dist/db-react.d.ts +1 -1
  28. package/dist/db.cjs +17 -7
  29. package/dist/db.cjs.map +1 -1
  30. package/dist/db.d.cts +1 -1
  31. package/dist/db.d.ts +1 -1
  32. package/dist/db.mjs +17 -7
  33. package/dist/db.mjs.map +1 -1
  34. package/dist/entitlements.d.cts +1 -1
  35. package/dist/entitlements.d.ts +1 -1
  36. package/dist/firestore-compat.d.cts +1 -1
  37. package/dist/firestore-compat.d.ts +1 -1
  38. package/dist/index.cjs +58 -24
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.d.cts +30 -2
  41. package/dist/index.d.ts +30 -2
  42. package/dist/index.mjs +58 -24
  43. package/dist/index.mjs.map +1 -1
  44. package/dist/mocks.cjs +17 -0
  45. package/dist/mocks.cjs.map +1 -1
  46. package/dist/mocks.d.cts +5 -1
  47. package/dist/mocks.d.ts +5 -1
  48. package/dist/mocks.mjs +17 -0
  49. package/dist/mocks.mjs.map +1 -1
  50. package/dist/notifications.cjs +11 -3
  51. package/dist/notifications.cjs.map +1 -1
  52. package/dist/notifications.d.cts +1 -1
  53. package/dist/notifications.d.ts +1 -1
  54. package/dist/notifications.mjs +11 -3
  55. package/dist/notifications.mjs.map +1 -1
  56. package/dist/react.cjs +52 -2
  57. package/dist/react.cjs.map +1 -1
  58. package/dist/react.d.cts +1 -1
  59. package/dist/react.d.ts +1 -1
  60. package/dist/react.mjs +52 -2
  61. package/dist/react.mjs.map +1 -1
  62. package/dist/support.cjs +15 -4
  63. package/dist/support.cjs.map +1 -1
  64. package/dist/support.d.cts +1 -1
  65. package/dist/support.d.ts +1 -1
  66. package/dist/support.mjs +15 -4
  67. package/dist/support.mjs.map +1 -1
  68. package/dist/telemetry.cjs +11 -3
  69. package/dist/telemetry.cjs.map +1 -1
  70. package/dist/telemetry.d.cts +1 -1
  71. package/dist/telemetry.d.ts +1 -1
  72. package/dist/telemetry.mjs +11 -3
  73. package/dist/telemetry.mjs.map +1 -1
  74. package/dist/{types-nnztVk7G.d.ts → types-BPATkXYu.d.ts} +35 -7
  75. package/dist/{types-DIVZl7nO.d.cts → types-Du_iioJ7.d.cts} +35 -7
  76. package/dist/usage.cjs +11 -3
  77. package/dist/usage.cjs.map +1 -1
  78. package/dist/usage.d.cts +1 -1
  79. package/dist/usage.d.ts +1 -1
  80. package/dist/usage.mjs +11 -3
  81. package/dist/usage.mjs.map +1 -1
  82. package/dist/webhooks.cjs +17 -4
  83. package/dist/webhooks.cjs.map +1 -1
  84. package/dist/webhooks.d.cts +1 -1
  85. package/dist/webhooks.d.ts +1 -1
  86. package/dist/webhooks.mjs +17 -4
  87. package/dist/webhooks.mjs.map +1 -1
  88. package/package.json +4 -1
package/dist/ai.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/validators.ts","../src/ai.ts"],"names":[],"mappings":"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","file":"ai.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 /** 3.0: runtime não expõe API necessária (ex: WebCrypto ausente). */\r\n | 'runtime_unsupported'\r\n /**\r\n * 3.1.3 (bug_c1c96a00): o `state` retornado pelo IdP no callback OIDC não bate com o gerado em\r\n * `signIn` (CSRF). Também usado quando não há transação OIDC pendente.\r\n */\r\n | 'oidc_state_mismatch'\r\n /**\r\n * 3.1.12 (incidente pdv-agiliza 2026-07-10): o `nonce` do `id_token` retornado\r\n * pelo `/token` não bate com o gerado em `signIn` (possível replay). O token\r\n * é descartado sem tocar o storage.\r\n */\r\n | 'oidc_nonce_mismatch'\r\n /**\r\n * 3.1.12: o POST `/api/v1/oauth/token` (troca do authorization_code por\r\n * tokens em `completeSignIn`) falhou — HTTP não-2xx, corpo com `error`, ou\r\n * resposta sem `id_token`.\r\n */\r\n | 'token_exchange_failed'\r\n /** HTTP 409 — colisão de idempotência ou conflito de recurso. */\r\n | 'conflict'\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 * Motivo semântico opcional propagado pelo Core no corpo do erro (campo\r\n * `reason` no TOPO do body, fora de `error`). Usado principalmente pelo 503\r\n * de lease de DB, onde `reason` discrimina o estado do ambiente\r\n * (`suspended` | `archived` | `revoked` | `provisioning` | `degraded` |\r\n * `no_route` | `expired`). Camadas superiores (ex.: `db/sql`) mapeiam isso\r\n * para um `NeetruDbErrorCode` mais específico (recuperável vs não).\r\n */\r\n public readonly reason?: 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 reason?: 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 this.reason = reason;\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.\r\n * - **Captura `X-Neetru-Version`** das respostas e emite `console.warn` quando\r\n * o Core está abaixo da versão mínima para a major do SDK.\r\n *\r\n * Política de retries (mudança breaking 3.0):\r\n * - GET/HEAD: default 2 retries (3 tentativas total) — idempotente, seguro.\r\n * - POST/PUT/PATCH/DELETE: default **0 retries** — mutations podem duplicar\r\n * side effects (ex: `usage.report` incrementa contador). Caller pode\r\n * reativar passando `retries: N` explicitamente ou usar `Idempotency-Key`\r\n * header (gerado automaticamente se `opts.idempotencyKey=true`).\r\n *\r\n * Idempotency-Key (3.0):\r\n * - `opts.idempotencyKey === true` → SDK gera UUID v4 e injeta header.\r\n * - `opts.idempotencyKey === 'uuid-string'` → usa o valor passado.\r\n * - Caller mantém retentos client-side se quiser; Core dedup serverside\r\n * (vide `docs/CORE_CHANGES_REQUIRED.md` §2).\r\n */\r\nimport { NeetruError, type NeetruErrorCode } from './errors';\r\nimport { generateIdempotencyKey } from './idempotency';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n// ─── Compat Matrix SDK↔Core ──────────────────────────────────────────────────\r\n\r\n/**\r\n * Matriz de compatibilidade SDK major → versão mínima do Core.\r\n *\r\n * Formato do Core: CalVer `YYYY.MM.patch+revision` (ex: `2026.05.1+neetru-core-00096-79t`).\r\n * A comparação é feita apenas nas partes `YYYY.MM.patch` (prefixo antes de `+`).\r\n *\r\n * Quando o Core reporta `X-Neetru-Version` abaixo do mínimo para a SDK major\r\n * corrente, o SDK emite `console.warn` uma única vez por sessão de processo.\r\n *\r\n * Atualize esta tabela a cada major de SDK.\r\n */\r\nconst COMPAT_MATRIX: Record<number, string> = {\r\n // SDK major 3.x requer Core ≥ 2026.05.1 (suporte a X-Neetru-Version header,\r\n // runTransaction write-after-read, verifyWebhookRequest, webhooks 3.0+)\r\n 3: '2026.05.1',\r\n};\r\n\r\n/** CalVer sem sufixo `+revision`. Ex: `2026.05.1+abc` → `2026.05.1`. */\r\nfunction stripRevision(v: string): string {\r\n return v.split('+')[0] ?? v;\r\n}\r\n\r\n/**\r\n * Compara dois CalVer (`YYYY.MM.patch`). Retorna negativo se `a < b`,\r\n * positivo se `a > b`, 0 se iguais. Partes não numéricas tratadas como 0.\r\n */\r\nfunction compareCalVer(a: string, b: string): number {\r\n const partsA = stripRevision(a).split('.').map(Number);\r\n const partsB = stripRevision(b).split('.').map(Number);\r\n const len = Math.max(partsA.length, partsB.length);\r\n for (let i = 0; i < len; i++) {\r\n const pa = partsA[i] ?? 0;\r\n const pb = partsB[i] ?? 0;\r\n if (pa !== pb) return pa - pb;\r\n }\r\n return 0;\r\n}\r\n\r\n/** Lê a SDK major a partir da string `VERSION` exportada de `./index`. Fallback 3. */\r\nfunction getSdkMajor(): number {\r\n try {\r\n // Importação estática não disponível aqui (evita ciclo). Usa variável injetada\r\n // em tempo de build pela tsup via `define`. Fallback para 3 (current major).\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const ver = (globalThis as any).__NEETRU_SDK_VERSION__ as string | undefined;\r\n if (ver) return parseInt(ver.split('.')[0] ?? '3', 10);\r\n } catch {\r\n // ignore\r\n }\r\n return 3;\r\n}\r\n\r\n/** Aviso emitido no máximo uma vez por major detectada pra não spammar logs. */\r\nconst _warnedCoreTooOld = new Set<string>();\r\n\r\n/**\r\n * Verifica se a versão do Core (`X-Neetru-Version`) é compatível com a SDK major.\r\n * Emite `console.warn` quando incompatível (uma vez por processo por versão detectada).\r\n */\r\nexport function checkCoreVersionCompat(coreVersion: string): void {\r\n if (!coreVersion) return;\r\n const sdkMajor = getSdkMajor();\r\n const minCore = COMPAT_MATRIX[sdkMajor];\r\n if (!minCore) return; // sem restrição para esta major\r\n const stripped = stripRevision(coreVersion);\r\n if (compareCalVer(stripped, minCore) < 0) {\r\n const key = `${sdkMajor}:${stripped}`;\r\n if (!_warnedCoreTooOld.has(key)) {\r\n _warnedCoreTooOld.add(key);\r\n console.warn(\r\n `[Neetru SDK] Atenção: Core versão \"${coreVersion}\" é anterior ao mínimo recomendado` +\r\n ` \"${minCore}\" para SDK major ${sdkMajor}. Alguns recursos podem não funcionar` +\r\n ` corretamente. Atualize o Core para a versão mais recente.`,\r\n );\r\n }\r\n }\r\n}\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`).\r\n *\r\n * Default (3.0):\r\n * - GET/HEAD: 2 (= 3 tentativas total) — idempotente, seguro.\r\n * - POST/PUT/PATCH/DELETE: 0 — mutations podem duplicar side effects.\r\n *\r\n * Caller pode reativar passando explicitamente: `retries: 2`.\r\n */\r\n retries?: number;\r\n /**\r\n * Injeta `Idempotency-Key` header pra dedup serverside (3.0):\r\n * - `true` → SDK gera UUID v4 cripto-seguro automaticamente.\r\n * - string → usa o valor passado (deve ser UUID v4).\r\n * - `undefined`/`false` → sem header.\r\n */\r\n idempotencyKey?: boolean | string;\r\n}\r\n\r\nconst DEFAULT_RETRIES_READ = 2;\r\nconst DEFAULT_RETRIES_WRITE = 0;\r\nconst READ_METHODS = new Set(['GET', 'HEAD']);\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\n * Bug fix: sem teto, um servidor hostil/mal-configurado poderia retornar\r\n * `Retry-After: 86400` (24h) ou uma HTTP-date anos no futuro, pendurando o\r\n * processo indefinidamente. Aplica teto de MAX_RETRY_AFTER_MS em ambos os caminhos.\r\n */\r\nconst MAX_RETRY_AFTER_MS = 60_000; // 60s — teto razoável para retry automático\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.min(Math.round(secs * 1000), MAX_RETRY_AFTER_MS);\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 Math.min(delta, MAX_RETRY_AFTER_MS);\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 === 409) return 'conflict'; // Bug fix: 409 vira 'conflict' (não 'unknown')\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 // Default por método: reads tentam 2x, writes 0x. Caller override sempre vence.\r\n const defaultRetries = READ_METHODS.has(method)\r\n ? DEFAULT_RETRIES_READ\r\n : DEFAULT_RETRIES_WRITE;\r\n const maxRetries = opts.retries ?? defaultRetries;\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 // Idempotency-Key: gerado por chamada se solicitado. UUID v4 cripto-seguro.\r\n if (opts.idempotencyKey) {\r\n const key =\r\n typeof opts.idempotencyKey === 'string'\r\n ? opts.idempotencyKey\r\n : generateIdempotencyKey();\r\n headers['idempotency-key'] = key;\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 // Captura X-Neetru-Version e verifica compat com a SDK major.\r\n const coreVersion = res.headers.get('x-neetru-version');\r\n if (coreVersion) checkCoreVersionCompat(coreVersion);\r\n const parsed = await safeJson(res);\r\n return parsed as T;\r\n }\r\n\r\n // O contrato clássico de erro do Core é `{ error: { code, message } }`.\r\n // O 503 de lease de DB (e alguns endpoints novos) coloca `code`/`reason`/\r\n // `message` no TOPO do corpo, SEM envelope `error`. Lemos ambos: preferimos\r\n // `body.error` quando presente; caímos nos campos do topo caso contrário.\r\n // `reason` é sempre considerado no topo (o 503 de lease o coloca lá mesmo\r\n // quando há `error`), pra que a camada de DB discrimine suspended/archived/\r\n // revoked de provisioning/degraded.\r\n const body = (await safeJson(res)) as\r\n | {\r\n error?: { code?: string; message?: string; reason?: string } | string;\r\n code?: string;\r\n reason?: string;\r\n message?: string;\r\n }\r\n | undefined;\r\n let code: string = statusToCode(res.status);\r\n let message = `HTTP ${res.status}`;\r\n let reason: string | undefined;\r\n if (body && typeof body === 'object') {\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 if (typeof errField.reason === 'string') reason = errField.reason;\r\n } else {\r\n // Sem envelope `error` — lê os campos no TOPO do corpo (contrato do 503\r\n // de lease: `{ code, reason }` no topo).\r\n if (typeof body.code === 'string') code = body.code;\r\n if (typeof body.message === 'string') message = body.message;\r\n }\r\n // `reason` no topo tem prioridade final (o 503 de lease o coloca no topo\r\n // mesmo quando também há `error`).\r\n if (typeof body.reason === 'string') reason = body.reason;\r\n }\r\n const err = new NeetruError(code, message, res.status, requestId, reason);\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 * Validators centralizados pra inputs do SDK que precisam casar com\r\n * regex do Core.\r\n *\r\n * **M-03 fix (Opus review 2026-05-27):** o Core rejeita productId que\r\n * não bate `/^[a-z0-9][a-z0-9_-]{0,62}$/` com 400 `validation_failed`.\r\n * O SDK não pré-validava — consumer recebia erro só em runtime de\r\n * produção, depois do round-trip de rede. Agora SDK throws localmente\r\n * antes do fetch.\r\n */\r\nimport { NeetruError } from './errors';\r\n\r\n/**\r\n * Regex canonical de IDs no Neetru Core (productId, tenantId, etc).\r\n * Espelha `SDK_ID_RE` em `neetru_core/src/lib/schemas/sdk.ts`.\r\n *\r\n * `i` flag (2026-09, mesmo fix do Core em `SDK_ID_RE`/`db-lease`/\r\n * `checkout-intents` 5c47e6e6): productId real de produtos como o\r\n * PDV-Agiliza é um Firestore auto-ID mixed-case (ex.\r\n * `qkcWzQ43LthAIRlVUSQ6`), não um slug lowercase. Sem `i`, este validator\r\n * lançava `validation_failed` client-side ANTES de qualquer fetch — o SDK\r\n * bloqueava `usage.report()`/`usage.check()` pro produto real, mesmo o Core\r\n * já aceitando o mesmo id (mixed-case) em `db/lease`.\r\n */\r\nexport const SDK_ID_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/i;\r\n\r\n/**\r\n * Throws `NeetruError('validation_failed')` se `value` não bater no\r\n * formato canonical.\r\n *\r\n * @example\r\n * ```ts\r\n * assertValidSdkId('productId', 'gestovendas'); // ok\r\n * assertValidSdkId('productId', 'GestoVendas'); // throws\r\n * ```\r\n */\r\nexport function assertValidSdkId(field: string, value: string): void {\r\n if (typeof value !== 'string' || !SDK_ID_RE.test(value)) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n `${field} must match ${SDK_ID_RE.source} (lowercase alphanumeric, _, -; first char must be alphanumeric; max 63 chars)`,\r\n );\r\n }\r\n}\r\n","/**\r\n * AI namespace — AI Gateway do Core exposto pro produto (3.1.10).\r\n *\r\n * Fecha o AI Gateway E2E: o produto chama `client.ai.chat(...)` /\r\n * `client.ai.stream(...)` e o Core roteia pro provider (OpenAI-compat),\r\n * aplica cota/entitlement e devolve resposta ou SSE.\r\n *\r\n * Endpoint consumido:\r\n * - `POST /api/sdk/v1/ai/chat` — Bearer + JSON.\r\n * Body: `{ productId, tenantId, model, messages, stream, maxTokens?, temperature? }`.\r\n * - `stream:false` → 200 JSON `{ ok, choices, usage, model, provider }`.\r\n * - `stream:true` → `text/event-stream`: `data: {chunk}\\n\\n` … `data: [DONE]\\n\\n`.\r\n * - Headers de resposta em ambos: `X-Neetru-Provider`, `X-Neetru-Ai-Usage-Warning`\r\n * ('1' quando a cota do tenant passou de 80%).\r\n *\r\n * Por que `config.fetch` cru (e não `httpRequest`)?\r\n * - `httpRequest` devolve só o body parseado; aqui preciso dos **headers**\r\n * de resposta (`X-Neetru-Provider` / `X-Neetru-Ai-Usage-Warning`) e do\r\n * **body como stream** (SSE). Então falo direto com `config.fetch`,\r\n * reusando o mesmo mapeamento status→NeetruError do transport.\r\n *\r\n * Retry: **nenhum**. Chat é POST (custo real por chamada — não duplica) e\r\n * streaming não pode ser retriado cegamente (já emitiu bytes).\r\n */\r\nimport { NeetruError, type NeetruErrorCode } from './errors';\r\nimport { checkCoreVersionCompat } from './http';\r\nimport { assertValidSdkId } from './validators';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n// ─── Tipos públicos ──────────────────────────────────────────────────────────\r\n\r\n/** Bloco de texto de uma mensagem multimodal (OpenAI-compat). */\r\nexport interface AiTextPart {\r\n type: 'text';\r\n text: string;\r\n}\r\n\r\n/**\r\n * Bloco de imagem de uma mensagem multimodal (OpenAI-compat).\r\n *\r\n * `url` pode ser:\r\n * - `data:image/<png|jpeg|jpg|gif|webp>;base64,<...>` — auto-contida.\r\n * - `https://...` — o Core NÃO busca a URL; quem busca é o provider upstream.\r\n *\r\n * Qualquer outro esquema (`http:`, `file:`, etc.) é rejeitado por segurança.\r\n */\r\nexport interface AiImageUrlPart {\r\n type: 'image_url';\r\n image_url: {\r\n url: string;\r\n /** Hint de fidelidade OpenAI: 'low' | 'high' | 'auto'. */\r\n detail?: string;\r\n };\r\n}\r\n\r\n/** Parte de conteúdo multimodal. */\r\nexport type AiContentPart = AiTextPart | AiImageUrlPart;\r\n\r\n/**\r\n * Formato de saída estruturada (opt-in). Espelha `response_format` do OpenAI.\r\n * Omitido = comportamento default do modelo (texto livre). Anthropic é\r\n * best-effort (o Core injeta uma diretiva de system prompt).\r\n */\r\nexport type AiResponseFormat =\r\n | { type: 'text' }\r\n | { type: 'json_object' }\r\n | {\r\n type: 'json_schema';\r\n json_schema: {\r\n name: string;\r\n schema?: Record<string, unknown>;\r\n description?: string;\r\n strict?: boolean;\r\n };\r\n };\r\n\r\n/**\r\n * Uma mensagem do diálogo (OpenAI-compat).\r\n *\r\n * `content` aceita string pura (retrocompat) OU array de partes multimodais\r\n * (`text` / `image_url`). String continua funcionando idêntico.\r\n */\r\nexport interface AiChatMessage {\r\n role: string;\r\n content: string | AiContentPart[];\r\n}\r\n\r\n/**\r\n * Opções de `ai.chat()` / `ai.stream()`.\r\n *\r\n * `productId`/`tenantId` são opcionais aqui: se o client já foi criado com\r\n * eles (`createNeetruClient({ productId, tenantId })`), viram default.\r\n */\r\nexport interface AiChatOptions {\r\n /** Default = `config.productId`. Obrigatório (opts OU config). */\r\n productId?: string;\r\n /** Default = `config.tenantId`. Obrigatório (opts OU config). */\r\n tenantId?: string;\r\n /** Modelo alvo (ex: `gpt-4o-mini`). O Core valida/roteia. */\r\n model: string;\r\n /** Diálogo. Array não-vazio de `{role, content}`. */\r\n messages: AiChatMessage[];\r\n /** Teto de tokens de saída (opcional). */\r\n maxTokens?: number;\r\n /** Temperatura de amostragem (opcional). */\r\n temperature?: number;\r\n /**\r\n * Saída estruturada opt-in (`json_object` / `json_schema`). Omitido =\r\n * comportamento default do modelo. O Core mapeia pro `response_format` nativo\r\n * dos providers OpenAI-compat; Anthropic é best-effort via system prompt.\r\n */\r\n responseFormat?: AiResponseFormat;\r\n /** AbortSignal do caller (cancela a request / o stream). */\r\n signal?: AbortSignal;\r\n}\r\n\r\n/** Uso de tokens (OpenAI-compat, pass-through do Core). */\r\nexport interface AiChatUsage {\r\n prompt_tokens: number;\r\n completion_tokens: number;\r\n total_tokens: number;\r\n}\r\n\r\n/** Uma escolha do modelo (OpenAI-compat). */\r\nexport interface AiChatChoice {\r\n message: { role: string; content: string };\r\n finish_reason?: string | null;\r\n}\r\n\r\n/** Retorno de `ai.chat()` (non-stream). */\r\nexport interface AiChatResult {\r\n choices: AiChatChoice[];\r\n usage: AiChatUsage;\r\n model: string;\r\n /** Provider que atendeu (do body; fallback header `X-Neetru-Provider`). */\r\n provider: string;\r\n /** `true` quando o Core sinalizou `X-Neetru-Ai-Usage-Warning: 1` (cota ≥80%). */\r\n usageWarning: boolean;\r\n}\r\n\r\n/** Metadados do stream (resolvidos quando os headers da resposta chegam). */\r\nexport interface AiStreamMeta {\r\n provider: string;\r\n usageWarning: boolean;\r\n}\r\n\r\n/**\r\n * Handle retornado por `ai.stream()`: um `AsyncIterable<string>` que yielda os\r\n * deltas de conteúdo conforme chegam, mais `meta` (provider/usageWarning) que\r\n * resolve assim que os headers da resposta chegam.\r\n *\r\n * @example\r\n * ```ts\r\n * const s = client.ai.stream({ model: 'gpt-4o-mini', messages });\r\n * for await (const delta of s) process.stdout.write(delta);\r\n * const { provider, usageWarning } = await s.meta;\r\n * ```\r\n */\r\nexport interface AiStreamHandle extends AsyncIterable<string> {\r\n readonly meta: Promise<AiStreamMeta>;\r\n}\r\n\r\n/** Namespace `client.ai`. */\r\nexport interface AiNamespace {\r\n /** Completa um chat (non-stream). Lança `NeetruError` em falha. */\r\n chat(opts: AiChatOptions): Promise<AiChatResult>;\r\n /** Abre um stream SSE. Yielda deltas de conteúdo (string). */\r\n stream(opts: AiChatOptions): AiStreamHandle;\r\n}\r\n\r\n// ─── Internos ────────────────────────────────────────────────────────────────\r\n\r\nconst AI_CHAT_PATH = '/api/sdk/v1/ai/chat';\r\n/** Timeout do chat non-stream. Modelos podem ser lentos → generoso. */\r\nconst AI_NONSTREAM_TIMEOUT_MS = 120_000;\r\n\r\ninterface AiRequestBody {\r\n productId: string;\r\n tenantId: string;\r\n model: string;\r\n messages: AiChatMessage[];\r\n stream: boolean;\r\n maxTokens?: number;\r\n temperature?: number;\r\n responseFormat?: AiResponseFormat;\r\n}\r\n\r\n// ─── Validação de conteúdo multimodal (espelha `@/lib/ai-gateway/content` do\r\n// Core — mesmos limites e esquemas de URL permitidos) ───────────────────────\r\n\r\n/** Teto de um bloco de texto. */\r\nconst MAX_TEXT_PART_LEN = 32_768;\r\n/** Máximo de partes por mensagem (anti-DoS). */\r\nconst MAX_CONTENT_PARTS = 32;\r\n/** Teto de uma `data:` URL base64 (≈ 3.9 MiB). */\r\nconst MAX_DATA_URL_LEN = 4_194_304;\r\n/** Teto de uma `https://` URL de imagem. */\r\nconst MAX_HTTPS_URL_LEN = 2_048;\r\nconst DATA_IMAGE_URL_RE = /^data:image\\/(?:png|jpe?g|gif|webp);base64,[A-Za-z0-9+/]+={0,2}$/;\r\nconst HTTPS_URL_RE = /^https:\\/\\/[^\\s]+$/;\r\nconst IMAGE_DETAIL_VALUES = new Set(['low', 'high', 'auto']);\r\n\r\n// ─── Contrato de request (espelha os limites do Core `AiChatRequestSchema` —\r\n// mesmos números, pra o SDK NÃO deixar passar o que o Core rejeita) ────────\r\n/** Roles válidas (enum do Core, não string qualquer). */\r\nconst AI_ROLES = new Set(['system', 'user', 'assistant']);\r\n/** Máximo de mensagens por request. */\r\nconst MAX_MESSAGES = 100;\r\n/** Comprimento máximo do nome do modelo. */\r\nconst MAX_MODEL_LEN = 128;\r\n/** Teto de maxTokens. */\r\nconst MAX_TOKENS_CAP = 32_768;\r\n/** Faixa de temperature. */\r\nconst MIN_TEMPERATURE = 0;\r\nconst MAX_TEMPERATURE = 2;\r\n\r\n// ─── Limites AGREGADOS por request (espelham `content.ts` do Core) ────────────\r\nconst MAX_TOTAL_CONTENT_PARTS = 200;\r\nconst MAX_TOTAL_IMAGES = 20;\r\nconst MAX_TOTAL_IMAGE_BYTES = 12 * 1024 * 1024;\r\n\r\n// ─── Limites do JSON Schema de saída estruturada (espelham o Core) ────────────\r\nconst MAX_SCHEMA_JSON_LEN = 50_000;\r\nconst MAX_SCHEMA_DEPTH = 16;\r\nconst MAX_SCHEMA_KEYS = 500;\r\nconst FORBIDDEN_SCHEMA_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\r\nconst RESPONSE_FORMAT_NAME_RE = /^[a-zA-Z0-9_-]+$/;\r\n\r\nfunction fail(msg: string): never {\r\n throw new NeetruError('validation_failed', msg);\r\n}\r\n\r\n/** Valida ESTRITAMENTE o corpo base64 de uma data-URL (comprimento/padding). */\r\nfunction isStrictBase64Payload(b64: string): boolean {\r\n if (b64.length === 0 || b64.length % 4 !== 0) return false;\r\n const pad = b64.endsWith('==') ? 2 : b64.endsWith('=') ? 1 : 0;\r\n const body = pad > 0 ? b64.slice(0, b64.length - pad) : b64;\r\n return !body.includes('=');\r\n}\r\n\r\n/** Bytes DECODIFICADOS aproximados de uma data-URL base64. */\r\nfunction dataUrlDecodedBytes(url: string): number {\r\n const comma = url.indexOf(',');\r\n if (comma === -1) return 0;\r\n const b64 = url.slice(comma + 1);\r\n const pad = b64.endsWith('==') ? 2 : b64.endsWith('=') ? 1 : 0;\r\n return Math.max(0, Math.floor((b64.length * 3) / 4) - pad);\r\n}\r\n\r\n/**\r\n * Impõe os limites AGREGADOS por request (soma de TODAS as mensagens). Espelha\r\n * `checkAggregateMultimodalLimits` do Core — MESMA política, mesmos números.\r\n * Retorna a mensagem de erro ou `null`.\r\n */\r\nfunction checkAggregateMultimodalLimits(messages: ReadonlyArray<{ content?: unknown }>): string | null {\r\n let totalParts = 0;\r\n let totalImages = 0;\r\n let totalImageBytes = 0;\r\n for (const m of messages) {\r\n const content = m?.content;\r\n if (!Array.isArray(content)) continue;\r\n for (const part of content) {\r\n totalParts++;\r\n if (totalParts > MAX_TOTAL_CONTENT_PARTS) {\r\n return `ai: total content parts exceeds ${MAX_TOTAL_CONTENT_PARTS} per request`;\r\n }\r\n if (part && typeof part === 'object' && (part as { type?: unknown }).type === 'image_url') {\r\n totalImages++;\r\n if (totalImages > MAX_TOTAL_IMAGES) {\r\n return `ai: total images exceeds ${MAX_TOTAL_IMAGES} per request`;\r\n }\r\n const url = (part as { image_url?: { url?: unknown } }).image_url?.url;\r\n if (typeof url === 'string' && url.startsWith('data:')) {\r\n totalImageBytes += dataUrlDecodedBytes(url);\r\n if (totalImageBytes > MAX_TOTAL_IMAGE_BYTES) {\r\n return `ai: aggregate image bytes exceeds ${MAX_TOTAL_IMAGE_BYTES} per request`;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Valida o objeto `schema` de `json_schema` — espelha `validateStructuredSchema`\r\n * do Core (tamanho serializado, profundidade, nº de chaves, e rejeição de\r\n * `__proto__`/`constructor`/`prototype`). Retorna a mensagem de erro ou `null`.\r\n */\r\nfunction validateStructuredSchema(schema: unknown): string | null {\r\n if (schema === undefined) return null;\r\n if (schema === null || typeof schema !== 'object') {\r\n return 'ai: responseFormat json_schema.schema must be an object';\r\n }\r\n let serialized: string | undefined;\r\n try {\r\n serialized = JSON.stringify(schema);\r\n } catch {\r\n return 'ai: responseFormat json_schema.schema is not serializable';\r\n }\r\n if (serialized === undefined) return 'ai: responseFormat json_schema.schema is invalid';\r\n if (serialized.length > MAX_SCHEMA_JSON_LEN) {\r\n return `ai: responseFormat json_schema.schema exceeds ${MAX_SCHEMA_JSON_LEN} serialized chars`;\r\n }\r\n let keyCount = 0;\r\n const walk = (node: unknown, depth: number): string | null => {\r\n if (depth > MAX_SCHEMA_DEPTH) {\r\n return `ai: responseFormat json_schema.schema exceeds max depth ${MAX_SCHEMA_DEPTH}`;\r\n }\r\n if (Array.isArray(node)) {\r\n for (const item of node) {\r\n const e = walk(item, depth + 1);\r\n if (e) return e;\r\n }\r\n return null;\r\n }\r\n if (node && typeof node === 'object') {\r\n for (const key of Object.getOwnPropertyNames(node)) {\r\n if (FORBIDDEN_SCHEMA_KEYS.has(key)) {\r\n return `ai: responseFormat json_schema.schema has forbidden key: ${key}`;\r\n }\r\n keyCount++;\r\n if (keyCount > MAX_SCHEMA_KEYS) {\r\n return `ai: responseFormat json_schema.schema exceeds ${MAX_SCHEMA_KEYS} keys`;\r\n }\r\n const e = walk((node as Record<string, unknown>)[key], depth + 1);\r\n if (e) return e;\r\n }\r\n }\r\n return null;\r\n };\r\n return walk(schema, 0);\r\n}\r\n\r\n/** Valida a `url` de um `image_url` (data:base64 ou https, com limites). */\r\nfunction validateImageUrl(url: unknown): void {\r\n if (typeof url !== 'string' || url.length === 0) {\r\n fail('ai: image_url.url must be a non-empty string');\r\n }\r\n const u = url as string;\r\n if (u.startsWith('data:')) {\r\n if (u.length > MAX_DATA_URL_LEN) fail(`ai: image_url.url (data:) exceeds ${MAX_DATA_URL_LEN} chars`);\r\n if (!DATA_IMAGE_URL_RE.test(u)) {\r\n fail('ai: image_url.url data: must be data:image/<png|jpeg|jpg|gif|webp>;base64,<...>');\r\n }\r\n // Valida comprimento/padding do base64 (a regex não garante múltiplo de 4).\r\n const b64 = u.slice(u.indexOf(',') + 1);\r\n if (!isStrictBase64Payload(b64)) {\r\n fail('ai: image_url.url data: has invalid base64 (length/padding)');\r\n }\r\n return;\r\n }\r\n if (u.startsWith('https://')) {\r\n if (u.length > MAX_HTTPS_URL_LEN) fail(`ai: image_url.url (https:) exceeds ${MAX_HTTPS_URL_LEN} chars`);\r\n if (!HTTPS_URL_RE.test(u)) fail('ai: image_url.url https: is invalid');\r\n return;\r\n }\r\n fail('ai: image_url.url must be a data:image/...;base64 or https:// URL (other schemes are rejected)');\r\n}\r\n\r\n/**\r\n * Valida o `content` de uma mensagem: string OU array de partes multimodais.\r\n * `role` é usado pra restringir imagem: `image_url` só é permitida em `user`\r\n * (mesma decisão do Core — imagem em system/assistant é rejeitada).\r\n */\r\nfunction validateAiContent(content: unknown, role: string): void {\r\n if (typeof content === 'string') {\r\n if (content.length === 0) fail('ai: message content string must be non-empty');\r\n if (content.length > MAX_TEXT_PART_LEN) fail(`ai: message content exceeds ${MAX_TEXT_PART_LEN} chars`);\r\n return;\r\n }\r\n if (!Array.isArray(content) || content.length === 0) {\r\n fail('ai: message content must be a non-empty string or array of parts');\r\n }\r\n if (content.length > MAX_CONTENT_PARTS) fail(`ai: message content has more than ${MAX_CONTENT_PARTS} parts`);\r\n for (const part of content) {\r\n if (!part || typeof part !== 'object') fail('ai: each content part must be an object');\r\n const type = (part as { type?: unknown }).type;\r\n if (type === 'text') {\r\n const text = (part as { text?: unknown }).text;\r\n if (typeof text !== 'string' || text.length === 0) fail('ai: text part must have non-empty { text: string }');\r\n if (text.length > MAX_TEXT_PART_LEN) fail(`ai: text part exceeds ${MAX_TEXT_PART_LEN} chars`);\r\n } else if (type === 'image_url') {\r\n if (role !== 'user') {\r\n fail(`ai: image_url is only allowed in role 'user' messages (got '${role}')`);\r\n }\r\n const iu = (part as { image_url?: unknown }).image_url;\r\n if (!iu || typeof iu !== 'object') fail('ai: image_url part must have { image_url: { url } }');\r\n validateImageUrl((iu as { url?: unknown }).url);\r\n const detail = (iu as { detail?: unknown }).detail;\r\n if (detail !== undefined && (typeof detail !== 'string' || !IMAGE_DETAIL_VALUES.has(detail))) {\r\n fail(\"ai: image_url.detail must be 'low' | 'high' | 'auto'\");\r\n }\r\n } else {\r\n fail(\"ai: content part type must be 'text' or 'image_url'\");\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Valida `responseFormat` (opt-in). Espelha EXATAMENTE o `AiResponseFormatSchema`\r\n * do Core: `name` regex `a-zA-Z0-9_-` + max 64, `schema` objeto (com os mesmos\r\n * limites de tamanho/profundidade/chaves), `description` max 1000, `strict`\r\n * boolean — pra o SDK não deixar passar o que o Core rejeita.\r\n */\r\nfunction validateResponseFormat(rf: unknown): void {\r\n if (!rf || typeof rf !== 'object') fail('ai: responseFormat must be an object');\r\n const type = (rf as { type?: unknown }).type;\r\n if (type === 'text' || type === 'json_object') return;\r\n if (type === 'json_schema') {\r\n const js = (rf as { json_schema?: unknown }).json_schema;\r\n if (!js || typeof js !== 'object') fail('ai: responseFormat json_schema requires { json_schema: { name } }');\r\n const jso = js as { name?: unknown; schema?: unknown; description?: unknown; strict?: unknown };\r\n const name = jso.name;\r\n if (typeof name !== 'string' || name.length === 0) fail('ai: responseFormat json_schema.name is required');\r\n if (name.length > 64) fail('ai: responseFormat json_schema.name exceeds 64 chars');\r\n if (!RESPONSE_FORMAT_NAME_RE.test(name)) fail('ai: responseFormat json_schema.name must match a-zA-Z0-9_-');\r\n if (jso.description !== undefined) {\r\n if (typeof jso.description !== 'string') fail('ai: responseFormat json_schema.description must be a string');\r\n if (jso.description.length > 1000) fail('ai: responseFormat json_schema.description exceeds 1000 chars');\r\n }\r\n if (jso.strict !== undefined && typeof jso.strict !== 'boolean') {\r\n fail('ai: responseFormat json_schema.strict must be a boolean');\r\n }\r\n if (jso.schema !== undefined) {\r\n const err = validateStructuredSchema(jso.schema);\r\n if (err) fail(err);\r\n }\r\n return;\r\n }\r\n fail(\"ai: responseFormat.type must be 'text' | 'json_object' | 'json_schema'\");\r\n}\r\n\r\n/** Valida input e resolve o body canonical enviado ao Core. */\r\nfunction resolveAiBody(\r\n config: ResolvedConfig,\r\n opts: AiChatOptions,\r\n stream: boolean,\r\n): AiRequestBody {\r\n if (!opts || typeof opts !== 'object') {\r\n throw new NeetruError('validation_failed', 'ai: options object is required');\r\n }\r\n if (typeof opts.model !== 'string' || opts.model.length === 0) {\r\n throw new NeetruError('validation_failed', 'ai: model is required');\r\n }\r\n if (opts.model.length > MAX_MODEL_LEN) {\r\n throw new NeetruError('validation_failed', `ai: model exceeds ${MAX_MODEL_LEN} chars`);\r\n }\r\n if (!Array.isArray(opts.messages) || opts.messages.length === 0) {\r\n throw new NeetruError('validation_failed', 'ai: messages must be a non-empty array');\r\n }\r\n if (opts.messages.length > MAX_MESSAGES) {\r\n throw new NeetruError('validation_failed', `ai: messages exceeds ${MAX_MESSAGES} per request`);\r\n }\r\n for (const m of opts.messages) {\r\n // role é um ENUM (system|user|assistant), não string qualquer — alinha ao\r\n // `AiMessageSchema` do Core (senão o SDK deixa passar o que o Core rejeita).\r\n if (!m || typeof m !== 'object' || typeof m.role !== 'string' || !AI_ROLES.has(m.role)) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n \"ai: each message role must be 'system' | 'user' | 'assistant'\",\r\n );\r\n }\r\n // Aceita string (retrocompat) OU array de partes multimodais (text/image_url).\r\n validateAiContent((m as AiChatMessage).content, m.role);\r\n }\r\n // Limites AGREGADOS por request (mesma política/números do Core).\r\n const aggErr = checkAggregateMultimodalLimits(opts.messages);\r\n if (aggErr) throw new NeetruError('validation_failed', aggErr);\r\n const productId = opts.productId ?? config.productId;\r\n const tenantId = opts.tenantId ?? config.tenantId;\r\n if (!productId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'ai: 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 'ai: tenantId required (pass to options or set on createNeetruClient)',\r\n );\r\n }\r\n assertValidSdkId('productId', productId);\r\n assertValidSdkId('tenantId', tenantId);\r\n\r\n const body: AiRequestBody = {\r\n productId,\r\n tenantId,\r\n model: opts.model,\r\n messages: opts.messages,\r\n stream,\r\n };\r\n if (opts.maxTokens !== undefined) {\r\n if (!Number.isInteger(opts.maxTokens) || opts.maxTokens <= 0 || opts.maxTokens > MAX_TOKENS_CAP) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n `ai: maxTokens must be a positive integer <= ${MAX_TOKENS_CAP}`,\r\n );\r\n }\r\n body.maxTokens = opts.maxTokens;\r\n }\r\n if (opts.temperature !== undefined) {\r\n if (\r\n typeof opts.temperature !== 'number' ||\r\n !Number.isFinite(opts.temperature) ||\r\n opts.temperature < MIN_TEMPERATURE ||\r\n opts.temperature > MAX_TEMPERATURE\r\n ) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n `ai: temperature must be a finite number between ${MIN_TEMPERATURE} and ${MAX_TEMPERATURE}`,\r\n );\r\n }\r\n body.temperature = opts.temperature;\r\n }\r\n if (opts.responseFormat !== undefined) {\r\n validateResponseFormat(opts.responseFormat);\r\n body.responseFormat = opts.responseFormat;\r\n }\r\n return body;\r\n}\r\n\r\n/** Parse JSON defensivo de uma Response — `undefined` em body vazio/inválido. */\r\nasync function safeJson(res: Response): Promise<unknown> {\r\n try {\r\n const text = await res.text();\r\n if (!text) return undefined;\r\n return JSON.parse(text);\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/** Mapeamento status→code estável (espelha `statusToCode` do http.ts). */\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 === 409) return 'conflict';\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 joinUrl(baseUrl: string, path: string): string {\r\n const base = baseUrl.replace(/\\/+$/, '');\r\n const p = path.startsWith('/') ? path : `/${path}`;\r\n return `${base}${p}`;\r\n}\r\n\r\n/**\r\n * Executa o POST no gateway e devolve a `Response` com body **intacto** em\r\n * sucesso (o caller lê `.json()` ou `.body`). Em `!res.ok`, extrai\r\n * `error.code`/`error.message` do body e lança `NeetruError` — o `code` do\r\n * Core (`ai_unavailable`, `token_limit_exceeded`, `forbidden_product`, …)\r\n * vence o code genérico derivado do status.\r\n */\r\nasync function aiFetch(\r\n config: ResolvedConfig,\r\n body: AiRequestBody,\r\n signal: AbortSignal | undefined,\r\n stream: boolean,\r\n): Promise<Response> {\r\n if (!config.apiKey) {\r\n throw new NeetruError(\r\n 'missing_api_key',\r\n 'ai requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.',\r\n );\r\n }\r\n const url = joinUrl(config.baseUrl, AI_CHAT_PATH);\r\n const headers: Record<string, string> = {\r\n 'content-type': 'application/json',\r\n accept: stream ? 'text/event-stream' : 'application/json',\r\n authorization: `Bearer ${config.apiKey}`,\r\n };\r\n const init: RequestInit = { method: 'POST', headers, body: JSON.stringify(body) };\r\n // Non-stream: timeout defensivo (ou signal do caller se passado).\r\n // Stream: só o signal do caller — timeout fixo mataria stream longo legítimo.\r\n if (stream) {\r\n if (signal) init.signal = signal;\r\n } else {\r\n init.signal = signal ?? AbortSignal.timeout(AI_NONSTREAM_TIMEOUT_MS);\r\n }\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 ${AI_NONSTREAM_TIMEOUT_MS / 1000}s`\r\n : err instanceof DOMException && err.name === 'AbortError'\r\n ? 'Network error: request aborted'\r\n : `Network error: ${err instanceof Error ? err.message : 'fetch failed'}`;\r\n throw new NeetruError('network_error', message);\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)) 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 (parsed && typeof parsed === 'object' && 'error' in parsed) {\r\n const errField = parsed.error;\r\n if (typeof errField === 'string') {\r\n message = errField;\r\n } else if (errField && typeof errField === 'object') {\r\n // O code do gateway (ai_unavailable/token_limit_exceeded/forbidden_product…)\r\n // vence o genérico do status — não pode ser engolido.\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 throw new NeetruError(code, message, res.status, requestId);\r\n }\r\n\r\n const coreVersion = res.headers.get('x-neetru-version');\r\n if (coreVersion) checkCoreVersionCompat(coreVersion);\r\n return res;\r\n}\r\n\r\nfunction readMeta(res: Response): AiStreamMeta {\r\n return {\r\n provider: res.headers.get('x-neetru-provider') ?? '',\r\n usageWarning: res.headers.get('x-neetru-ai-usage-warning') === '1',\r\n };\r\n}\r\n\r\n/**\r\n * Extrai o conteúdo de um evento SSE (bloco entre `\\n\\n`).\r\n * - `{ done: true }` quando o evento é `[DONE]`.\r\n * - `{ content }` quando extraiu `choices[0].delta.content`.\r\n * - `null` quando é comentário/keep-alive/JSON inválido/sem delta (ignorar).\r\n * Junta múltiplas linhas `data:` do mesmo evento (SSE permite; OpenAI manda 1).\r\n */\r\nfunction parseSseData(rawEvent: string): { done: true } | { content: string } | null {\r\n const dataLines: string[] = [];\r\n for (const line of rawEvent.split('\\n')) {\r\n const trimmed = line.replace(/\\r$/, '');\r\n if (trimmed.startsWith('data:')) {\r\n // Strip 'data:' + no máximo um espaço de cortesia.\r\n let v = trimmed.slice(5);\r\n if (v.startsWith(' ')) v = v.slice(1);\r\n dataLines.push(v);\r\n }\r\n }\r\n if (dataLines.length === 0) return null;\r\n const payload = dataLines.join('\\n');\r\n if (payload === '[DONE]') return { done: true };\r\n try {\r\n const obj = JSON.parse(payload) as {\r\n choices?: Array<{ delta?: { content?: unknown } }>;\r\n };\r\n const content = obj?.choices?.[0]?.delta?.content;\r\n if (typeof content === 'string' && content.length > 0) return { content };\r\n return null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ─── Factory ─────────────────────────────────────────────────────────────────\r\n\r\nexport function createAiNamespace(config: ResolvedConfig): AiNamespace {\r\n return {\r\n async chat(opts: AiChatOptions): Promise<AiChatResult> {\r\n const body = resolveAiBody(config, opts, false);\r\n const res = await aiFetch(config, body, opts.signal, false);\r\n const { provider: providerHeader, usageWarning } = readMeta(res);\r\n const raw = (await safeJson(res)) as\r\n | {\r\n ok?: boolean;\r\n choices?: AiChatChoice[];\r\n usage?: AiChatUsage;\r\n model?: string;\r\n provider?: string;\r\n }\r\n | undefined;\r\n if (!raw || raw.ok !== true || !Array.isArray(raw.choices)) {\r\n throw new NeetruError('invalid_response', 'ai.chat response missing ok/choices');\r\n }\r\n return {\r\n choices: raw.choices,\r\n usage:\r\n raw.usage ?? { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\r\n model: raw.model ?? opts.model,\r\n provider: raw.provider ?? providerHeader ?? '',\r\n usageWarning,\r\n };\r\n },\r\n\r\n stream(opts: AiChatOptions): AiStreamHandle {\r\n const body = resolveAiBody(config, opts, true);\r\n // Dispara já — assim `meta` pode resolver assim que os headers chegam,\r\n // independente de o caller começar a iterar.\r\n const responsePromise = aiFetch(config, body, opts.signal, true);\r\n\r\n const meta: Promise<AiStreamMeta> = responsePromise.then(readMeta);\r\n // Evita unhandledRejection se o caller só itera e nunca toca `meta`\r\n // (o erro ainda propaga pelo for-await, que aguarda a mesma promise).\r\n meta.catch(() => {});\r\n\r\n async function* iterate(): AsyncGenerator<string, void, unknown> {\r\n const res = await responsePromise; // já lançou NeetruError se !ok\r\n const stream = res.body;\r\n if (!stream) {\r\n throw new NeetruError('invalid_response', 'ai.stream: response has no body');\r\n }\r\n const reader = stream.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n buffer += decoder.decode(value, { stream: true });\r\n let sep: number;\r\n // Processa todos os eventos completos acumulados no buffer.\r\n while ((sep = buffer.indexOf('\\n\\n')) !== -1) {\r\n const rawEvent = buffer.slice(0, sep);\r\n buffer = buffer.slice(sep + 2);\r\n const parsed = parseSseData(rawEvent);\r\n if (parsed && 'done' in parsed) return;\r\n if (parsed && 'content' in parsed) yield parsed.content;\r\n }\r\n }\r\n // Flush de um evento final sem `\\n\\n` de fechamento.\r\n const tail = buffer.trim();\r\n if (tail) {\r\n const parsed = parseSseData(tail);\r\n if (parsed && 'content' in parsed) yield parsed.content;\r\n }\r\n } finally {\r\n // Garante liberação/cancelamento mesmo em break precoce ou erro —\r\n // sem travar nem vazar o corpo da resposta.\r\n try {\r\n reader.releaseLock();\r\n } catch {\r\n /* ignore */\r\n }\r\n try {\r\n await stream.cancel();\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n }\r\n\r\n return {\r\n meta,\r\n [Symbol.asyncIterator]: iterate,\r\n };\r\n },\r\n };\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/validators.ts","../src/ai.ts"],"names":[],"mappings":"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","file":"ai.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 /** 3.0: runtime não expõe API necessária (ex: WebCrypto ausente). */\r\n | 'runtime_unsupported'\r\n /**\r\n * 3.1.3 (bug_c1c96a00): o `state` retornado pelo IdP no callback OIDC não bate com o gerado em\r\n * `signIn` (CSRF). Também usado quando não há transação OIDC pendente.\r\n */\r\n | 'oidc_state_mismatch'\r\n /**\r\n * 3.1.12 (incidente pdv-agiliza 2026-07-10): o `nonce` do `id_token` retornado\r\n * pelo `/token` não bate com o gerado em `signIn` (possível replay). O token\r\n * é descartado sem tocar o storage.\r\n */\r\n | 'oidc_nonce_mismatch'\r\n /**\r\n * 3.1.12: o POST `/api/v1/oauth/token` (troca do authorization_code por\r\n * tokens em `completeSignIn`) falhou — HTTP não-2xx, corpo com `error`, ou\r\n * resposta sem `id_token`.\r\n */\r\n | 'token_exchange_failed'\r\n /** HTTP 409 — colisão de idempotência ou conflito de recurso. */\r\n | 'conflict'\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 * Motivo semântico opcional propagado pelo Core no corpo do erro (campo\r\n * `reason` no TOPO do body, fora de `error`). Usado principalmente pelo 503\r\n * de lease de DB, onde `reason` discrimina o estado do ambiente\r\n * (`suspended` | `archived` | `revoked` | `provisioning` | `degraded` |\r\n * `no_route` | `expired`). Camadas superiores (ex.: `db/sql`) mapeiam isso\r\n * para um `NeetruDbErrorCode` mais específico (recuperável vs não).\r\n */\r\n public readonly reason?: 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 reason?: 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 this.reason = reason;\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.\r\n * - **Captura `X-Neetru-Version`** das respostas e emite `console.warn` quando\r\n * o Core está abaixo da versão mínima para a major do SDK.\r\n *\r\n * Política de retries (mudança breaking 3.0):\r\n * - GET/HEAD: default 2 retries (3 tentativas total) — idempotente, seguro.\r\n * - POST/PUT/PATCH/DELETE: default **0 retries** — mutations podem duplicar\r\n * side effects (ex: `usage.report` incrementa contador). Caller pode\r\n * reativar passando `retries: N` explicitamente ou usar `Idempotency-Key`\r\n * header (gerado automaticamente se `opts.idempotencyKey=true`).\r\n *\r\n * Idempotency-Key (3.0):\r\n * - `opts.idempotencyKey === true` → SDK gera UUID v4 e injeta header.\r\n * - `opts.idempotencyKey === 'uuid-string'` → usa o valor passado.\r\n * - Caller mantém retentos client-side se quiser; Core dedup serverside\r\n * (vide `docs/CORE_CHANGES_REQUIRED.md` §2).\r\n */\r\nimport { NeetruError, type NeetruErrorCode } from './errors';\r\nimport { generateIdempotencyKey } from './idempotency';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n// ─── Compat Matrix SDK↔Core ──────────────────────────────────────────────────\r\n\r\n/**\r\n * Matriz de compatibilidade SDK major → versão mínima do Core.\r\n *\r\n * Formato do Core: CalVer `YYYY.MM.patch+revision` (ex: `2026.05.1+neetru-core-00096-79t`).\r\n * A comparação é feita apenas nas partes `YYYY.MM.patch` (prefixo antes de `+`).\r\n *\r\n * Quando o Core reporta `X-Neetru-Version` abaixo do mínimo para a SDK major\r\n * corrente, o SDK emite `console.warn` uma única vez por sessão de processo.\r\n *\r\n * Atualize esta tabela a cada major de SDK.\r\n */\r\nconst COMPAT_MATRIX: Record<number, string> = {\r\n // SDK major 3.x requer Core ≥ 2026.05.1 (suporte a X-Neetru-Version header,\r\n // runTransaction write-after-read, verifyWebhookRequest, webhooks 3.0+)\r\n 3: '2026.05.1',\r\n};\r\n\r\n/** CalVer sem sufixo `+revision`. Ex: `2026.05.1+abc` → `2026.05.1`. */\r\nfunction stripRevision(v: string): string {\r\n return v.split('+')[0] ?? v;\r\n}\r\n\r\n/**\r\n * Compara dois CalVer (`YYYY.MM.patch`). Retorna negativo se `a < b`,\r\n * positivo se `a > b`, 0 se iguais. Partes não numéricas tratadas como 0.\r\n */\r\nfunction compareCalVer(a: string, b: string): number {\r\n const partsA = stripRevision(a).split('.').map(Number);\r\n const partsB = stripRevision(b).split('.').map(Number);\r\n const len = Math.max(partsA.length, partsB.length);\r\n for (let i = 0; i < len; i++) {\r\n const pa = partsA[i] ?? 0;\r\n const pb = partsB[i] ?? 0;\r\n if (pa !== pb) return pa - pb;\r\n }\r\n return 0;\r\n}\r\n\r\n/**\r\n * Versão do SDK injetada em tempo de build (tsup `define`, vide tsup.config.ts).\r\n * `undefined` fora de um build real (ex: rodando `.ts` direto em teste) --\r\n * consumers tratam a ausência como \"SDK pré-versionamento\" (caller antigo).\r\n */\r\nfunction readInjectedSdkVersion(): string | undefined {\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n return (globalThis as any).__NEETRU_SDK_VERSION__ as string | undefined;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/** Lê a SDK major a partir da versão injetada em build. Fallback 3. */\r\nfunction getSdkMajor(): number {\r\n const ver = readInjectedSdkVersion();\r\n if (ver) return parseInt(ver.split('.')[0] ?? '3', 10);\r\n return 3;\r\n}\r\n\r\n/** Aviso emitido no máximo uma vez por major detectada pra não spammar logs. */\r\nconst _warnedCoreTooOld = new Set<string>();\r\n\r\n/**\r\n * Verifica se a versão do Core (`X-Neetru-Version`) é compatível com a SDK major.\r\n * Emite `console.warn` quando incompatível (uma vez por processo por versão detectada).\r\n */\r\nexport function checkCoreVersionCompat(coreVersion: string): void {\r\n if (!coreVersion) return;\r\n const sdkMajor = getSdkMajor();\r\n const minCore = COMPAT_MATRIX[sdkMajor];\r\n if (!minCore) return; // sem restrição para esta major\r\n const stripped = stripRevision(coreVersion);\r\n if (compareCalVer(stripped, minCore) < 0) {\r\n const key = `${sdkMajor}:${stripped}`;\r\n if (!_warnedCoreTooOld.has(key)) {\r\n _warnedCoreTooOld.add(key);\r\n console.warn(\r\n `[Neetru SDK] Atenção: Core versão \"${coreVersion}\" é anterior ao mínimo recomendado` +\r\n ` \"${minCore}\" para SDK major ${sdkMajor}. Alguns recursos podem não funcionar` +\r\n ` corretamente. Atualize o Core para a versão mais recente.`,\r\n );\r\n }\r\n }\r\n}\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`).\r\n *\r\n * Default (3.0):\r\n * - GET/HEAD: 2 (= 3 tentativas total) — idempotente, seguro.\r\n * - POST/PUT/PATCH/DELETE: 0 — mutations podem duplicar side effects.\r\n *\r\n * Caller pode reativar passando explicitamente: `retries: 2`.\r\n */\r\n retries?: number;\r\n /**\r\n * Injeta `Idempotency-Key` header pra dedup serverside (3.0):\r\n * - `true` → SDK gera UUID v4 cripto-seguro automaticamente.\r\n * - string → usa o valor passado (deve ser UUID v4).\r\n * - `undefined`/`false` → sem header.\r\n */\r\n idempotencyKey?: boolean | string;\r\n}\r\n\r\nconst DEFAULT_RETRIES_READ = 2;\r\nconst DEFAULT_RETRIES_WRITE = 0;\r\nconst READ_METHODS = new Set(['GET', 'HEAD']);\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\n * Bug fix: sem teto, um servidor hostil/mal-configurado poderia retornar\r\n * `Retry-After: 86400` (24h) ou uma HTTP-date anos no futuro, pendurando o\r\n * processo indefinidamente. Aplica teto de MAX_RETRY_AFTER_MS em ambos os caminhos.\r\n */\r\nconst MAX_RETRY_AFTER_MS = 60_000; // 60s — teto razoável para retry automático\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.min(Math.round(secs * 1000), MAX_RETRY_AFTER_MS);\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 Math.min(delta, MAX_RETRY_AFTER_MS);\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/**\r\n * Mapeamento status → code estável do NeetruError. Exportado para reuso\r\n * (ex: `ai.ts` espelhava esta função duplicada — DRY, achado da auditoria\r\n * 2026-09-15).\r\n */\r\nexport function 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 === 409) return 'conflict'; // Bug fix: 409 vira 'conflict' (não 'unknown')\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 // Default por método: reads tentam 2x, writes 0x. Caller override sempre vence.\r\n const defaultRetries = READ_METHODS.has(method)\r\n ? DEFAULT_RETRIES_READ\r\n : DEFAULT_RETRIES_WRITE;\r\n const maxRetries = opts.retries ?? defaultRetries;\r\n\r\n const headers: Record<string, string> = {\r\n accept: 'application/json',\r\n ...opts.headers,\r\n };\r\n\r\n // Melhoria 2026-09-19: o Core não tinha NENHUMA visibilidade da versão do\r\n // SDK que fazia cada request -- quando uma rota mudava de contrato (ex:\r\n // telemetry/event exigindo Bearer incompatível com apiKey publicável), um\r\n // caller desatualizado só via 401 genérico, indistinguível de qualquer\r\n // outra falha de auth, e o Core não tinha como saber/alertar. Este header\r\n // é a base pra isso nunca mais falhar calado (ver sdk-compat no Core).\r\n // Ausência do header (build antigo, sem o `define` do tsup) já é sinal\r\n // suficiente de \"SDK pré-versionamento\" pro lado do Core.\r\n const sdkVersion = readInjectedSdkVersion();\r\n if (sdkVersion) {\r\n headers['x-neetru-sdk-version'] = sdkVersion;\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 // Idempotency-Key: gerado por chamada se solicitado. UUID v4 cripto-seguro.\r\n if (opts.idempotencyKey) {\r\n const key =\r\n typeof opts.idempotencyKey === 'string'\r\n ? opts.idempotencyKey\r\n : generateIdempotencyKey();\r\n headers['idempotency-key'] = key;\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 // Captura X-Neetru-Version e verifica compat com a SDK major.\r\n const coreVersion = res.headers.get('x-neetru-version');\r\n if (coreVersion) checkCoreVersionCompat(coreVersion);\r\n const parsed = await safeJson(res);\r\n return parsed as T;\r\n }\r\n\r\n // O contrato clássico de erro do Core é `{ error: { code, message } }`.\r\n // O 503 de lease de DB (e alguns endpoints novos) coloca `code`/`reason`/\r\n // `message` no TOPO do corpo, SEM envelope `error`. Lemos ambos: preferimos\r\n // `body.error` quando presente; caímos nos campos do topo caso contrário.\r\n // `reason` é sempre considerado no topo (o 503 de lease o coloca lá mesmo\r\n // quando há `error`), pra que a camada de DB discrimine suspended/archived/\r\n // revoked de provisioning/degraded.\r\n const body = (await safeJson(res)) as\r\n | {\r\n error?: { code?: string; message?: string; reason?: string } | string;\r\n code?: string;\r\n reason?: string;\r\n message?: string;\r\n }\r\n | undefined;\r\n let code: string = statusToCode(res.status);\r\n let message = `HTTP ${res.status}`;\r\n let reason: string | undefined;\r\n if (body && typeof body === 'object') {\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 if (typeof errField.reason === 'string') reason = errField.reason;\r\n } else {\r\n // Sem envelope `error` — lê os campos no TOPO do corpo (contrato do 503\r\n // de lease: `{ code, reason }` no topo).\r\n if (typeof body.code === 'string') code = body.code;\r\n if (typeof body.message === 'string') message = body.message;\r\n }\r\n // `reason` no topo tem prioridade final (o 503 de lease o coloca no topo\r\n // mesmo quando também há `error`).\r\n if (typeof body.reason === 'string') reason = body.reason;\r\n }\r\n const err = new NeetruError(code, message, res.status, requestId, reason);\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 * Validators centralizados pra inputs do SDK que precisam casar com\r\n * regex do Core.\r\n *\r\n * **M-03 fix (Opus review 2026-05-27):** o Core rejeita productId que\r\n * não bate `/^[a-z0-9][a-z0-9_-]{0,62}$/` com 400 `validation_failed`.\r\n * O SDK não pré-validava — consumer recebia erro só em runtime de\r\n * produção, depois do round-trip de rede. Agora SDK throws localmente\r\n * antes do fetch.\r\n */\r\nimport { NeetruError } from './errors';\r\n\r\n/**\r\n * Regex canonical de IDs no Neetru Core (productId, tenantId, etc).\r\n * Espelha `SDK_ID_RE` em `neetru_core/src/lib/schemas/sdk.ts`.\r\n *\r\n * `i` flag (2026-09, mesmo fix do Core em `SDK_ID_RE`/`db-lease`/\r\n * `checkout-intents` 5c47e6e6): productId real de produtos como o\r\n * PDV-Agiliza é um Firestore auto-ID mixed-case (ex.\r\n * `qkcWzQ43LthAIRlVUSQ6`), não um slug lowercase. Sem `i`, este validator\r\n * lançava `validation_failed` client-side ANTES de qualquer fetch — o SDK\r\n * bloqueava `usage.report()`/`usage.check()` pro produto real, mesmo o Core\r\n * já aceitando o mesmo id (mixed-case) em `db/lease`.\r\n */\r\nexport const SDK_ID_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/i;\r\n\r\n/**\r\n * Throws `NeetruError('validation_failed')` se `value` não bater no\r\n * formato canonical.\r\n *\r\n * @example\r\n * ```ts\r\n * assertValidSdkId('productId', 'gestovendas'); // ok\r\n * assertValidSdkId('productId', 'GestoVendas'); // throws\r\n * ```\r\n */\r\nexport function assertValidSdkId(field: string, value: string): void {\r\n if (typeof value !== 'string' || !SDK_ID_RE.test(value)) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n `${field} must match ${SDK_ID_RE.source} (lowercase alphanumeric, _, -; first char must be alphanumeric; max 63 chars)`,\r\n );\r\n }\r\n}\r\n","/**\r\n * AI namespace — AI Gateway do Core exposto pro produto (3.1.10).\r\n *\r\n * Fecha o AI Gateway E2E: o produto chama `client.ai.chat(...)` /\r\n * `client.ai.stream(...)` e o Core roteia pro provider (OpenAI-compat),\r\n * aplica cota/entitlement e devolve resposta ou SSE.\r\n *\r\n * Endpoint consumido:\r\n * - `POST /api/sdk/v1/ai/chat` — Bearer + JSON.\r\n * Body: `{ productId, tenantId, model, messages, stream, maxTokens?, temperature? }`.\r\n * - `stream:false` → 200 JSON `{ ok, choices, usage, model, provider }`.\r\n * - `stream:true` → `text/event-stream`: `data: {chunk}\\n\\n` … `data: [DONE]\\n\\n`.\r\n * - Headers de resposta em ambos: `X-Neetru-Provider`, `X-Neetru-Ai-Usage-Warning`\r\n * ('1' quando a cota do tenant passou de 80%).\r\n *\r\n * Por que `config.fetch` cru (e não `httpRequest`)?\r\n * - `httpRequest` devolve só o body parseado; aqui preciso dos **headers**\r\n * de resposta (`X-Neetru-Provider` / `X-Neetru-Ai-Usage-Warning`) e do\r\n * **body como stream** (SSE). Então falo direto com `config.fetch`,\r\n * reusando o mesmo mapeamento status→NeetruError do transport.\r\n *\r\n * Retry: **nenhum**. Chat é POST (custo real por chamada — não duplica) e\r\n * streaming não pode ser retriado cegamente (já emitiu bytes).\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { checkCoreVersionCompat, statusToCode } from './http';\r\nimport { assertValidSdkId } from './validators';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n// ─── Tipos públicos ──────────────────────────────────────────────────────────\r\n\r\n/** Bloco de texto de uma mensagem multimodal (OpenAI-compat). */\r\nexport interface AiTextPart {\r\n type: 'text';\r\n text: string;\r\n}\r\n\r\n/**\r\n * Bloco de imagem de uma mensagem multimodal (OpenAI-compat).\r\n *\r\n * `url` pode ser:\r\n * - `data:image/<png|jpeg|jpg|gif|webp>;base64,<...>` — auto-contida.\r\n * - `https://...` — o Core NÃO busca a URL; quem busca é o provider upstream.\r\n *\r\n * Qualquer outro esquema (`http:`, `file:`, etc.) é rejeitado por segurança.\r\n */\r\nexport interface AiImageUrlPart {\r\n type: 'image_url';\r\n image_url: {\r\n url: string;\r\n /** Hint de fidelidade OpenAI: 'low' | 'high' | 'auto'. */\r\n detail?: string;\r\n };\r\n}\r\n\r\n/** Parte de conteúdo multimodal. */\r\nexport type AiContentPart = AiTextPart | AiImageUrlPart;\r\n\r\n/**\r\n * Formato de saída estruturada (opt-in). Espelha `response_format` do OpenAI.\r\n * Omitido = comportamento default do modelo (texto livre). Anthropic é\r\n * best-effort (o Core injeta uma diretiva de system prompt).\r\n */\r\nexport type AiResponseFormat =\r\n | { type: 'text' }\r\n | { type: 'json_object' }\r\n | {\r\n type: 'json_schema';\r\n json_schema: {\r\n name: string;\r\n schema?: Record<string, unknown>;\r\n description?: string;\r\n strict?: boolean;\r\n };\r\n };\r\n\r\n/**\r\n * Uma mensagem do diálogo (OpenAI-compat).\r\n *\r\n * `content` aceita string pura (retrocompat) OU array de partes multimodais\r\n * (`text` / `image_url`). String continua funcionando idêntico.\r\n */\r\nexport interface AiChatMessage {\r\n role: string;\r\n content: string | AiContentPart[];\r\n}\r\n\r\n/**\r\n * Opções de `ai.chat()` / `ai.stream()`.\r\n *\r\n * `productId`/`tenantId` são opcionais aqui: se o client já foi criado com\r\n * eles (`createNeetruClient({ productId, tenantId })`), viram default.\r\n */\r\nexport interface AiChatOptions {\r\n /** Default = `config.productId`. Obrigatório (opts OU config). */\r\n productId?: string;\r\n /** Default = `config.tenantId`. Obrigatório (opts OU config). */\r\n tenantId?: string;\r\n /** Modelo alvo (ex: `gpt-4o-mini`). O Core valida/roteia. */\r\n model: string;\r\n /** Diálogo. Array não-vazio de `{role, content}`. */\r\n messages: AiChatMessage[];\r\n /** Teto de tokens de saída (opcional). */\r\n maxTokens?: number;\r\n /** Temperatura de amostragem (opcional). */\r\n temperature?: number;\r\n /**\r\n * Saída estruturada opt-in (`json_object` / `json_schema`). Omitido =\r\n * comportamento default do modelo. O Core mapeia pro `response_format` nativo\r\n * dos providers OpenAI-compat; Anthropic é best-effort via system prompt.\r\n */\r\n responseFormat?: AiResponseFormat;\r\n /** AbortSignal do caller (cancela a request / o stream). */\r\n signal?: AbortSignal;\r\n}\r\n\r\n/** Uso de tokens (OpenAI-compat, pass-through do Core). */\r\nexport interface AiChatUsage {\r\n prompt_tokens: number;\r\n completion_tokens: number;\r\n total_tokens: number;\r\n}\r\n\r\n/** Uma escolha do modelo (OpenAI-compat). */\r\nexport interface AiChatChoice {\r\n message: { role: string; content: string };\r\n finish_reason?: string | null;\r\n}\r\n\r\n/** Retorno de `ai.chat()` (non-stream). */\r\nexport interface AiChatResult {\r\n choices: AiChatChoice[];\r\n usage: AiChatUsage;\r\n model: string;\r\n /** Provider que atendeu (do body; fallback header `X-Neetru-Provider`). */\r\n provider: string;\r\n /** `true` quando o Core sinalizou `X-Neetru-Ai-Usage-Warning: 1` (cota ≥80%). */\r\n usageWarning: boolean;\r\n}\r\n\r\n/** Metadados do stream (resolvidos quando os headers da resposta chegam). */\r\nexport interface AiStreamMeta {\r\n provider: string;\r\n usageWarning: boolean;\r\n}\r\n\r\n/**\r\n * Handle retornado por `ai.stream()`: um `AsyncIterable<string>` que yielda os\r\n * deltas de conteúdo conforme chegam, mais `meta` (provider/usageWarning) que\r\n * resolve assim que os headers da resposta chegam.\r\n *\r\n * @example\r\n * ```ts\r\n * const s = client.ai.stream({ model: 'gpt-4o-mini', messages });\r\n * for await (const delta of s) process.stdout.write(delta);\r\n * const { provider, usageWarning } = await s.meta;\r\n * ```\r\n */\r\nexport interface AiStreamHandle extends AsyncIterable<string> {\r\n readonly meta: Promise<AiStreamMeta>;\r\n}\r\n\r\n/** Namespace `client.ai`. */\r\nexport interface AiNamespace {\r\n /** Completa um chat (non-stream). Lança `NeetruError` em falha. */\r\n chat(opts: AiChatOptions): Promise<AiChatResult>;\r\n /** Abre um stream SSE. Yielda deltas de conteúdo (string). */\r\n stream(opts: AiChatOptions): AiStreamHandle;\r\n}\r\n\r\n// ─── Internos ────────────────────────────────────────────────────────────────\r\n\r\nconst AI_CHAT_PATH = '/api/sdk/v1/ai/chat';\r\n/** Timeout do chat non-stream. Modelos podem ser lentos → generoso. */\r\nconst AI_NONSTREAM_TIMEOUT_MS = 120_000;\r\n\r\ninterface AiRequestBody {\r\n productId: string;\r\n tenantId: string;\r\n model: string;\r\n messages: AiChatMessage[];\r\n stream: boolean;\r\n maxTokens?: number;\r\n temperature?: number;\r\n responseFormat?: AiResponseFormat;\r\n}\r\n\r\n// ─── Validação de conteúdo multimodal (espelha `@/lib/ai-gateway/content` do\r\n// Core — mesmos limites e esquemas de URL permitidos) ───────────────────────\r\n\r\n/** Teto de um bloco de texto. */\r\nconst MAX_TEXT_PART_LEN = 32_768;\r\n/** Máximo de partes por mensagem (anti-DoS). */\r\nconst MAX_CONTENT_PARTS = 32;\r\n/** Teto de uma `data:` URL base64 (≈ 3.9 MiB). */\r\nconst MAX_DATA_URL_LEN = 4_194_304;\r\n/** Teto de uma `https://` URL de imagem. */\r\nconst MAX_HTTPS_URL_LEN = 2_048;\r\nconst DATA_IMAGE_URL_RE = /^data:image\\/(?:png|jpe?g|gif|webp);base64,[A-Za-z0-9+/]+={0,2}$/;\r\nconst HTTPS_URL_RE = /^https:\\/\\/[^\\s]+$/;\r\nconst IMAGE_DETAIL_VALUES = new Set(['low', 'high', 'auto']);\r\n\r\n// ─── Contrato de request (espelha os limites do Core `AiChatRequestSchema` —\r\n// mesmos números, pra o SDK NÃO deixar passar o que o Core rejeita) ────────\r\n/** Roles válidas (enum do Core, não string qualquer). */\r\nconst AI_ROLES = new Set(['system', 'user', 'assistant']);\r\n/** Máximo de mensagens por request. */\r\nconst MAX_MESSAGES = 100;\r\n/** Comprimento máximo do nome do modelo. */\r\nconst MAX_MODEL_LEN = 128;\r\n/** Teto de maxTokens. */\r\nconst MAX_TOKENS_CAP = 32_768;\r\n/** Faixa de temperature. */\r\nconst MIN_TEMPERATURE = 0;\r\nconst MAX_TEMPERATURE = 2;\r\n\r\n// ─── Limites AGREGADOS por request (espelham `content.ts` do Core) ────────────\r\nconst MAX_TOTAL_CONTENT_PARTS = 200;\r\nconst MAX_TOTAL_IMAGES = 20;\r\nconst MAX_TOTAL_IMAGE_BYTES = 12 * 1024 * 1024;\r\n\r\n// ─── Limites do JSON Schema de saída estruturada (espelham o Core) ────────────\r\nconst MAX_SCHEMA_JSON_LEN = 50_000;\r\nconst MAX_SCHEMA_DEPTH = 16;\r\nconst MAX_SCHEMA_KEYS = 500;\r\nconst FORBIDDEN_SCHEMA_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\r\nconst RESPONSE_FORMAT_NAME_RE = /^[a-zA-Z0-9_-]+$/;\r\n\r\nfunction fail(msg: string): never {\r\n throw new NeetruError('validation_failed', msg);\r\n}\r\n\r\n/** Valida ESTRITAMENTE o corpo base64 de uma data-URL (comprimento/padding). */\r\nfunction isStrictBase64Payload(b64: string): boolean {\r\n if (b64.length === 0 || b64.length % 4 !== 0) return false;\r\n const pad = b64.endsWith('==') ? 2 : b64.endsWith('=') ? 1 : 0;\r\n const body = pad > 0 ? b64.slice(0, b64.length - pad) : b64;\r\n return !body.includes('=');\r\n}\r\n\r\n/** Bytes DECODIFICADOS aproximados de uma data-URL base64. */\r\nfunction dataUrlDecodedBytes(url: string): number {\r\n const comma = url.indexOf(',');\r\n if (comma === -1) return 0;\r\n const b64 = url.slice(comma + 1);\r\n const pad = b64.endsWith('==') ? 2 : b64.endsWith('=') ? 1 : 0;\r\n return Math.max(0, Math.floor((b64.length * 3) / 4) - pad);\r\n}\r\n\r\n/**\r\n * Impõe os limites AGREGADOS por request (soma de TODAS as mensagens). Espelha\r\n * `checkAggregateMultimodalLimits` do Core — MESMA política, mesmos números.\r\n * Retorna a mensagem de erro ou `null`.\r\n */\r\nfunction checkAggregateMultimodalLimits(messages: ReadonlyArray<{ content?: unknown }>): string | null {\r\n let totalParts = 0;\r\n let totalImages = 0;\r\n let totalImageBytes = 0;\r\n for (const m of messages) {\r\n const content = m?.content;\r\n if (!Array.isArray(content)) continue;\r\n for (const part of content) {\r\n totalParts++;\r\n if (totalParts > MAX_TOTAL_CONTENT_PARTS) {\r\n return `ai: total content parts exceeds ${MAX_TOTAL_CONTENT_PARTS} per request`;\r\n }\r\n if (part && typeof part === 'object' && (part as { type?: unknown }).type === 'image_url') {\r\n totalImages++;\r\n if (totalImages > MAX_TOTAL_IMAGES) {\r\n return `ai: total images exceeds ${MAX_TOTAL_IMAGES} per request`;\r\n }\r\n const url = (part as { image_url?: { url?: unknown } }).image_url?.url;\r\n if (typeof url === 'string' && url.startsWith('data:')) {\r\n totalImageBytes += dataUrlDecodedBytes(url);\r\n if (totalImageBytes > MAX_TOTAL_IMAGE_BYTES) {\r\n return `ai: aggregate image bytes exceeds ${MAX_TOTAL_IMAGE_BYTES} per request`;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Valida o objeto `schema` de `json_schema` — espelha `validateStructuredSchema`\r\n * do Core (tamanho serializado, profundidade, nº de chaves, e rejeição de\r\n * `__proto__`/`constructor`/`prototype`). Retorna a mensagem de erro ou `null`.\r\n */\r\nfunction validateStructuredSchema(schema: unknown): string | null {\r\n if (schema === undefined) return null;\r\n if (schema === null || typeof schema !== 'object') {\r\n return 'ai: responseFormat json_schema.schema must be an object';\r\n }\r\n let serialized: string | undefined;\r\n try {\r\n serialized = JSON.stringify(schema);\r\n } catch {\r\n return 'ai: responseFormat json_schema.schema is not serializable';\r\n }\r\n if (serialized === undefined) return 'ai: responseFormat json_schema.schema is invalid';\r\n if (serialized.length > MAX_SCHEMA_JSON_LEN) {\r\n return `ai: responseFormat json_schema.schema exceeds ${MAX_SCHEMA_JSON_LEN} serialized chars`;\r\n }\r\n let keyCount = 0;\r\n const walk = (node: unknown, depth: number): string | null => {\r\n if (depth > MAX_SCHEMA_DEPTH) {\r\n return `ai: responseFormat json_schema.schema exceeds max depth ${MAX_SCHEMA_DEPTH}`;\r\n }\r\n if (Array.isArray(node)) {\r\n for (const item of node) {\r\n const e = walk(item, depth + 1);\r\n if (e) return e;\r\n }\r\n return null;\r\n }\r\n if (node && typeof node === 'object') {\r\n for (const key of Object.getOwnPropertyNames(node)) {\r\n if (FORBIDDEN_SCHEMA_KEYS.has(key)) {\r\n return `ai: responseFormat json_schema.schema has forbidden key: ${key}`;\r\n }\r\n keyCount++;\r\n if (keyCount > MAX_SCHEMA_KEYS) {\r\n return `ai: responseFormat json_schema.schema exceeds ${MAX_SCHEMA_KEYS} keys`;\r\n }\r\n const e = walk((node as Record<string, unknown>)[key], depth + 1);\r\n if (e) return e;\r\n }\r\n }\r\n return null;\r\n };\r\n return walk(schema, 0);\r\n}\r\n\r\n/** Valida a `url` de um `image_url` (data:base64 ou https, com limites). */\r\nfunction validateImageUrl(url: unknown): void {\r\n if (typeof url !== 'string' || url.length === 0) {\r\n fail('ai: image_url.url must be a non-empty string');\r\n }\r\n const u = url as string;\r\n if (u.startsWith('data:')) {\r\n if (u.length > MAX_DATA_URL_LEN) fail(`ai: image_url.url (data:) exceeds ${MAX_DATA_URL_LEN} chars`);\r\n if (!DATA_IMAGE_URL_RE.test(u)) {\r\n fail('ai: image_url.url data: must be data:image/<png|jpeg|jpg|gif|webp>;base64,<...>');\r\n }\r\n // Valida comprimento/padding do base64 (a regex não garante múltiplo de 4).\r\n const b64 = u.slice(u.indexOf(',') + 1);\r\n if (!isStrictBase64Payload(b64)) {\r\n fail('ai: image_url.url data: has invalid base64 (length/padding)');\r\n }\r\n return;\r\n }\r\n if (u.startsWith('https://')) {\r\n if (u.length > MAX_HTTPS_URL_LEN) fail(`ai: image_url.url (https:) exceeds ${MAX_HTTPS_URL_LEN} chars`);\r\n if (!HTTPS_URL_RE.test(u)) fail('ai: image_url.url https: is invalid');\r\n return;\r\n }\r\n fail('ai: image_url.url must be a data:image/...;base64 or https:// URL (other schemes are rejected)');\r\n}\r\n\r\n/**\r\n * Valida o `content` de uma mensagem: string OU array de partes multimodais.\r\n * `role` é usado pra restringir imagem: `image_url` só é permitida em `user`\r\n * (mesma decisão do Core — imagem em system/assistant é rejeitada).\r\n */\r\nfunction validateAiContent(content: unknown, role: string): void {\r\n if (typeof content === 'string') {\r\n if (content.length === 0) fail('ai: message content string must be non-empty');\r\n if (content.length > MAX_TEXT_PART_LEN) fail(`ai: message content exceeds ${MAX_TEXT_PART_LEN} chars`);\r\n return;\r\n }\r\n if (!Array.isArray(content) || content.length === 0) {\r\n fail('ai: message content must be a non-empty string or array of parts');\r\n }\r\n if (content.length > MAX_CONTENT_PARTS) fail(`ai: message content has more than ${MAX_CONTENT_PARTS} parts`);\r\n for (const part of content) {\r\n if (!part || typeof part !== 'object') fail('ai: each content part must be an object');\r\n const type = (part as { type?: unknown }).type;\r\n if (type === 'text') {\r\n const text = (part as { text?: unknown }).text;\r\n if (typeof text !== 'string' || text.length === 0) fail('ai: text part must have non-empty { text: string }');\r\n if (text.length > MAX_TEXT_PART_LEN) fail(`ai: text part exceeds ${MAX_TEXT_PART_LEN} chars`);\r\n } else if (type === 'image_url') {\r\n if (role !== 'user') {\r\n fail(`ai: image_url is only allowed in role 'user' messages (got '${role}')`);\r\n }\r\n const iu = (part as { image_url?: unknown }).image_url;\r\n if (!iu || typeof iu !== 'object') fail('ai: image_url part must have { image_url: { url } }');\r\n validateImageUrl((iu as { url?: unknown }).url);\r\n const detail = (iu as { detail?: unknown }).detail;\r\n if (detail !== undefined && (typeof detail !== 'string' || !IMAGE_DETAIL_VALUES.has(detail))) {\r\n fail(\"ai: image_url.detail must be 'low' | 'high' | 'auto'\");\r\n }\r\n } else {\r\n fail(\"ai: content part type must be 'text' or 'image_url'\");\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Valida `responseFormat` (opt-in). Espelha EXATAMENTE o `AiResponseFormatSchema`\r\n * do Core: `name` regex `a-zA-Z0-9_-` + max 64, `schema` objeto (com os mesmos\r\n * limites de tamanho/profundidade/chaves), `description` max 1000, `strict`\r\n * boolean — pra o SDK não deixar passar o que o Core rejeita.\r\n */\r\nfunction validateResponseFormat(rf: unknown): void {\r\n if (!rf || typeof rf !== 'object') fail('ai: responseFormat must be an object');\r\n const type = (rf as { type?: unknown }).type;\r\n if (type === 'text' || type === 'json_object') return;\r\n if (type === 'json_schema') {\r\n const js = (rf as { json_schema?: unknown }).json_schema;\r\n if (!js || typeof js !== 'object') fail('ai: responseFormat json_schema requires { json_schema: { name } }');\r\n const jso = js as { name?: unknown; schema?: unknown; description?: unknown; strict?: unknown };\r\n const name = jso.name;\r\n if (typeof name !== 'string' || name.length === 0) fail('ai: responseFormat json_schema.name is required');\r\n if (name.length > 64) fail('ai: responseFormat json_schema.name exceeds 64 chars');\r\n if (!RESPONSE_FORMAT_NAME_RE.test(name)) fail('ai: responseFormat json_schema.name must match a-zA-Z0-9_-');\r\n if (jso.description !== undefined) {\r\n if (typeof jso.description !== 'string') fail('ai: responseFormat json_schema.description must be a string');\r\n if (jso.description.length > 1000) fail('ai: responseFormat json_schema.description exceeds 1000 chars');\r\n }\r\n if (jso.strict !== undefined && typeof jso.strict !== 'boolean') {\r\n fail('ai: responseFormat json_schema.strict must be a boolean');\r\n }\r\n if (jso.schema !== undefined) {\r\n const err = validateStructuredSchema(jso.schema);\r\n if (err) fail(err);\r\n }\r\n return;\r\n }\r\n fail(\"ai: responseFormat.type must be 'text' | 'json_object' | 'json_schema'\");\r\n}\r\n\r\n/** Valida input e resolve o body canonical enviado ao Core. */\r\nfunction resolveAiBody(\r\n config: ResolvedConfig,\r\n opts: AiChatOptions,\r\n stream: boolean,\r\n): AiRequestBody {\r\n if (!opts || typeof opts !== 'object') {\r\n throw new NeetruError('validation_failed', 'ai: options object is required');\r\n }\r\n if (typeof opts.model !== 'string' || opts.model.length === 0) {\r\n throw new NeetruError('validation_failed', 'ai: model is required');\r\n }\r\n if (opts.model.length > MAX_MODEL_LEN) {\r\n throw new NeetruError('validation_failed', `ai: model exceeds ${MAX_MODEL_LEN} chars`);\r\n }\r\n if (!Array.isArray(opts.messages) || opts.messages.length === 0) {\r\n throw new NeetruError('validation_failed', 'ai: messages must be a non-empty array');\r\n }\r\n if (opts.messages.length > MAX_MESSAGES) {\r\n throw new NeetruError('validation_failed', `ai: messages exceeds ${MAX_MESSAGES} per request`);\r\n }\r\n for (const m of opts.messages) {\r\n // role é um ENUM (system|user|assistant), não string qualquer — alinha ao\r\n // `AiMessageSchema` do Core (senão o SDK deixa passar o que o Core rejeita).\r\n if (!m || typeof m !== 'object' || typeof m.role !== 'string' || !AI_ROLES.has(m.role)) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n \"ai: each message role must be 'system' | 'user' | 'assistant'\",\r\n );\r\n }\r\n // Aceita string (retrocompat) OU array de partes multimodais (text/image_url).\r\n validateAiContent((m as AiChatMessage).content, m.role);\r\n }\r\n // Limites AGREGADOS por request (mesma política/números do Core).\r\n const aggErr = checkAggregateMultimodalLimits(opts.messages);\r\n if (aggErr) throw new NeetruError('validation_failed', aggErr);\r\n const productId = opts.productId ?? config.productId;\r\n const tenantId = opts.tenantId ?? config.tenantId;\r\n if (!productId) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'ai: 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 'ai: tenantId required (pass to options or set on createNeetruClient)',\r\n );\r\n }\r\n assertValidSdkId('productId', productId);\r\n assertValidSdkId('tenantId', tenantId);\r\n\r\n const body: AiRequestBody = {\r\n productId,\r\n tenantId,\r\n model: opts.model,\r\n messages: opts.messages,\r\n stream,\r\n };\r\n if (opts.maxTokens !== undefined) {\r\n if (!Number.isInteger(opts.maxTokens) || opts.maxTokens <= 0 || opts.maxTokens > MAX_TOKENS_CAP) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n `ai: maxTokens must be a positive integer <= ${MAX_TOKENS_CAP}`,\r\n );\r\n }\r\n body.maxTokens = opts.maxTokens;\r\n }\r\n if (opts.temperature !== undefined) {\r\n if (\r\n typeof opts.temperature !== 'number' ||\r\n !Number.isFinite(opts.temperature) ||\r\n opts.temperature < MIN_TEMPERATURE ||\r\n opts.temperature > MAX_TEMPERATURE\r\n ) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n `ai: temperature must be a finite number between ${MIN_TEMPERATURE} and ${MAX_TEMPERATURE}`,\r\n );\r\n }\r\n body.temperature = opts.temperature;\r\n }\r\n if (opts.responseFormat !== undefined) {\r\n validateResponseFormat(opts.responseFormat);\r\n body.responseFormat = opts.responseFormat;\r\n }\r\n return body;\r\n}\r\n\r\n/** Parse JSON defensivo de uma Response — `undefined` em body vazio/inválido. */\r\nasync function safeJson(res: Response): Promise<unknown> {\r\n try {\r\n const text = await res.text();\r\n if (!text) return undefined;\r\n return JSON.parse(text);\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\nfunction joinUrl(baseUrl: string, path: string): string {\r\n const base = baseUrl.replace(/\\/+$/, '');\r\n const p = path.startsWith('/') ? path : `/${path}`;\r\n return `${base}${p}`;\r\n}\r\n\r\n/**\r\n * Executa o POST no gateway e devolve a `Response` com body **intacto** em\r\n * sucesso (o caller lê `.json()` ou `.body`). Em `!res.ok`, extrai\r\n * `error.code`/`error.message` do body e lança `NeetruError` — o `code` do\r\n * Core (`ai_unavailable`, `token_limit_exceeded`, `forbidden_product`, …)\r\n * vence o code genérico derivado do status.\r\n */\r\nasync function aiFetch(\r\n config: ResolvedConfig,\r\n body: AiRequestBody,\r\n signal: AbortSignal | undefined,\r\n stream: boolean,\r\n): Promise<Response> {\r\n if (!config.apiKey) {\r\n throw new NeetruError(\r\n 'missing_api_key',\r\n 'ai requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.',\r\n );\r\n }\r\n const url = joinUrl(config.baseUrl, AI_CHAT_PATH);\r\n const headers: Record<string, string> = {\r\n 'content-type': 'application/json',\r\n accept: stream ? 'text/event-stream' : 'application/json',\r\n authorization: `Bearer ${config.apiKey}`,\r\n };\r\n const init: RequestInit = { method: 'POST', headers, body: JSON.stringify(body) };\r\n // Non-stream: timeout defensivo (ou signal do caller se passado).\r\n // Stream: só o signal do caller — timeout fixo mataria stream longo legítimo.\r\n if (stream) {\r\n if (signal) init.signal = signal;\r\n } else {\r\n init.signal = signal ?? AbortSignal.timeout(AI_NONSTREAM_TIMEOUT_MS);\r\n }\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 ${AI_NONSTREAM_TIMEOUT_MS / 1000}s`\r\n : err instanceof DOMException && err.name === 'AbortError'\r\n ? 'Network error: request aborted'\r\n : `Network error: ${err instanceof Error ? err.message : 'fetch failed'}`;\r\n throw new NeetruError('network_error', message);\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)) 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 (parsed && typeof parsed === 'object' && 'error' in parsed) {\r\n const errField = parsed.error;\r\n if (typeof errField === 'string') {\r\n message = errField;\r\n } else if (errField && typeof errField === 'object') {\r\n // O code do gateway (ai_unavailable/token_limit_exceeded/forbidden_product…)\r\n // vence o genérico do status — não pode ser engolido.\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 throw new NeetruError(code, message, res.status, requestId);\r\n }\r\n\r\n const coreVersion = res.headers.get('x-neetru-version');\r\n if (coreVersion) checkCoreVersionCompat(coreVersion);\r\n return res;\r\n}\r\n\r\nfunction readMeta(res: Response): AiStreamMeta {\r\n return {\r\n provider: res.headers.get('x-neetru-provider') ?? '',\r\n usageWarning: res.headers.get('x-neetru-ai-usage-warning') === '1',\r\n };\r\n}\r\n\r\n/**\r\n * Extrai o conteúdo de um evento SSE (bloco entre `\\n\\n`).\r\n * - `{ done: true }` quando o evento é `[DONE]`.\r\n * - `{ content }` quando extraiu `choices[0].delta.content`.\r\n * - `null` quando é comentário/keep-alive/JSON inválido/sem delta (ignorar).\r\n * Junta múltiplas linhas `data:` do mesmo evento (SSE permite; OpenAI manda 1).\r\n */\r\nfunction parseSseData(rawEvent: string): { done: true } | { content: string } | null {\r\n const dataLines: string[] = [];\r\n for (const line of rawEvent.split('\\n')) {\r\n const trimmed = line.replace(/\\r$/, '');\r\n if (trimmed.startsWith('data:')) {\r\n // Strip 'data:' + no máximo um espaço de cortesia.\r\n let v = trimmed.slice(5);\r\n if (v.startsWith(' ')) v = v.slice(1);\r\n dataLines.push(v);\r\n }\r\n }\r\n if (dataLines.length === 0) return null;\r\n const payload = dataLines.join('\\n');\r\n if (payload === '[DONE]') return { done: true };\r\n try {\r\n const obj = JSON.parse(payload) as {\r\n choices?: Array<{ delta?: { content?: unknown } }>;\r\n };\r\n const content = obj?.choices?.[0]?.delta?.content;\r\n if (typeof content === 'string' && content.length > 0) return { content };\r\n return null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ─── Factory ─────────────────────────────────────────────────────────────────\r\n\r\nexport function createAiNamespace(config: ResolvedConfig): AiNamespace {\r\n return {\r\n async chat(opts: AiChatOptions): Promise<AiChatResult> {\r\n const body = resolveAiBody(config, opts, false);\r\n const res = await aiFetch(config, body, opts.signal, false);\r\n const { provider: providerHeader, usageWarning } = readMeta(res);\r\n const raw = (await safeJson(res)) as\r\n | {\r\n ok?: boolean;\r\n choices?: AiChatChoice[];\r\n usage?: AiChatUsage;\r\n model?: string;\r\n provider?: string;\r\n }\r\n | undefined;\r\n if (!raw || raw.ok !== true || !Array.isArray(raw.choices)) {\r\n throw new NeetruError('invalid_response', 'ai.chat response missing ok/choices');\r\n }\r\n return {\r\n choices: raw.choices,\r\n usage:\r\n raw.usage ?? { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\r\n model: raw.model ?? opts.model,\r\n provider: raw.provider ?? providerHeader ?? '',\r\n usageWarning,\r\n };\r\n },\r\n\r\n stream(opts: AiChatOptions): AiStreamHandle {\r\n const body = resolveAiBody(config, opts, true);\r\n // Dispara já — assim `meta` pode resolver assim que os headers chegam,\r\n // independente de o caller começar a iterar.\r\n const responsePromise = aiFetch(config, body, opts.signal, true);\r\n\r\n const meta: Promise<AiStreamMeta> = responsePromise.then(readMeta);\r\n // Evita unhandledRejection se o caller só itera e nunca toca `meta`\r\n // (o erro ainda propaga pelo for-await, que aguarda a mesma promise).\r\n meta.catch(() => {});\r\n\r\n async function* iterate(): AsyncGenerator<string, void, unknown> {\r\n const res = await responsePromise; // já lançou NeetruError se !ok\r\n const stream = res.body;\r\n if (!stream) {\r\n throw new NeetruError('invalid_response', 'ai.stream: response has no body');\r\n }\r\n const reader = stream.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n buffer += decoder.decode(value, { stream: true });\r\n let sep: number;\r\n // Processa todos os eventos completos acumulados no buffer.\r\n while ((sep = buffer.indexOf('\\n\\n')) !== -1) {\r\n const rawEvent = buffer.slice(0, sep);\r\n buffer = buffer.slice(sep + 2);\r\n const parsed = parseSseData(rawEvent);\r\n if (parsed && 'done' in parsed) return;\r\n if (parsed && 'content' in parsed) yield parsed.content;\r\n }\r\n }\r\n // Flush de um evento final sem `\\n\\n` de fechamento.\r\n const tail = buffer.trim();\r\n if (tail) {\r\n const parsed = parseSseData(tail);\r\n if (parsed && 'content' in parsed) yield parsed.content;\r\n }\r\n } finally {\r\n // Garante liberação/cancelamento mesmo em break precoce ou erro —\r\n // sem travar nem vazar o corpo da resposta.\r\n try {\r\n reader.releaseLock();\r\n } catch {\r\n /* ignore */\r\n }\r\n try {\r\n await stream.cancel();\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n }\r\n\r\n return {\r\n meta,\r\n [Symbol.asyncIterator]: iterate,\r\n };\r\n },\r\n };\r\n}\r\n"]}
package/dist/auth.cjs CHANGED
@@ -64,7 +64,8 @@ var init_idempotency = __esm({
64
64
  var http_exports = {};
65
65
  __export(http_exports, {
66
66
  checkCoreVersionCompat: () => checkCoreVersionCompat,
67
- httpRequest: () => httpRequest
67
+ httpRequest: () => httpRequest,
68
+ statusToCode: () => statusToCode
68
69
  });
69
70
  function stripRevision(v) {
70
71
  return v.split("+")[0] ?? v;
@@ -80,12 +81,16 @@ function compareCalVer(a, b) {
80
81
  }
81
82
  return 0;
82
83
  }
83
- function getSdkMajor() {
84
+ function readInjectedSdkVersion() {
84
85
  try {
85
- const ver = globalThis.__NEETRU_SDK_VERSION__;
86
- if (ver) return parseInt(ver.split(".")[0] ?? "3", 10);
86
+ return "3.5.0";
87
87
  } catch {
88
+ return void 0;
88
89
  }
90
+ }
91
+ function getSdkMajor() {
92
+ const ver = readInjectedSdkVersion();
93
+ if (ver) return parseInt(ver.split(".")[0] ?? "3", 10);
89
94
  return 3;
90
95
  }
91
96
  function checkCoreVersionCompat(coreVersion) {
@@ -163,6 +168,10 @@ async function httpRequest(config, opts) {
163
168
  accept: "application/json",
164
169
  ...opts.headers
165
170
  };
171
+ const sdkVersion = readInjectedSdkVersion();
172
+ if (sdkVersion) {
173
+ headers["x-neetru-sdk-version"] = sdkVersion;
174
+ }
166
175
  if (opts.requireAuth) {
167
176
  if (!config.apiKey) {
168
177
  throw new NeetruError(
@@ -527,7 +536,7 @@ var init_lease = __esm({
527
536
  void this._doRenew();
528
537
  }, MIN_RENEWAL_DELAY_MS);
529
538
  console.warn(
530
- `[SqlLeaseManager] renova\xE7\xE3o E emiss\xE3o de lease novo falharam; re-tentando em ${MIN_RENEWAL_DELAY_MS}ms (cert mTLS expira ~15min ap\xF3s o \xFAltimo swap):`,
539
+ `[SqlLeaseManager] renova\xE7\xE3o E emiss\xE3o de lease novo falharam; re-tentando em ${MIN_RENEWAL_DELAY_MS}ms (cert TLS ef\xEAmero do servidor expira ~15min ap\xF3s o \xFAltimo swap):`,
531
540
  err instanceof Error ? err.message : err
532
541
  );
533
542
  return;
@@ -538,8 +547,9 @@ var init_lease = __esm({
538
547
  /**
539
548
  * Recuperação REATIVA: chamado pelo wrapper resiliente (`resilient-pool.ts`)
540
549
  * quando uma query plana falha num erro de ESTABELECIMENTO de conexão (cert
541
- * mTLS expirado no meio de uma request, ou timer de renovação que não
542
- * disparou). Emite um lease NOVO e faz o swap do pool interno do wrapper com
550
+ * TLS efêmero do servidor expirado no meio de uma request, ou timer de
551
+ * renovação que não disparou). Emite um lease NOVO e faz o swap do pool interno
552
+ * do wrapper com
543
553
  * o certificado fresco; o wrapper então re-tenta a query 1x no pool novo.
544
554
  *
545
555
  * Vai DIRETO ao lease novo (sem `leaseId`) — a conexão falhou porque o
@@ -1139,7 +1149,14 @@ function toProduct(raw) {
1139
1149
  if (Array.isArray(r.plans)) {
1140
1150
  product.plans = r.plans.filter(
1141
1151
  (p) => typeof p === "object" && p !== null && typeof p.id === "string" && typeof p.name === "string"
1142
- );
1152
+ ).map((p) => {
1153
+ const plan = { id: p.id, name: p.name };
1154
+ if (typeof p.amountCents === "number") plan.amountCents = p.amountCents;
1155
+ if (Array.isArray(p.features) && p.features.every((f) => typeof f === "string")) {
1156
+ plan.features = p.features;
1157
+ }
1158
+ return plan;
1159
+ });
1143
1160
  }
1144
1161
  return product;
1145
1162
  }
@@ -1719,7 +1736,10 @@ function createSupportNamespace(config) {
1719
1736
  await httpRequest(config, {
1720
1737
  method: "POST",
1721
1738
  path: `/api/sdk/v1/support/tickets/${encodeURIComponent(ticketId)}/satisfaction-attempt`,
1722
- requireAuth: true
1739
+ requireAuth: true,
1740
+ // Incrementa satisfactionAttempts += 1 no Core — sem idempotencyKey,
1741
+ // um retry de rede infla o contador (mesmo padrão de createTicket acima).
1742
+ idempotencyKey: true
1723
1743
  });
1724
1744
  },
1725
1745
  /**
@@ -5824,7 +5844,12 @@ function createWebhooksNamespace(config) {
5824
5844
  events: input.events,
5825
5845
  ...input.secret ? { secret: input.secret } : {}
5826
5846
  },
5827
- requireAuth: true
5847
+ requireAuth: true,
5848
+ // Sem isso, um retry de rede (app-level; SDK default é 0 retries em
5849
+ // POST) podia registrar o MESMO webhook duas vezes → entrega
5850
+ // duplicada de todo evento futuro pro endpoint do cliente. Core
5851
+ // dedup TTL 24h (mesmo padrão de usage.report/support.createTicket).
5852
+ idempotencyKey: true
5828
5853
  });
5829
5854
  return toEndpoint(raw);
5830
5855
  },
@@ -6377,16 +6402,6 @@ async function safeJson2(res) {
6377
6402
  return void 0;
6378
6403
  }
6379
6404
  }
6380
- function statusToCode2(status) {
6381
- if (status === 401) return "unauthorized";
6382
- if (status === 403) return "forbidden";
6383
- if (status === 404) return "not_found";
6384
- if (status === 409) return "conflict";
6385
- if (status === 422 || status === 400) return "validation_failed";
6386
- if (status === 429) return "rate_limited";
6387
- if (status >= 500) return "server_error";
6388
- return "unknown";
6389
- }
6390
6405
  function joinUrl(baseUrl, path) {
6391
6406
  const base = baseUrl.replace(/\/+$/, "");
6392
6407
  const p = path.startsWith("/") ? path : `/${path}`;
@@ -6421,7 +6436,7 @@ async function aiFetch(config, body, signal, stream) {
6421
6436
  const requestId = res.headers.get("x-request-id") ?? res.headers.get("x-correlation-id") ?? void 0;
6422
6437
  if (!res.ok) {
6423
6438
  const parsed = await safeJson2(res);
6424
- let code = statusToCode2(res.status);
6439
+ let code = statusToCode(res.status);
6425
6440
  let message = `HTTP ${res.status}`;
6426
6441
  if (parsed && typeof parsed === "object" && "error" in parsed) {
6427
6442
  const errField = parsed.error;
@@ -6539,6 +6554,19 @@ function createAiNamespace(config) {
6539
6554
 
6540
6555
  // src/mocks.ts
6541
6556
  init_errors();
6557
+
6558
+ // src/runtime-env.ts
6559
+ function isProductionRuntime() {
6560
+ try {
6561
+ if (typeof process !== "undefined" && process.env) {
6562
+ return process.env.NODE_ENV === "production";
6563
+ }
6564
+ } catch {
6565
+ }
6566
+ return false;
6567
+ }
6568
+
6569
+ // src/mocks.ts
6542
6570
  var DEV_FIXTURE_USER = Object.freeze({
6543
6571
  uid: "dev-fixture-uid-0001",
6544
6572
  email: "dev@neetru.local",
@@ -6555,6 +6583,12 @@ var MockAuth = class {
6555
6583
  this._user = initialUser;
6556
6584
  this._listeners = /* @__PURE__ */ new Set();
6557
6585
  this._allowUnsignedDecode = options?.allowUnsignedDecode ?? false;
6586
+ if (this._allowUnsignedDecode && isProductionRuntime()) {
6587
+ throw new NeetruError(
6588
+ "invalid_config",
6589
+ "MockAuth com allowUnsignedDecode=true \xE9 PROIBIDO em produ\xE7\xE3o (NODE_ENV=production): decodificar JWT sem verificar assinatura \xE9 bypass de autentica\xE7\xE3o. Este modo existe exclusivamente para testes."
6590
+ );
6591
+ }
6558
6592
  if (this._allowUnsignedDecode) {
6559
6593
  const isTestEnv = typeof process !== "undefined" && (process.env?.NODE_ENV === "test" || process.env?.VITEST === "true" || process.env?.VITEST != null);
6560
6594
  if (!isTestEnv && typeof console !== "undefined") {
@@ -6976,7 +7010,7 @@ function resolveEnv(configEnv) {
6976
7010
  }
6977
7011
  try {
6978
7012
  const g = globalThis.NEETRU_ENV;
6979
- if (g === "dev" || g === "workspace" || g === "prod") return g;
7013
+ if (g === "workspace" || g === "prod") return g;
6980
7014
  } catch {
6981
7015
  }
6982
7016
  return "prod";
@@ -7564,7 +7598,7 @@ function createNeetruClient(config = {}) {
7564
7598
  productId: config.productId,
7565
7599
  tenantId: config.tenantId
7566
7600
  });
7567
- const isDev = env === "dev";
7601
+ const isDev = env === "dev" && !isProductionRuntime();
7568
7602
  const auth = config.mocks?.auth ?? (isDev ? new MockAuth({ ...DEV_FIXTURE_USER }) : createOidcAuthNamespace(resolved));
7569
7603
  const usage = config.mocks?.usage ?? (isDev ? new MockUsage() : createUsageNamespace(resolved));
7570
7604
  const support = config.mocks?.support ?? (isDev ? new MockSupport() : createSupportNamespace(resolved));