@neetru/sdk 3.1.6 → 3.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/auth.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/idempotency.ts","../src/http.ts","../src/db-errors.ts","../src/db/sql/lease.ts","../src/db/sql/sql-client.ts","../src/auth.ts","../src/api-key.ts","../src/base-url-allowlist.ts","../src/types.ts","../src/catalog.ts","../src/entitlements.ts","../src/telemetry.ts","../src/usage.ts","../src/validators.ts","../src/support.ts","../src/db/client-db.ts","../src/db/offline/query-engine.ts","../src/db/offline/local-store.ts","../src/db/offline/memory-store.ts","../src/db/offline/mutation-queue.ts","../src/db/field-value.ts","../src/db/offline/sync-engine.ts","../src/db/offline/conflict-resolver.ts","../src/db/offline/change-bus.ts","../src/db/offline/connectivity-monitor.ts","../src/db/offline/tab-coordinator.ts","../src/db/collection-ref.ts","../src/db/realtime/realtime-client.ts","../src/checkout.ts","../src/webhooks.ts","../src/notifications.ts","../src/mocks.ts"],"names":["err","message","RETRYABLE_CODES","httpRequest","openDB","resolveProductId","VALID_SEVERITIES","validateInput","createRemoteJWKSet","crypto","storage","jwtVerify"],"mappings":"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","file":"auth.cjs","sourcesContent":["/**\r\n * Erros tipados do SDK.\r\n *\r\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\r\n * por `.code` (string estável) sem parsing de message.\r\n */\r\n\r\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\r\nexport type NeetruErrorCode =\r\n | 'invalid_config'\r\n | 'missing_api_key'\r\n | 'unauthorized'\r\n | 'forbidden'\r\n | 'not_found'\r\n | 'rate_limited'\r\n | 'validation_failed'\r\n | 'network_error'\r\n | 'invalid_response'\r\n | 'server_error'\r\n | 'token_expired'\r\n | 'token_invalid_signature'\r\n | 'token_invalid_audience'\r\n | 'token_invalid_issuer'\r\n /** 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 /** 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 constructor(\r\n code: NeetruErrorCode | string,\r\n message: string,\r\n status?: number,\r\n requestId?: string,\r\n ) {\r\n super(message);\r\n this.name = 'NeetruError';\r\n this.code = code;\r\n this.status = status;\r\n this.requestId = requestId;\r\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\r\n Object.setPrototypeOf(this, NeetruError.prototype);\r\n }\r\n}\r\n","/**\n * Idempotency-Key helper — gera UUID v4 cripto-seguro para identificar\n * mutations não-idempotentes (`usage.report`, `support.createTicket`,\n * `notifications.send`, `webhooks.test`).\n *\n * Estratégia 3.0:\n * - SDK gera UUID v4 por chamada via `randomUUID()` (WebCrypto.subtle não\n * necessário aqui — `crypto.randomUUID()` está em Node 14.17+ e em todos\n * os browsers/Edge runtimes modernos).\n * - Header `Idempotency-Key: <uuid>` é injetado pelo `httpRequest` quando\n * `opts.idempotencyKey === true` OU caller passa explicit `opts.idempotencyKeyValue`.\n * - Core dedup em coleção `usage_idempotency_keys/{key}` TTL 24h (vide\n * `docs/CORE_CHANGES_REQUIRED.md` §2). Se Core ainda não dedupa, o header\n * é benign (ignorado).\n *\n * Defesa em camadas: combinado com `retries: 0` em POSTs (vide http.ts), o\n * risco de double-write em transientes vai pra zero.\n */\nimport { NeetruError } from './errors';\n\n/**\n * Gera UUID v4 criptograficamente seguro. Universal: Node 14.17+, browsers\n * modernos, Edge runtimes (Workers/Vercel Edge/Cloudflare).\n *\n * Fallback puro-JS removido em 3.0 — `crypto.randomUUID()` é ubíquo desde\n * 2022. Se runtime não tem, lança `NeetruError('runtime_unsupported')`\n * (consumer deve polyfillar).\n *\n * **L-01 fix (Opus review 2026-05-27):** antes lançava `Error` cru, que\n * não era pego por `catch (err) { if (err instanceof NeetruError) ... }`\n * dos consumers. Agora throw canonical.\n *\n * @throws NeetruError('runtime_unsupported') se `crypto.randomUUID` não disponível.\n */\nexport function generateIdempotencyKey(): string {\n // WebCrypto (browser/Edge) e Node 14.17+ expõem `crypto.randomUUID()`.\n // Node anterior precisa de `node:crypto` mas SDK 3.0 exige Node ≥20 (vide engines).\n const cryptoObj: { randomUUID?: () => string } | undefined =\n typeof globalThis !== 'undefined' && 'crypto' in globalThis\n ? (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n : undefined;\n if (cryptoObj && typeof cryptoObj.randomUUID === 'function') {\n return cryptoObj.randomUUID();\n }\n throw new NeetruError(\n 'runtime_unsupported',\n 'crypto.randomUUID not available in this runtime. SDK 3.0 requires Node ≥20 or modern browser/Edge.',\n );\n}\n\n/** Regex UUID v4 — validação para uso interno. */\nexport const UUID_V4_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\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 const body = (await safeJson(res)) as\r\n | { error?: { code?: string; message?: string } | string }\r\n | undefined;\r\n let code: string = statusToCode(res.status);\r\n let message = `HTTP ${res.status}`;\r\n if (body && typeof body === 'object' && 'error' in body) {\r\n const errField = body.error;\r\n if (typeof errField === 'string') {\r\n message = errField;\r\n } else if (errField && typeof errField === 'object') {\r\n if (typeof errField.code === 'string') code = errField.code;\r\n if (typeof errField.message === 'string') message = errField.message;\r\n }\r\n }\r\n const err = new NeetruError(code, message, res.status, requestId);\r\n lastError = err;\r\n\r\n const isRetryable = RETRYABLE_CODES.has(code as NeetruErrorCode);\r\n if (isRetryable && attempt < maxRetries) {\r\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\r\n const delay = retryAfter ?? backoffMs(attempt);\r\n await sleep(delay);\r\n continue;\r\n }\r\n throw err;\r\n }\r\n\r\n // Unreachable — loop sempre retorna ou lança. Safety net.\r\n throw lastError ?? new NeetruError('unknown', 'unexpected httpRequest exit');\r\n}\r\n","/**\r\n * NeetruDbError — classe de erro especializada para o módulo `db`.\r\n *\r\n * Conforma com 02-sdk.md §3.5: `NeetruDbError extends NeetruError`,\r\n * campo `code` fechado em `NeetruDbErrorCode`, campo `retryable` booleano,\r\n * campo `dbId` opaco para correlação.\r\n *\r\n * Herda de `NeetruError` para que um `catch (e) { if (e instanceof NeetruError) }`\r\n * genérico continue pegando erros de DB. Quem quer granularidade usa\r\n * `instanceof NeetruDbError` e o `code` fechado.\r\n */\r\n\r\nimport { NeetruError } from './errors';\r\n\r\n/**\r\n * Códigos de erro específicos do módulo `db`.\r\n *\r\n * - `db_unavailable` — lifecycle: provisionando / falhou / arquivado.\r\n * NÃO significa \"sem rede\" — offline é transparente.\r\n * - `db_not_found` — documento/coleção não encontrado no servidor.\r\n * - `db_conflict` — conflito de escrita detectado.\r\n * - `db_quota_exceeded` — quota de escrita/leitura excedida no banco.\r\n * - `db_permission_denied` — sem permissão para a operação.\r\n * - `db_invalid_query` — query inválida (campo, operador, tipo).\r\n * - `db_timeout` — operação excedeu o timeout.\r\n * - `offline_quota_exceeded`— IndexedDB cheio; a escrita não pode ser enfileirada.\r\n * - `offline_unavailable` — IndexedDB indisponível; SDK degrado para cache RAM.\r\n */\r\nexport type NeetruDbErrorCode =\r\n | 'db_unavailable'\r\n | 'db_not_found'\r\n | 'db_conflict'\r\n | 'db_quota_exceeded'\r\n | 'db_permission_denied'\r\n | 'db_invalid_query'\r\n | 'db_timeout'\r\n | 'offline_quota_exceeded'\r\n | 'offline_unavailable';\r\n\r\n/**\r\n * Códigos que são retryable por natureza.\r\n */\r\nconst RETRYABLE_CODES = new Set<NeetruDbErrorCode>([\r\n 'db_unavailable',\r\n 'db_conflict',\r\n 'db_timeout',\r\n]);\r\n\r\n/**\r\n * Erro tipado do módulo `db` — estende `NeetruError` para compatibilidade.\r\n *\r\n * @example\r\n * ```ts\r\n * try {\r\n * await client.db.collection('orders').add({ ... });\r\n * } catch (e) {\r\n * if (e instanceof NeetruDbError && e.code === 'offline_quota_exceeded') {\r\n * // IndexedDB cheio — notificar usuário\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport class NeetruDbError extends NeetruError {\r\n /** Código de erro fechado — específico de DB. */\r\n public override readonly code: NeetruDbErrorCode;\r\n\r\n /**\r\n * `true` para erros transientes que o produto pode tentar novamente.\r\n * São retryable: `db_unavailable`, `db_conflict`, `db_timeout`.\r\n */\r\n public readonly retryable: boolean;\r\n\r\n /**\r\n * ID opaco do banco lógico — só para correlação com logs do Core.\r\n * Nunca deve ser exibido ao usuário final.\r\n */\r\n public readonly dbId?: string;\r\n\r\n constructor(code: NeetruDbErrorCode, message: string, dbId?: string) {\r\n super(code, message);\r\n this.name = 'NeetruDbError';\r\n this.code = code;\r\n this.retryable = RETRYABLE_CODES.has(code);\r\n this.dbId = dbId;\r\n // Preserva o prototype chain (TypeScript + downlevel).\r\n Object.setPrototypeOf(this, NeetruDbError.prototype);\r\n }\r\n}\r\n","/**\r\n * SqlLeaseManager — gestão de lease de credencial SQL (M2).\r\n *\r\n * Peça canônica 8 da 00-RELATORIO-CENTRAL.md §6.1:\r\n * - Busca o `DbSqlLease` no startup via `fetchLease()`.\r\n * - Agenda renovação proativa aos ~80% do TTL.\r\n * - Faz hot-swap da credencial: quando o lease renova (ou `credentialVersion`\r\n * muda), o pool antigo drena enquanto o novo aceita conexões.\r\n * - NUNCA loga a senha; NUNCA persiste o lease.\r\n *\r\n * Implementação do hot-swap: pg.Pool não tem API de primeira classe para trocar\r\n * credencial. A estratégia aqui é \"novo pool aceita, velho pool drena\":\r\n * 1. Cria pool novo com o lease renovado.\r\n * 2. Atualiza o ponteiro `_pool` e `_orm` (novos queries vão pro pool novo).\r\n * 3. Chama `end()` no pool antigo (drena gracioso — espera queries em curso).\r\n *\r\n * A janela de dois pools coexistindo é curta (~queries em voo), aceitável e\r\n * esperada (documentada em 02-sdk.md §5 risco 7).\r\n */\r\n\r\nimport { NeetruDbError } from '../../db-errors';\r\nimport type {\r\n DbSqlLease,\r\n SqlClientDeps,\r\n PgPoolLike,\r\n NeetruSqlClient,\r\n} from './types';\r\nimport type { NodePgDatabase } from 'drizzle-orm/node-postgres';\r\n\r\n// ─── Constantes ──────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Proporção do TTL após a qual o lease é renovado proativamente.\r\n *\r\n * 0.80 = renova aos 80% — para um lease de 15 min isso é ~12 min.\r\n * Garante margem antes da expiração real mesmo com latência de rede.\r\n */\r\nconst RENEWAL_THRESHOLD = 0.8;\r\n\r\n/** Tempo mínimo de espera antes de tentar renovar (evita tight-loop). */\r\nconst MIN_RENEWAL_DELAY_MS = 30_000; // 30 s\r\n\r\n// ─── SqlLeaseManager ─────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Implementação interna de `NeetruSqlClient`.\r\n *\r\n * O produto nunca constrói `SqlLeaseManager` diretamente — usa `createSqlClient`\r\n * (a factory pública que faz o primeiro lease + abre o pool).\r\n */\r\nexport class SqlLeaseManager<TSchema extends Record<string, unknown>>\r\n implements NeetruSqlClient<TSchema>\r\n{\r\n private _lease: DbSqlLease;\r\n private _pool: PgPoolLike;\r\n private _orm: NodePgDatabase<TSchema>;\r\n private _renewalTimer: ReturnType<typeof setTimeout> | null = null;\r\n private _closed = false;\r\n\r\n private readonly _deps: Required<Omit<SqlClientDeps<TSchema>, 'database'>> & { database?: string };\r\n\r\n constructor(\r\n lease: DbSqlLease,\r\n pool: PgPoolLike,\r\n orm: NodePgDatabase<TSchema>,\r\n deps: SqlClientDeps<TSchema>,\r\n ) {\r\n this._lease = lease;\r\n this._pool = pool;\r\n this._orm = orm;\r\n // Aplica default de `now` se não fornecido.\r\n this._deps = {\r\n ...deps,\r\n now: deps.now ?? (() => Date.now()),\r\n };\r\n this._scheduleRenewal();\r\n }\r\n\r\n // ─── Superfície pública (NeetruSqlClient) ──────────────────────────────────\r\n\r\n get orm(): NodePgDatabase<TSchema> {\r\n this._assertOpen();\r\n return this._orm;\r\n }\r\n\r\n async transaction<T>(\r\n fn: (tx: NodePgDatabase<TSchema>) => Promise<T>,\r\n opts?: {\r\n isolationLevel?: 'read committed' | 'repeatable read' | 'serializable';\r\n },\r\n ): Promise<T> {\r\n this._assertOpen();\r\n try {\r\n if (opts?.isolationLevel) {\r\n return await this._orm.transaction(fn, {\r\n isolationLevel: opts.isolationLevel,\r\n });\r\n }\r\n return await this._orm.transaction(fn);\r\n } catch (err) {\r\n throw mapPoolError(err);\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n if (this._closed) return;\r\n this._closed = true;\r\n this._cancelRenewal();\r\n await this._pool.end().catch(() => {\r\n // Melhor esforço — não relança no shutdown.\r\n });\r\n }\r\n\r\n // ─── Renovação proativa ────────────────────────────────────────────────────\r\n\r\n /**\r\n * Calcula o delay de renovação: momento de ~80% do TTL restante.\r\n *\r\n * Fórmula: `renewAt = issuedAt + TTL * RENEWAL_THRESHOLD`\r\n * = `expiresAt - TTL * (1 - RENEWAL_THRESHOLD)`\r\n *\r\n * Se o lease já está além do ponto de renovação (ou TTL não calculável),\r\n * usa `MIN_RENEWAL_DELAY_MS` como fallback seguro.\r\n */\r\n _calcRenewalDelayMs(): number {\r\n const expiresAtMs = Date.parse(this._lease.expiresAt);\r\n if (!Number.isFinite(expiresAtMs)) return MIN_RENEWAL_DELAY_MS;\r\n\r\n const now = this._deps.now();\r\n const remainingMs = expiresAtMs - now;\r\n if (remainingMs <= 0) return MIN_RENEWAL_DELAY_MS;\r\n\r\n // Renova quando restar (1 - RENEWAL_THRESHOLD) do TTL.\r\n // Ex: 15 min de TTL total → renova quando restar 3 min.\r\n const renewInMs = remainingMs * (1 - RENEWAL_THRESHOLD);\r\n return Math.max(MIN_RENEWAL_DELAY_MS, Math.round(renewInMs));\r\n }\r\n\r\n _scheduleRenewal(): void {\r\n if (this._closed) return;\r\n const delayMs = this._calcRenewalDelayMs();\r\n this._renewalTimer = setTimeout(() => {\r\n void this._doRenew();\r\n }, delayMs);\r\n }\r\n\r\n _cancelRenewal(): void {\r\n if (this._renewalTimer !== null) {\r\n clearTimeout(this._renewalTimer);\r\n this._renewalTimer = null;\r\n }\r\n }\r\n\r\n async _doRenew(): Promise<void> {\r\n if (this._closed) return;\r\n try {\r\n const renewOpts: import('./types').LeaseFetchOptions = {\r\n leaseId: this._lease.leaseId,\r\n };\r\n // Propaga o database original (contrato C-H) na renovação.\r\n if (this._deps.database !== undefined) {\r\n renewOpts.database = this._deps.database;\r\n }\r\n const newLease = await this._deps.fetchLease(renewOpts);\r\n await this._swapPool(newLease);\r\n } catch (err) {\r\n // Renovação falhou — reagenda com delay mínimo e tenta de novo.\r\n // O pool atual ainda funciona enquanto o lease não expirou.\r\n // Ignora silenciosamente (melhor esforço) e reagenda.\r\n this._renewalTimer = setTimeout(() => {\r\n void this._doRenew();\r\n }, MIN_RENEWAL_DELAY_MS);\r\n // Registra no console apenas em dev para diagnóstico; produção é silenciosa.\r\n if (process.env['NODE_ENV'] !== 'production') {\r\n // eslint-disable-next-line no-console\r\n console.warn('[SqlLeaseManager] Lease renewal failed, will retry:', err);\r\n }\r\n return;\r\n }\r\n this._scheduleRenewal();\r\n }\r\n\r\n /**\r\n * Hot-swap do pool: cria pool novo, atualiza ponteiros, drena pool antigo.\r\n *\r\n * Exposto como método protegido para testes.\r\n */\r\n async _swapPool(newLease: DbSqlLease): Promise<void> {\r\n const credRotated =\r\n newLease.credentialVersion !== this._lease.credentialVersion;\r\n\r\n // Se a versão não mudou e o lease é o mesmo, nada a fazer além de\r\n // atualizar `expiresAt`.\r\n if (!credRotated && newLease.leaseId === this._lease.leaseId) {\r\n this._lease = newLease;\r\n return;\r\n }\r\n\r\n // Cria novo pool + handle Drizzle antes de desconectar o antigo.\r\n const newPool = this._deps.createPool(newLease);\r\n const newOrm = this._deps.createDrizzle(newPool, this._deps.schema);\r\n\r\n const oldPool = this._pool;\r\n\r\n // Atualiza ponteiros — queries novas vão pro pool novo.\r\n this._lease = newLease;\r\n this._pool = newPool;\r\n this._orm = newOrm;\r\n\r\n // Drena o pool antigo graciosamente (não bloqueia o caller).\r\n void oldPool.end().catch(() => {\r\n /* best-effort */\r\n });\r\n }\r\n\r\n // ─── Helpers ───────────────────────────────────────────────────────────────\r\n\r\n private _assertOpen(): void {\r\n if (this._closed) {\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n 'SqlLeaseManager foi fechado — chame close() apenas no shutdown.',\r\n );\r\n }\r\n }\r\n}\r\n\r\n// ─── Mapeamento de erros de pool ─────────────────────────────────────────────\r\n\r\n/**\r\n * Mapeia erros de `pg` / PgBouncer / timeout para `NeetruDbError` canônico.\r\n *\r\n * Erros desconhecidos são relançados como `db_unavailable` (retryable).\r\n */\r\nexport function mapPoolError(err: unknown): NeetruDbError {\r\n if (err instanceof NeetruDbError) return err;\r\n\r\n const message = err instanceof Error ? err.message : String(err);\r\n const code = err instanceof Error ? (err as NodeJS.ErrnoException).code : undefined;\r\n\r\n // ECONNREFUSED / ENOTFOUND / ETIMEDOUT — pool não conseguiu conectar.\r\n if (\r\n typeof code === 'string' &&\r\n (code === 'ECONNREFUSED' || code === 'ENOTFOUND' || code === 'ETIMEDOUT')\r\n ) {\r\n return new NeetruDbError(\r\n 'db_unavailable',\r\n `Pool connection failed (${code}): ${message}`,\r\n );\r\n }\r\n\r\n // Timeout de query Postgres (statement_timeout / lock_timeout).\r\n if (message.includes('statement timeout') || message.includes('lock timeout')) {\r\n return new NeetruDbError('db_timeout', `Query timeout: ${message}`);\r\n }\r\n\r\n // Serialization failure / deadlock (código Postgres 40001 / 40P01).\r\n if (message.includes('40001') || message.includes('40P01') || message.includes('deadlock')) {\r\n return new NeetruDbError('db_conflict', `Transaction conflict: ${message}`);\r\n }\r\n\r\n // Permission denied (Postgres 42501).\r\n if (message.includes('42501') || message.toLowerCase().includes('permission denied')) {\r\n return new NeetruDbError('db_permission_denied', `Permission denied: ${message}`);\r\n }\r\n\r\n // Fallback — genérico db_unavailable (retryable).\r\n return new NeetruDbError('db_unavailable', `Database error: ${message}`);\r\n}\r\n","/**\r\n * `createSqlClient` — factory pública do Mundo SQL.\r\n *\r\n * É a implementação de `client.db.sql(schema)` (02-sdk.md §3.3):\r\n * 1. Busca o lease inicial no Core (`POST /api/sdk/v1/db/lease`).\r\n * 2. Abre um `pg.Pool` com as credenciais do lease.\r\n * 3. Cria o handle Drizzle (`drizzle-orm/node-postgres`).\r\n * 4. Instancia o `SqlLeaseManager` que renova o lease proativamente.\r\n *\r\n * Em produção, usar `createSqlClientFromConfig` (que injeta `pg.Pool` real e\r\n * Drizzle real). Para testes, injetar deps fake via `createSqlClientWithDeps`.\r\n */\r\n\r\nimport type { ResolvedConfig } from '../../types';\r\nimport { NeetruDbError } from '../../db-errors';\r\nimport { SqlLeaseManager } from './lease';\r\nimport type {\r\n DbSqlLease,\r\n NeetruSqlClient,\r\n PgPoolLike,\r\n SqlClientDeps,\r\n LeaseFetcher,\r\n SqlOptions,\r\n} from './types';\r\n\r\n// ─── Endpoint do Core ─────────────────────────────────────────────────────────\r\n\r\n/** Endpoint de emissão de lease SQL no Core. */\r\nexport const LEASE_ENDPOINT = '/api/sdk/v1/db/lease';\r\n\r\n/** Endpoint de renovação de lease SQL no Core. */\r\nexport const LEASE_RENEW_ENDPOINT = '/api/sdk/v1/db/lease/renew';\r\n\r\n// ─── Lease fetcher HTTP ───────────────────────────────────────────────────────\r\n\r\n// ─── Mapeamento de env SDK → env Core ────────────────────────────────────────\r\n\r\n/**\r\n * Mapeia o env do SDK (`'dev'|'workspace'|'prod'`) para o enum aceito pelo\r\n * Core (`'dev'|'staging'|'production'`).\r\n *\r\n * O Core usa `z.enum(['dev', 'staging', 'production'])` no LeaseRequestSchema;\r\n * o SDK expõe `'dev'|'workspace'|'prod'` (NeetruEnv). Sem este mapeamento o\r\n * Core retornaria 400 validation_failed para `workspace` e `prod`.\r\n */\r\nfunction mapEnvToCore(sdkEnv: string): 'dev' | 'staging' | 'production' {\r\n if (sdkEnv === 'workspace') return 'staging';\r\n if (sdkEnv === 'prod') return 'production';\r\n return 'dev'; // 'dev' passa direto\r\n}\r\n\r\n/**\r\n * Cria um `LeaseFetcher` que chama o Core via `httpRequest`.\r\n *\r\n * BL-7 fix:\r\n * - Novo lease: envia `{ productId, environment }` (obrigatório pelo Core).\r\n * - Mapeia SDK env (`prod`→`production`, `workspace`→`staging`, `dev`→`dev`).\r\n * - Parseia a resposta desembrulhando `response.lease` (Core retorna\r\n * `{ kind, lease: {...} }`, não campos no topo).\r\n * - Renovação: envia `{ leaseId }` e desembrulha `response.lease`.\r\n *\r\n * Importação dinâmica de `./http` mantém o `pg` fora do bundle de quem não\r\n * usa SQL (tree-shaking é garantido pois `pg` só entra via `createPool`).\r\n */\r\nexport function createHttpLeaseFetcher(config: ResolvedConfig): LeaseFetcher {\r\n return async (opts) => {\r\n // Import dinâmico não disponível em CJS isolatedModules — importamos\r\n // estaticamente mas só quando a factory é chamada (lazy init).\r\n const { httpRequest } = await import('../../http');\r\n\r\n const isRenewal = Boolean(opts?.leaseId);\r\n const path = isRenewal ? LEASE_RENEW_ENDPOINT : LEASE_ENDPOINT;\r\n\r\n // BL-7: monta o body conforme o contrato de CADA rota do Core.\r\n //\r\n // Rota de novo lease (POST /lease): { productId, environment }\r\n // Rota de renovação (POST /lease/renew): { leaseId }\r\n //\r\n // Para novo lease inclui `database` quando fornecido (contrato C-H) como\r\n // campo extra — o Core o aceita via passthrough no `issueLease`.\r\n let body: Record<string, unknown>;\r\n if (isRenewal) {\r\n // Renovação: apenas leaseId\r\n body = { leaseId: opts!.leaseId };\r\n } else {\r\n // Novo lease: obrigatório productId + environment (mapeado)\r\n body = {\r\n productId: config.productId ?? '',\r\n environment: mapEnvToCore(config.env ?? 'prod'),\r\n };\r\n if (opts?.database !== undefined) {\r\n body['database'] = opts.database;\r\n }\r\n }\r\n\r\n let raw: unknown;\r\n try {\r\n raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path,\r\n body,\r\n requireAuth: true,\r\n // Lease fetch é idempotente do ponto de vista de segurança — retries OK.\r\n retries: 2,\r\n });\r\n } catch (err) {\r\n // Mapeia NeetruError → NeetruDbError(db_unavailable).\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n `Falha ao ${isRenewal ? 'renovar' : 'obter'} lease SQL: ${msg}`,\r\n );\r\n }\r\n\r\n return parseLease(raw);\r\n };\r\n}\r\n\r\n/**\r\n * Parseia e valida a resposta do Core como `DbSqlLease`.\r\n *\r\n * BL-7 fix: o Core retorna `{ kind, lease: { leaseId, host, ... } }` — não\r\n * campos no topo. `parseLease` agora desembrulha `response.lease` antes de\r\n * validar os campos obrigatórios.\r\n *\r\n * Lança `NeetruDbError(db_unavailable)` se o shape estiver errado.\r\n */\r\nfunction parseLease(raw: unknown): DbSqlLease {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruDbError('db_unavailable', 'Resposta de lease inválida (não é objeto).');\r\n }\r\n\r\n // BL-7: desembrulha o envelope { kind, lease: {...} }\r\n const envelope = raw as Record<string, unknown>;\r\n const leaseObj = envelope['lease'];\r\n\r\n if (!leaseObj || typeof leaseObj !== 'object') {\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n 'Resposta de lease inválida: campo \"lease\" ausente ou não é objeto. ' +\r\n 'O Core retorna { kind, lease: { leaseId, host, ... } }.',\r\n );\r\n }\r\n\r\n const r = leaseObj as Record<string, unknown>;\r\n\r\n function req<T>(field: string, type: string): T {\r\n if (typeof r[field] !== type) {\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n `Campo obrigatório \"${field}\" ausente ou tipo inválido na resposta de lease.`,\r\n );\r\n }\r\n return r[field] as T;\r\n }\r\n\r\n return {\r\n leaseId: req<string>('leaseId', 'string'),\r\n host: req<string>('host', 'string'),\r\n port: (typeof r['port'] === 'number' ? r['port'] : 5433) as 5433,\r\n dbName: req<string>('dbName', 'string'),\r\n user: req<string>('user', 'string'),\r\n password: req<string>('password', 'string'),\r\n sslca: typeof r['sslca'] === 'string' ? r['sslca'] : null,\r\n clientCert: typeof r['clientCert'] === 'string' ? r['clientCert'] : null,\r\n clientKey: typeof r['clientKey'] === 'string' ? r['clientKey'] : null,\r\n credentialVersion:\r\n typeof r['credentialVersion'] === 'number' ? r['credentialVersion'] : 1,\r\n expiresAt: req<string>('expiresAt', 'string'),\r\n };\r\n}\r\n\r\n// ─── Pool real (produção) ─────────────────────────────────────────────────────\r\n\r\n/**\r\n * Cria um `pg.Pool` real a partir do lease.\r\n *\r\n * - Aponta sempre para a porta 5433 (PgBouncer).\r\n * - `max: 3` — conservador para serverless (Cloud Run).\r\n * - SSL opcional: usa `sslca` quando presente.\r\n */\r\nexport async function createPgPool(lease: DbSqlLease): Promise<PgPoolLike> {\r\n // bug_168368ae (CRITICAL 26/05): webpackIgnore obrigatório aqui também.\r\n // Sem ele, webpack do consumer ainda processa o module ID 'pg' e segue o\r\n // module graph → 'tls/fs not found' no client bundle. `pg` é server-only.\r\n const { Pool } = await import(/* webpackIgnore: true */ 'pg');\r\n\r\n // C-07 (Codex BLOCKER 2026-05-22): Core retorna PEM strings via\r\n // `.toString('pem')` do @peculiar/x509 (formato `-----BEGIN ...-----`).\r\n // Buffer.from(pem, 'base64') silenciosamente SKIPA chars inválidos do\r\n // header/footer e corrompe os bytes. `pg` Pool aceita PEM string direto —\r\n // passa cru.\r\n const ssl: Record<string, unknown> | false =\r\n lease.sslca\r\n ? {\r\n ca: lease.sslca,\r\n cert: lease.clientCert ?? undefined,\r\n key: lease.clientKey ?? undefined,\r\n rejectUnauthorized: true,\r\n }\r\n : false;\r\n\r\n return new Pool({\r\n host: lease.host,\r\n port: lease.port,\r\n database: lease.dbName,\r\n user: lease.user,\r\n password: lease.password,\r\n ssl,\r\n max: 3,\r\n idleTimeoutMillis: 30_000,\r\n connectionTimeoutMillis: 10_000,\r\n });\r\n}\r\n\r\n/**\r\n * Cria o handle Drizzle real.\r\n *\r\n * Import dinâmico de `drizzle-orm/node-postgres` para tree-shaking.\r\n */\r\nexport async function createDrizzleHandle<TSchema extends Record<string, unknown>>(\r\n pool: PgPoolLike,\r\n schema: TSchema,\r\n) {\r\n // bug_168368ae: webpackIgnore obrigatório (idem createPgPool).\r\n const { drizzle } = await import(/* webpackIgnore: true */ 'drizzle-orm/node-postgres');\r\n // `PgPoolLike` é mais estreito que `Pool` do pg — cast necessário.\r\n // Em produção o valor sempre é um `pg.Pool` real.\r\n return drizzle(pool as unknown as import('pg').Pool, { schema });\r\n}\r\n\r\n// ─── Factory principal ────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Cria `NeetruSqlClient` com dependências injetadas explicitamente.\r\n *\r\n * Usado pelos testes e pela factory de produção.\r\n *\r\n * @param deps — dependências injetáveis (fetchLease, createPool, createDrizzle, schema).\r\n * @param options — opções de `client.db.sql(schema, options?)` (contrato C-H).\r\n * `options.database` desambigua quando o produto tem N>1 bancos SQL.\r\n */\r\nexport async function createSqlClientWithDeps<\r\n TSchema extends Record<string, unknown>,\r\n>(\r\n deps: SqlClientDeps<TSchema>,\r\n options?: SqlOptions,\r\n): Promise<NeetruSqlClient<TSchema>> {\r\n // Mescla `database` das options com deps para que o SqlLeaseManager\r\n // propague o valor em todas as renovações de lease (contrato C-H).\r\n const depsWithDb: SqlClientDeps<TSchema> =\r\n options?.database !== undefined\r\n ? { ...deps, database: options.database }\r\n : deps;\r\n\r\n // 1. Busca o lease inicial, incluindo `database` quando fornecido.\r\n // Quando não há `database`, chama fetchLease() sem argumento — compatibilidade\r\n // exata com o comportamento v1.x (o teste verifica chamada sem parâmetros).\r\n let lease: DbSqlLease;\r\n try {\r\n if (options?.database !== undefined) {\r\n lease = await depsWithDb.fetchLease({ database: options.database });\r\n } else {\r\n lease = await depsWithDb.fetchLease();\r\n }\r\n } catch (err) {\r\n if (err instanceof NeetruDbError) throw err;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new NeetruDbError('db_unavailable', `Falha ao obter lease inicial: ${msg}`);\r\n }\r\n\r\n // 2. Abre o pool.\r\n let pool: PgPoolLike;\r\n try {\r\n pool = depsWithDb.createPool(lease);\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new NeetruDbError('db_unavailable', `Falha ao abrir pool: ${msg}`);\r\n }\r\n\r\n // 3. Cria handle Drizzle.\r\n let orm;\r\n try {\r\n orm = depsWithDb.createDrizzle(pool, depsWithDb.schema);\r\n } catch (err) {\r\n // Pool aberto mas Drizzle falhou — fechar o pool antes de relançar.\r\n await pool.end().catch(() => {});\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new NeetruDbError('db_unavailable', `Falha ao criar handle Drizzle: ${msg}`);\r\n }\r\n\r\n // 4. Instancia o manager (que agenda o timer de renovação).\r\n // Passa `depsWithDb` para que `database` seja propagado nas renovações.\r\n return new SqlLeaseManager(lease, pool, orm, depsWithDb);\r\n}\r\n\r\n/**\r\n * Factory de produção — usa `pg.Pool` real e Drizzle real.\r\n *\r\n * `schema` deve ser o objeto Drizzle do produto (exportado de `db/schema.ts`).\r\n * `options.database` desambigua quando o produto tem N>1 bancos SQL (C-H).\r\n *\r\n * @example\r\n * ```ts\r\n * import { createNeetruClient } from '@neetru/sdk';\r\n * import * as schema from './db/schema';\r\n * const client = createNeetruClient();\r\n * // banco padrão:\r\n * export const db = await client.db.sql(schema);\r\n * // banco específico:\r\n * export const analytics = await client.db.sql(schema, { database: 'analytics' });\r\n * ```\r\n */\r\nexport async function createSqlClientFromConfig<\r\n TSchema extends Record<string, unknown>,\r\n>(\r\n config: ResolvedConfig,\r\n schema: TSchema,\r\n options?: SqlOptions,\r\n): Promise<NeetruSqlClient<TSchema>> {\r\n const fetchLease = createHttpLeaseFetcher(config);\r\n\r\n // bug_0f836014 (CRITICAL 26/05): require('pg') + require('drizzle-orm/node-postgres')\r\n // literais eram inlined pelo tsup no entry index.mjs. Webpack do consumer\r\n // Next.js seguia o module graph e tentava bundle pg → puxa fs → 'Module not\r\n // found: fs' no client bundle. Fix: dynamic import com /* webpackIgnore: true */\r\n // que instrui webpack a NÃO processar (deixa pro runtime Node resolver). sql()\r\n // é server-only por contrato — browser nunca chega aqui em runtime.\r\n let pgMod: typeof import('pg');\r\n let drizzlePgMod: typeof import('drizzle-orm/node-postgres');\r\n try {\r\n pgMod = (await import(/* webpackIgnore: true */ 'pg')) as typeof import('pg');\r\n drizzlePgMod = (await import(/* webpackIgnore: true */ 'drizzle-orm/node-postgres')) as typeof import('drizzle-orm/node-postgres');\r\n } catch (err) {\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n `[client.db.sql] requer pg + drizzle-orm como peerDependencies do servidor. ` +\r\n `Instale: npm install pg drizzle-orm. (${(err as Error).message})`,\r\n );\r\n }\r\n\r\n // Wrappers síncronos — Pool/drizzle já carregados acima via dynamic import.\r\n const createPool = (lease: DbSqlLease): PgPoolLike => {\r\n const Pool =\r\n (pgMod as { Pool?: typeof import('pg').Pool }).Pool ??\r\n ((pgMod as { default?: { Pool?: typeof import('pg').Pool } }).default?.Pool as typeof import('pg').Pool);\r\n\r\n // C-07 (Codex BLOCKER 2026-05-22) — PEM direto.\r\n const ssl: Record<string, unknown> | false =\r\n lease.sslca\r\n ? {\r\n ca: lease.sslca,\r\n cert: lease.clientCert ?? undefined,\r\n key: lease.clientKey ?? undefined,\r\n rejectUnauthorized: true,\r\n }\r\n : false;\r\n\r\n return new Pool({\r\n host: lease.host,\r\n port: lease.port,\r\n database: lease.dbName,\r\n user: lease.user,\r\n password: lease.password,\r\n ssl,\r\n max: 3,\r\n idleTimeoutMillis: 30_000,\r\n connectionTimeoutMillis: 10_000,\r\n });\r\n };\r\n\r\n const createDrizzle = <S extends Record<string, unknown>>(\r\n pool: PgPoolLike,\r\n s: S,\r\n ) => {\r\n // bug_0f836014: usa drizzlePgMod pré-carregado via dynamicImport acima.\r\n return drizzlePgMod.drizzle(pool as unknown as import('pg').Pool, { schema: s });\r\n };\r\n\r\n return createSqlClientWithDeps(\r\n {\r\n fetchLease,\r\n createPool,\r\n createDrizzle: createDrizzle as SqlClientDeps<TSchema>['createDrizzle'],\r\n schema,\r\n },\r\n options,\r\n );\r\n}\r\n","/**\r\n * Factory `createNeetruClient` + namespace `auth` (v0.2).\r\n *\r\n * Responsabilidades:\r\n * - Factory: resolver `apiKey`, `baseUrl`, `fetch`, `env`, e montar handle\r\n * imutável com namespaces (`auth`, `catalog`, `entitlements`, `telemetry`,\r\n * `usage`, `support`).\r\n * - Auth namespace: signIn (OIDC redirect ou mock dev), signOut, getUser,\r\n * onAuthStateChanged.\r\n *\r\n * v0.1 expunha apenas Bearer estático (long-lived `nrt_*_*`). v0.2 adiciona\r\n * camada de auth para SaaS produtos consumirem identity Neetru via OIDC\r\n * (auth.neetru.com já live).\r\n */\r\nimport { jwtVerify, createRemoteJWKSet, type JWTPayload } from 'jose';\r\nimport { NeetruError } from './errors';\r\nimport { parseApiKey, tryParseApiKey } from './api-key';\r\nimport { validateBaseUrl } from './base-url-allowlist';\r\nimport {\r\n DEFAULT_BASE_URL,\r\n type AuthNamespace,\r\n type AuthStateListener,\r\n type NeetruClient,\r\n type NeetruClientConfig,\r\n type NeetruEnv,\r\n type NeetruUser,\r\n type RedirectCallbackResult,\r\n type ResolvedConfig,\r\n type SignInOptions,\r\n type VerifyTokenOptions,\r\n} from './types';\r\nimport { createCatalogNamespace } from './catalog';\r\nimport { createEntitlementsNamespace } from './entitlements';\r\nimport { createTelemetryNamespace } from './telemetry';\r\nimport { createUsageNamespace } from './usage';\r\nimport { createSupportNamespace } from './support';\r\nimport { createNeetruDb } from './db/client-db';\r\nimport { createCheckoutNamespace } from './checkout';\r\nimport { createWebhooksNamespace, MockWebhooks } from './webhooks';\r\nimport { createNotificationsNamespace, MockNotifications } from './notifications';\r\nimport { DEV_FIXTURE_USER, MockAuth, MockUsage, MockSupport, MockEntitlements } from './mocks';\r\n\r\n/**\r\n * Lê `NEETRU_API_KEY` do ambiente Node de forma defensiva. Em browser,\r\n * `process` não existe — try/catch evita ReferenceError. Em Edge runtimes\r\n * que polyfillam `process` parcialmente, optional chaining absorve undefined.\r\n */\r\nfunction readEnvApiKey(): string | undefined {\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const proc = (globalThis as any).process;\r\n const val = proc?.env?.NEETRU_API_KEY;\r\n return typeof val === 'string' && val.length > 0 ? val : undefined;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Resolve `NEETRU_ENV` de várias fontes:\r\n * 1. Config arg `env`.\r\n * 2. `process.env.NEETRU_ENV` em Node.\r\n * 3. `globalThis.NEETRU_ENV` em browser/Edge (se setado por bundler).\r\n * 4. Default `prod`.\r\n */\r\nfunction resolveEnv(configEnv?: NeetruEnv): NeetruEnv {\r\n if (configEnv) return configEnv;\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const proc = (globalThis as any).process;\r\n const val = proc?.env?.NEETRU_ENV;\r\n if (val === 'dev' || val === 'workspace' || val === 'prod') return val;\r\n } catch {\r\n /* ignore */\r\n }\r\n // SECURITY TODO (audit 2026-06-18): globalThis.NEETRU_ENV pode ser influenciado por\r\n // código de terceiros em bundles browser (ex: script injection, prototype pollution).\r\n // Se NEETRU_ENV='dev' for aceito via globalThis em prod, o client ativa MockAuth\r\n // (incluindo MockAuth.verifyToken com allowUnsignedDecode=true) silenciosamente.\r\n // Mitigação segura: honrar globalThis apenas quando process.env não está disponível\r\n // (puro browser), e nunca aceitar 'dev' via globalThis em builds de produção.\r\n // Esta mudança requer alinhamento com bundlers (define plugin) e testes E2E —\r\n // deixada como TODO para não introduzir regressão sem suite de integração full.\r\n // Mitigação atual: MockAuth.verifyToken sem allowUnsignedDecode=true lança\r\n // 'unauthorized', portanto mesmo que env='dev' seja ativado via globalThis,\r\n // verifyToken não aceita tokens não-assinados sem opt-in explícito (Finding 2 fix).\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const g = (globalThis as any).NEETRU_ENV;\r\n if (g === 'dev' || g === 'workspace' || g === 'prod') return g;\r\n } catch {\r\n /* ignore */\r\n }\r\n return 'prod';\r\n}\r\n\r\n// ─── JWKS cache ────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Cache de JWKS por URL. Cada entrada é uma `RemoteJWKSet` retornada por\r\n * `createRemoteJWKSet` (jose) — já faz internal caching e refresh automático\r\n * de chaves. O mapa aqui evita criar múltiplas instâncias pra mesma URL em\r\n * processos com vários clientes.\r\n */\r\nconst _jwksCache = new Map<string, { jwks: ReturnType<typeof createRemoteJWKSet>; createdAt: number }>();\r\n\r\nconst DEFAULT_JWKS_TTL_MS = 60 * 60 * 1000; // 1h\r\n\r\nfunction _getJwks(jwksUrl: string, cacheTtlMs: number): ReturnType<typeof createRemoteJWKSet> {\r\n const now = Date.now();\r\n const cached = _jwksCache.get(jwksUrl);\r\n if (cached && now - cached.createdAt < cacheTtlMs) {\r\n return cached.jwks;\r\n }\r\n const jwks = createRemoteJWKSet(new URL(jwksUrl));\r\n _jwksCache.set(jwksUrl, { jwks, createdAt: now });\r\n return jwks;\r\n}\r\n\r\n/** Limpa o cache de JWKS — uso exclusivo em testes. */\r\nexport function __resetJwksCacheForTests(): void {\r\n _jwksCache.clear();\r\n}\r\n\r\n/** Mapeia claims do JWT pra `NeetruUser`. */\r\nfunction _jwtPayloadToUser(payload: JWTPayload): NeetruUser {\r\n const sub = payload.sub ?? '';\r\n const email = typeof payload.email === 'string' ? payload.email : '';\r\n return {\r\n uid: sub,\r\n email,\r\n emailVerified: typeof payload.email_verified === 'boolean' ? payload.email_verified : undefined,\r\n displayName: typeof payload.name === 'string' ? payload.name : undefined,\r\n photoURL: typeof payload.picture === 'string' ? payload.picture : undefined,\r\n isStaff: payload.is_staff === true,\r\n isCustomer: payload.is_customer === true,\r\n tenantId: typeof payload.tenant_id === 'string' ? payload.tenant_id : undefined,\r\n // Spreads todos os claims originais (aud, iss, iat, exp, etc).\r\n ...payload,\r\n };\r\n}\r\n\r\n// ─── PKCE / OIDC redirect helpers (3.1.3) ────────────────────────────────────\r\n\r\n/** Chave da transação OIDC pendente em `sessionStorage` (state + nonce + PKCE). */\r\nconst OIDC_TX_KEY = 'neetru_oauth_tx';\r\n\r\n/** Transação de um `signIn` em voo, retomada em `handleRedirectCallback`. */\r\ninterface OidcTransaction {\r\n state: string;\r\n nonce: string;\r\n codeVerifier: string;\r\n redirectUri: string;\r\n postLoginRedirect?: string;\r\n}\r\n\r\n/**\r\n * Deriva o origin do IdP (`auth.neetru.com`) a partir do `baseUrl` (api.* →\r\n * auth.*). Override por `globalThis.NEETRU_AUTH_URL` (testes / staging).\r\n */\r\nfunction resolveIdpOrigin(baseUrl: string): string {\r\n const overrideAuthUrl =\r\n typeof (globalThis as { NEETRU_AUTH_URL?: string }).NEETRU_AUTH_URL === 'string'\r\n ? (globalThis as { NEETRU_AUTH_URL?: string }).NEETRU_AUTH_URL\r\n : null;\r\n return overrideAuthUrl ?? baseUrl.replace(/^https?:\\/\\/api\\./, 'https://auth.');\r\n}\r\n\r\n/**\r\n * Acessa WebCrypto de forma defensiva. O fluxo PKCE exige `getRandomValues` +\r\n * `subtle.digest`. Em runtimes sem WebCrypto (http inseguro, browser muito\r\n * antigo) lança `runtime_unsupported` em vez de gerar PKCE fraco.\r\n */\r\nfunction getWebCrypto(): Crypto {\r\n const c = (globalThis as { crypto?: Crypto }).crypto;\r\n if (!c || typeof c.getRandomValues !== 'function' || !c.subtle) {\r\n throw new NeetruError(\r\n 'runtime_unsupported',\r\n 'auth.signIn requer WebCrypto (crypto.subtle) — indisponível neste runtime. Use HTTPS (ou http://localhost) num browser moderno.',\r\n );\r\n }\r\n return c;\r\n}\r\n\r\n/** Codifica bytes em base64url sem padding (browser/Node compat). */\r\nfunction base64UrlFromBytes(bytes: Uint8Array): string {\r\n let str = '';\r\n for (const b of bytes) str += String.fromCharCode(b);\r\n const b64 =\r\n typeof btoa === 'function' ? btoa(str) : Buffer.from(str, 'binary').toString('base64');\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\r\n}\r\n\r\n/** Token URL-safe aleatório de `byteLen` bytes (base64url). 32 bytes → 43 chars. */\r\nfunction randomUrlSafe(crypto: Crypto, byteLen: number): string {\r\n const bytes = new Uint8Array(byteLen);\r\n crypto.getRandomValues(bytes);\r\n return base64UrlFromBytes(bytes);\r\n}\r\n\r\n/** PKCE S256 (RFC 7636 §4.2): `base64url(sha256(code_verifier))`. */\r\nasync function pkceChallengeS256(crypto: Crypto, verifier: string): Promise<string> {\r\n const data = new TextEncoder().encode(verifier);\r\n const digest = await crypto.subtle.digest('SHA-256', data);\r\n return base64UrlFromBytes(new Uint8Array(digest));\r\n}\r\n\r\n/**\r\n * Remove os params do callback OIDC (`code`, `state`, `error`, ...) da URL via\r\n * `history.replaceState`, sem recarregar a página nem deixar o code no histórico.\r\n * Best-effort: no-op se `history` indisponível.\r\n */\r\nfunction cleanCallbackUrl(parsed: URL): void {\r\n try {\r\n const history = (globalThis as { history?: History }).history;\r\n if (!history || typeof history.replaceState !== 'function') return;\r\n const clean = new URL(parsed.toString());\r\n for (const p of ['code', 'state', 'error', 'error_description', 'iss', 'session_state']) {\r\n clean.searchParams.delete(p);\r\n }\r\n history.replaceState(history.state ?? null, '', clean.pathname + clean.search + clean.hash);\r\n } catch {\r\n /* best-effort — não falha o callback se history estiver indisponível */\r\n }\r\n}\r\n\r\n// ─── Real OIDC auth namespace ──────────────────────────────────────────────\r\n\r\n/**\r\n * Implementação real do namespace auth — redireciona pra auth.neetru.com\r\n * em signIn, lê id_token do localStorage (se browser) ou do env em Node.\r\n *\r\n * Storage key: `neetru_id_token`. JWT decoded inline (sem verifyJWT — backend\r\n * já validou; SDK só lê claims pra populate getUser).\r\n */\r\nfunction createOidcAuthNamespace(config: ResolvedConfig): AuthNamespace {\r\n const STORAGE_KEY = 'neetru_id_token';\r\n const listeners = new Set<AuthStateListener>();\r\n let cachedUser: NeetruUser | null = null;\r\n // Bug fix: timer pra notificar listeners quando o token expira proativamente.\r\n // Sem isso, componentes com `onAuthStateChanged` ficam com `user` stale até\r\n // a próxima chamada de `getUser()`. Timer cancelado no signOut.\r\n let _expiryTimerId: ReturnType<typeof setTimeout> | null = null;\r\n\r\n function getStorage(): Storage | null {\r\n try {\r\n return typeof globalThis.localStorage !== 'undefined' ? globalThis.localStorage : null;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /** sessionStorage pra transação OIDC em voo (PKCE verifier + state + nonce). */\r\n function getSessionStorage(): Storage | null {\r\n try {\r\n return typeof globalThis.sessionStorage !== 'undefined' ? globalThis.sessionStorage : null;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n function decodeJwtPayload(token: string): Record<string, unknown> | null {\r\n const parts = token.split('.');\r\n if (parts.length !== 3) return null;\r\n try {\r\n // base64url decode (browser/Node compat).\r\n const b64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');\r\n const pad = '='.repeat((4 - (b64.length % 4)) % 4);\r\n const decoded =\r\n typeof atob === 'function'\r\n ? atob(b64 + pad)\r\n : Buffer.from(b64 + pad, 'base64').toString('utf-8');\r\n return JSON.parse(decoded);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n function tokenToUser(token: string): NeetruUser | null {\r\n const payload = decodeJwtPayload(token);\r\n if (!payload || typeof payload.sub !== 'string') return null;\r\n // BUG fix: valida expiração do JWT antes de retornar usuário.\r\n // `exp` é timestamp Unix em segundos; multiplicamos por 1000 pra comparar\r\n // com Date.now() (ms). Token expirado → null, independente do cache.\r\n if (typeof payload.exp === 'number' && payload.exp * 1000 < Date.now()) {\r\n return null;\r\n }\r\n return {\r\n uid: payload.sub,\r\n email: typeof payload.email === 'string' ? payload.email : '',\r\n emailVerified: typeof payload.email_verified === 'boolean' ? payload.email_verified : undefined,\r\n displayName: typeof payload.name === 'string' ? payload.name : undefined,\r\n photoURL: typeof payload.picture === 'string' ? payload.picture : undefined,\r\n isStaff: payload.is_staff === true,\r\n isCustomer: payload.is_customer === true,\r\n tenantId: typeof payload.tenant_id === 'string' ? payload.tenant_id : undefined,\r\n ...payload,\r\n };\r\n }\r\n\r\n function loadCachedUser(): NeetruUser | null {\r\n // Re-valida cachedUser — pode ter expirado entre chamadas sem reload de página.\r\n // `tokenToUser` já verifica `exp`; ao reler do storage verificamos novamente.\r\n if (cachedUser) {\r\n // `tokenToUser` faz o spread de payload, então `exp` está em cachedUser.\r\n // Verifica expiração diretamente no objeto cached (campo exp é timestamp Unix s).\r\n const exp = (cachedUser as unknown as Record<string, unknown>).exp;\r\n if (typeof exp === 'number' && exp * 1000 < Date.now()) {\r\n // Token expirado — limpa cache e storage.\r\n cachedUser = null;\r\n const storage = getStorage();\r\n storage?.removeItem(STORAGE_KEY);\r\n notify();\r\n return null;\r\n }\r\n return cachedUser;\r\n }\r\n const storage = getStorage();\r\n if (!storage) return null;\r\n const token = storage.getItem(STORAGE_KEY);\r\n if (!token) return null;\r\n const user = tokenToUser(token);\r\n if (!user) {\r\n // Token inválido ou expirado — remove do storage.\r\n storage.removeItem(STORAGE_KEY);\r\n return null;\r\n }\r\n cachedUser = user;\r\n // Agenda notificação proativa de expiração pra listeners não ficarem stale.\r\n scheduleExpiryTimer(user);\r\n return cachedUser;\r\n }\r\n\r\n function notify(): void {\r\n for (const l of listeners) {\r\n try {\r\n l(cachedUser);\r\n } catch {\r\n /* ignore consumer errors */\r\n }\r\n }\r\n }\r\n\r\n /** Cancela o timer de expiração pendente, se houver. */\r\n function cancelExpiryTimer(): void {\r\n if (_expiryTimerId !== null) {\r\n clearTimeout(_expiryTimerId);\r\n _expiryTimerId = null;\r\n }\r\n }\r\n\r\n /**\r\n * Agenda um timer para notificar listeners quando o token expirar.\r\n * Chama `loadCachedUser()` no vencimento, que já limpa cache + chama `notify()`.\r\n * Se `exp` for inválido ou já expirado, não agenda.\r\n */\r\n function scheduleExpiryTimer(user: NeetruUser): void {\r\n cancelExpiryTimer();\r\n const exp = (user as unknown as Record<string, unknown>).exp;\r\n if (typeof exp !== 'number') return;\r\n const msUntilExpiry = exp * 1000 - Date.now();\r\n if (msUntilExpiry <= 0) return; // já expirado — não agendar\r\n // +1ms garante que Date.now() esteja estritamente após exp*1000 quando\r\n // o callback rodar (evita race condition com igualdade exata de ms).\r\n _expiryTimerId = setTimeout(() => {\r\n _expiryTimerId = null;\r\n loadCachedUser(); // detecta expiração, limpa cache e chama notify()\r\n }, msUntilExpiry + 1);\r\n }\r\n\r\n return {\r\n async signIn(options?: SignInOptions): Promise<NeetruUser | void> {\r\n // Em browser, redireciona pro authorize endpoint do IdP (auth.neetru.com).\r\n // Fix audit 2026-05-15: antes apontava `api.neetru.com/oauth/authorize`\r\n // (404 — middleware só roteia /api/v1/oauth a partir de auth.neetru.com).\r\n // O issuer canônico é `auth.neetru.com` (vide PLATFORM_IDENTIDADE.md).\r\n if (typeof globalThis.location !== 'undefined' && typeof globalThis.location.assign === 'function') {\r\n // Bug 2 (bug_c1c96a00): o /authorize do Core EXIGE `nonce` + `state` e\r\n // valida PKCE. Antes mandávamos só response_type/redirect/scope/state(=href)\r\n // → 302 de volta com `invalid_request: nonce is required` (fluxo quebrado\r\n // ponta-a-ponta). Agora geramos state CSRF aleatório, nonce e o par PKCE\r\n // S256, e guardamos a transação pra retomar no callback.\r\n const crypto = getWebCrypto();\r\n const redirectUri = options?.redirectUri ?? globalThis.location.origin;\r\n const scope = options?.scope ?? 'openid profile email';\r\n\r\n // client_id: prefere o oidcClientId (oidc_clients/{id}, par id+segredo do\r\n // produto). Cai no keyId da apiKey por compat — mas o Core só reconhece um\r\n // oidc_clients válido, então oidcClientId é o caminho correto em produção.\r\n let clientId = config.oidcClientId;\r\n if (!clientId && config.apiKey) {\r\n // H-02 fix: parse seguro (throws se malformado) — nunca vaza a apiKey\r\n // inteira como client_id.\r\n clientId = parseApiKey(config.apiKey).keyId;\r\n }\r\n if (!clientId) {\r\n throw new NeetruError(\r\n 'invalid_config',\r\n 'auth.signIn requer `oidcClientId` (ou `apiKey`) configurado para montar o client_id.',\r\n );\r\n }\r\n\r\n const state = randomUrlSafe(crypto, 16);\r\n const nonce = randomUrlSafe(crypto, 16);\r\n // RFC 7636 §4.1: verifier 43..128 chars. 32 bytes → 43 chars base64url.\r\n const codeVerifier = randomUrlSafe(crypto, 32);\r\n const codeChallenge = await pkceChallengeS256(crypto, codeVerifier);\r\n\r\n // Persiste a transação ANTES do redirect (sobrevive ao round-trip same-tab).\r\n const session = getSessionStorage();\r\n if (!session) {\r\n throw new NeetruError(\r\n 'runtime_unsupported',\r\n 'auth.signIn requer sessionStorage para guardar a transação PKCE entre o redirect e o callback.',\r\n );\r\n }\r\n const tx: OidcTransaction = {\r\n state,\r\n nonce,\r\n codeVerifier,\r\n redirectUri,\r\n postLoginRedirect: options?.postLoginRedirect,\r\n };\r\n session.setItem(OIDC_TX_KEY, JSON.stringify(tx));\r\n\r\n const idpOrigin = resolveIdpOrigin(config.baseUrl);\r\n const url = new URL('/api/v1/oauth/authorize', idpOrigin);\r\n url.searchParams.set('response_type', 'code');\r\n url.searchParams.set('client_id', clientId);\r\n url.searchParams.set('redirect_uri', redirectUri);\r\n url.searchParams.set('scope', scope);\r\n url.searchParams.set('state', state);\r\n url.searchParams.set('nonce', nonce);\r\n url.searchParams.set('code_challenge', codeChallenge);\r\n url.searchParams.set('code_challenge_method', 'S256');\r\n globalThis.location.assign(url.toString());\r\n return;\r\n }\r\n // Não-browser sem mock — não dá pra signIn interativo.\r\n throw new NeetruError(\r\n 'invalid_config',\r\n 'auth.signIn requires a browser context or mocks. Use NEETRU_ENV=dev or pass mocks.auth.',\r\n );\r\n },\r\n\r\n async handleRedirectCallback(currentUrl?: string): Promise<RedirectCallbackResult | null> {\r\n const href =\r\n currentUrl ??\r\n (typeof globalThis.location !== 'undefined' ? globalThis.location.href : undefined);\r\n if (!href) return null;\r\n let parsed: URL;\r\n try {\r\n parsed = new URL(href);\r\n } catch {\r\n return null;\r\n }\r\n const params = parsed.searchParams;\r\n\r\n // IdP devolveu erro (ex: access_denied, invalid_scope) — propaga com o\r\n // próprio código de erro do OAuth e limpa a transação pendente.\r\n const idpError = params.get('error');\r\n if (idpError) {\r\n const desc = params.get('error_description') ?? idpError;\r\n getSessionStorage()?.removeItem(OIDC_TX_KEY);\r\n cleanCallbackUrl(parsed);\r\n throw new NeetruError(idpError, `OIDC authorize falhou: ${desc}`);\r\n }\r\n\r\n const code = params.get('code');\r\n if (!code) return null; // não é um callback OIDC — nada a fazer\r\n\r\n const returnedState = params.get('state');\r\n const session = getSessionStorage();\r\n const txRaw = session?.getItem(OIDC_TX_KEY) ?? null;\r\n let tx: OidcTransaction | null = null;\r\n if (txRaw) {\r\n try {\r\n tx = JSON.parse(txRaw) as OidcTransaction;\r\n } catch {\r\n tx = null;\r\n }\r\n }\r\n\r\n if (!tx) {\r\n throw new NeetruError(\r\n 'oidc_state_mismatch',\r\n 'Callback OIDC sem transação pendente — `signIn` não foi iniciado nesta sessão (ou já consumido).',\r\n );\r\n }\r\n // CSRF: o state retornado precisa bater com o gerado no signIn.\r\n if (!returnedState || returnedState !== tx.state) {\r\n session?.removeItem(OIDC_TX_KEY);\r\n cleanCallbackUrl(parsed);\r\n throw new NeetruError(\r\n 'oidc_state_mismatch',\r\n 'state do callback OIDC não confere com o da transação (possível CSRF).',\r\n );\r\n }\r\n\r\n // Sucesso: consome a transação (single-use) e tira os params da URL.\r\n session?.removeItem(OIDC_TX_KEY);\r\n cleanCallbackUrl(parsed);\r\n\r\n return {\r\n code,\r\n codeVerifier: tx.codeVerifier,\r\n redirectUri: tx.redirectUri,\r\n nonce: tx.nonce,\r\n state: tx.state,\r\n postLoginRedirect: tx.postLoginRedirect,\r\n };\r\n },\r\n\r\n getIdToken(): string | null {\r\n const storage = getStorage();\r\n const token = storage?.getItem(STORAGE_KEY) ?? null;\r\n if (!token) return null;\r\n // Não devolve token expirado/malformado — o BFF rejeitaria de qualquer forma.\r\n // `tokenToUser` retorna null se exp no passado ou payload inválido.\r\n return tokenToUser(token) ? token : null;\r\n },\r\n\r\n async signOut(): Promise<void> {\r\n // BUG fix (RFC 7009): lê o token ANTES de remover do storage para incluir\r\n // no corpo do POST de revoke. Sem o token, o servidor não tem como\r\n // identificar qual sessão invalidar — refresh token permaneceria válido.\r\n const storage = getStorage();\r\n const storedToken = storage?.getItem(STORAGE_KEY) ?? null;\r\n if (storage) storage.removeItem(STORAGE_KEY);\r\n cancelExpiryTimer(); // cancela timer de expiração pendente ao fazer logout\r\n cachedUser = null;\r\n // Best-effort revoke no server. O endpoint canônico é\r\n // auth.neetru.com/api/v1/oauth/revoke (não api.neetru.com). Aplica a\r\n // mesma derivação api.* → auth.* usada no signIn().\r\n //\r\n // L-02 fix (Opus review): retry 1× com backoff 500ms em falha network.\r\n // Refresh token continua válido se ambas tentativas falharem — caller\r\n // deve assumir que pode ter sessão server-side stale e re-autenticar.\r\n const overrideAuthUrl =\r\n typeof (globalThis as { NEETRU_AUTH_URL?: string }).NEETRU_AUTH_URL === 'string'\r\n ? (globalThis as { NEETRU_AUTH_URL?: string }).NEETRU_AUTH_URL\r\n : null;\r\n const idpOrigin =\r\n overrideAuthUrl ?? config.baseUrl.replace(/^https?:\\/\\/api\\./, 'https://auth.');\r\n const revokeUrl = `${idpOrigin}/api/v1/oauth/revoke`;\r\n // RFC 7009 §2.1: inclui `token` no corpo sem `token_type_hint`.\r\n // Bug fix: o token em storage é um id_token OIDC — usar hint 'access_token'\r\n // faz servidores que roteiam por tipo não encontrarem a sessão e ignorarem\r\n // a revogação. Sem hint o servidor tenta todos os tipos (RFC 7009 §2.1 §4.1.2).\r\n // Se não há token armazenado (ex: signIn em Node sem storage), pula o revoke.\r\n const revokeBody = storedToken\r\n ? JSON.stringify({ token: storedToken })\r\n : null;\r\n let revokeError: unknown = null;\r\n for (let attempt = 0; attempt < 2; attempt++) {\r\n try {\r\n if (revokeBody) {\r\n await config.fetch(revokeUrl, {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n body: revokeBody,\r\n });\r\n }\r\n revokeError = null;\r\n break;\r\n } catch (err) {\r\n revokeError = err;\r\n if (attempt === 0) {\r\n // Backoff 500ms antes do retry final.\r\n await new Promise((resolve) => setTimeout(resolve, 500));\r\n }\r\n }\r\n }\r\n if (revokeError && typeof console !== 'undefined') {\r\n console.warn(\r\n '[neetru-sdk] signOut: server-side revoke falhou (2 tentativas). Refresh token pode estar stale.',\r\n revokeError,\r\n );\r\n }\r\n notify();\r\n },\r\n\r\n getUser(): NeetruUser | null {\r\n return loadCachedUser();\r\n },\r\n\r\n onAuthStateChanged(listener: AuthStateListener): () => void {\r\n listeners.add(listener);\r\n try {\r\n listener(loadCachedUser());\r\n } catch {\r\n /* ignore */\r\n }\r\n return () => {\r\n listeners.delete(listener);\r\n };\r\n },\r\n\r\n async verifyToken(token: string, options?: VerifyTokenOptions): Promise<NeetruUser> {\r\n if (!token || typeof token !== 'string') {\r\n throw new NeetruError('token_invalid_signature', 'token must be a non-empty string');\r\n }\r\n\r\n // Deriva o issuer e JWKS URL a partir do baseUrl (api.* → auth.*).\r\n const overrideAuthUrl =\r\n typeof (globalThis as { NEETRU_AUTH_URL?: string }).NEETRU_AUTH_URL === 'string'\r\n ? (globalThis as { NEETRU_AUTH_URL?: string }).NEETRU_AUTH_URL\r\n : null;\r\n const idpOrigin = overrideAuthUrl ?? config.baseUrl.replace(/^https?:\\/\\/api\\./, 'https://auth.');\r\n const issuer = idpOrigin;\r\n const jwksUrl = `${idpOrigin}/api/v1/oauth/.well-known/jwks.json`;\r\n const cacheTtlMs = options?.jwksCacheTtlMs ?? DEFAULT_JWKS_TTL_MS;\r\n\r\n // Audience é OBRIGATÓRIA — sem ela um token emitido para um client diferente\r\n // passaria na verificação de assinatura/issuer sem ser detectado.\r\n // Fontes (em ordem de prioridade):\r\n // 1. options.audience passado explicitamente pelo caller.\r\n // 2. keyId derivado do apiKey configurado no client.\r\n // Se nenhuma fonte estiver disponível, lança invalid_config imediatamente.\r\n const audienceFromOptions = options?.audience;\r\n const parsedKey = tryParseApiKey(config.apiKey);\r\n const audience = audienceFromOptions ?? parsedKey?.keyId;\r\n\r\n if (!audience) {\r\n throw new NeetruError(\r\n 'invalid_config',\r\n 'verifyToken requires an audience: provide apiKey on the client or pass options.audience. ' +\r\n 'Calling jwtVerify without an audience allows tokens issued for other OIDC clients to pass.',\r\n );\r\n }\r\n\r\n const jwks = _getJwks(jwksUrl, cacheTtlMs);\r\n\r\n try {\r\n const { payload } = await jwtVerify(token, jwks, {\r\n issuer,\r\n audience,\r\n algorithms: ['RS256'],\r\n });\r\n return _jwtPayloadToUser(payload);\r\n } catch (err: unknown) {\r\n // jose lança JWTExpired, JWTClaimValidationFailed, JWSSignatureVerificationFailed etc.\r\n // Mapeamos pra NeetruErrorCode tipado.\r\n const errName = (err as { code?: string })?.code ?? (err as Error)?.name ?? '';\r\n const errMsg = (err as Error)?.message ?? String(err);\r\n\r\n if (errName === 'ERR_JWT_EXPIRED') {\r\n throw new NeetruError('token_expired', `Token expired: ${errMsg}`);\r\n }\r\n if (errName === 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED') {\r\n throw new NeetruError('token_invalid_signature', `Token signature invalid: ${errMsg}`);\r\n }\r\n if (errName === 'ERR_JWT_CLAIM_VALIDATION_FAILED') {\r\n // jose inclui o nome do claim na mensagem. Ex: 'unexpected \"aud\" claim value'\r\n // ou 'iss claim value mismatch'.\r\n if (errMsg.includes('\"aud\"') || errMsg.includes('audience')) {\r\n throw new NeetruError('token_invalid_audience', `Token audience mismatch: ${errMsg}`);\r\n }\r\n if (errMsg.includes('\"iss\"') || errMsg.includes('issuer')) {\r\n throw new NeetruError('token_invalid_issuer', `Token issuer mismatch: ${errMsg}`);\r\n }\r\n throw new NeetruError('token_invalid_signature', `Token claim validation failed: ${errMsg}`);\r\n }\r\n // Qualquer outro erro de verificação (JWKS fetch, parse, exp checado via claim etc).\r\n throw new NeetruError('token_invalid_signature', `Token verification failed: ${errMsg}`);\r\n }\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Cria uma instância imutável do cliente Neetru SDK.\r\n *\r\n * @example\r\n * ```ts\r\n * import { createNeetruClient } from '@neetru/sdk';\r\n *\r\n * const client = createNeetruClient({\r\n * apiKey: 'nrt_a1b2c3d4_xY9z...',\r\n * });\r\n *\r\n * const { products } = await client.catalog.list();\r\n * const can = await client.entitlements.check('neetru-pulse', 'export-pdf');\r\n * await client.telemetry.event({ name: 'report_exported' });\r\n * await client.usage.track('api_call', { route: '/x' });\r\n * await client.support.createTicket({ subject: 'help', message: '...' });\r\n * ```\r\n *\r\n * @throws {NeetruError} `invalid_config` se fetch não disponível no runtime.\r\n */\r\nexport function createNeetruClient(config: NeetruClientConfig = {}): NeetruClient {\r\n const fetchImpl = config.fetch ?? globalThis.fetch;\r\n if (typeof fetchImpl !== 'function') {\r\n throw new NeetruError(\r\n 'invalid_config',\r\n 'fetch is not available in this runtime. Pass `fetch` explicitly to createNeetruClient.',\r\n );\r\n }\r\n\r\n // 3.0: validateBaseUrl rejeita URLs fora da allowlist (*.neetru.com /\r\n // localhost / configured allowedHosts). Bypass via NEETRU_ALLOW_INSECURE_BASEURL=1.\r\n const rawBaseUrl = config.baseUrl ?? DEFAULT_BASE_URL;\r\n const baseUrl = validateBaseUrl(rawBaseUrl, config.allowedHosts ?? []);\r\n const apiKey = config.apiKey ?? readEnvApiKey();\r\n const env = resolveEnv(config.env);\r\n\r\n // `bind` garante `this` correto em runtimes que validam (ex: undici).\r\n const resolved: ResolvedConfig = Object.freeze({\r\n apiKey,\r\n oidcClientId: config.oidcClientId,\r\n baseUrl,\r\n fetch: fetchImpl.bind(globalThis),\r\n env,\r\n productId: config.productId,\r\n tenantId: config.tenantId,\r\n });\r\n\r\n // Em dev, sempre ativa mocks. Mocks explícitos sempre vencem.\r\n const isDev = env === 'dev';\r\n const auth = config.mocks?.auth ?? (isDev ? new MockAuth({ ...DEV_FIXTURE_USER }) : createOidcAuthNamespace(resolved));\r\n const usage = config.mocks?.usage ?? (isDev ? new MockUsage() : createUsageNamespace(resolved));\r\n const support = config.mocks?.support ?? (isDev ? new MockSupport() : createSupportNamespace(resolved));\r\n const entitlements = config.mocks?.entitlements ?? (isDev ? new MockEntitlements() : createEntitlementsNamespace(resolved));\r\n const db = config.mocks?.db ?? createNeetruDb(resolved, config.db);\r\n const webhooks = config.mocks?.webhooks ?? (isDev ? new MockWebhooks() : createWebhooksNamespace(resolved));\r\n const notifications = config.mocks?.notifications ?? (isDev ? new MockNotifications() : createNotificationsNamespace(resolved));\r\n\r\n const client: NeetruClient = Object.freeze({\r\n config: resolved,\r\n auth,\r\n catalog: createCatalogNamespace(resolved),\r\n entitlements,\r\n telemetry: createTelemetryNamespace(resolved),\r\n usage,\r\n support,\r\n db,\r\n checkout: createCheckoutNamespace(resolved),\r\n webhooks,\r\n notifications,\r\n });\r\n\r\n return client;\r\n}\r\n","/**\n * Helper canonical pra parsing de apiKey Neetru.\n *\n * Formato: `nrt_<keyId>_<secret>` onde keyId e secret sao tokens\n * alfanumericos sem underscore.\n *\n * **H-02 fix (Opus review 2026-05-27):** o uso anterior `apiKey.split('_')[1]`\n * com fallback `?? apiKey` vazava a chave inteira como `client_id` na URL\n * publica de OAuth se o consumer passasse uma string malformada\n * (typo, ou key de outro provider colada por engano).\n *\n * Agora valida o formato e throws `NeetruError('invalid_config')` em\n * input malformado.\n */\nimport { NeetruError } from './errors';\n\nconst API_KEY_RE = /^nrt_([A-Za-z0-9]+)_([A-Za-z0-9]+)$/;\n\nexport interface ParsedApiKey {\n keyId: string;\n secret: string;\n}\n\n/**\n * Faz parse seguro da apiKey. Throws `NeetruError('invalid_config')`\n * se o formato nao bater.\n *\n * @example\n * ```ts\n * const { keyId, secret } = parseApiKey('nrt_kid123_sec456');\n * // -> { keyId: 'kid123', secret: 'sec456' }\n * ```\n */\nexport function parseApiKey(apiKey: string | undefined | null): ParsedApiKey {\n if (typeof apiKey !== 'string' || apiKey.length === 0) {\n throw new NeetruError(\n 'invalid_config',\n 'apiKey is required (formato nrt_<keyId>_<secret>)',\n );\n }\n const match = API_KEY_RE.exec(apiKey);\n if (!match) {\n throw new NeetruError(\n 'invalid_config',\n 'apiKey malformado - esperado formato nrt_<keyId>_<secret>',\n );\n }\n return { keyId: match[1], secret: match[2] };\n}\n\n/**\n * Variante que retorna `null` ao inves de throw - util pra paths\n * opcionais onde apiKey pode estar vazio (signOut sem auth previo).\n */\nexport function tryParseApiKey(apiKey: string | undefined | null): ParsedApiKey | null {\n if (typeof apiKey !== 'string' || apiKey.length === 0) return null;\n const match = API_KEY_RE.exec(apiKey);\n if (!match) return null;\n return { keyId: match[1], secret: match[2] };\n}\n","/**\n * baseUrl allowlist (HIGH-SDK-05) — fail-closed contra phishing/MITM.\n *\n * Default allow:\n * - HTTPS para `*.neetru.com` (apex e qualquer subdomínio)\n * - HTTP **apenas** para localhost / 127.0.0.1 / [::1] / *.test / *.localhost\n * - HTTPS para qualquer hostname **se** estiver em `allowedHosts` configurado\n * pelo consumer (override explícito)\n *\n * Bypass: `NEETRU_ALLOW_INSECURE_BASEURL=1` no env (Node) ou `globalThis.NEETRU_ALLOW_INSECURE_BASEURL = '1'`\n * (browser/Edge). Útil em tests / staging customizado / proxies. Lança warning\n * no console quando ativo.\n *\n * Por que: caller pode configurar `createNeetruClient({apiKey: 'nrt_xxx', baseUrl: 'http://attacker.example/'})`.\n * Sem allowlist, todo Bearer vaza pro atacker. SDK 3.0 fail-closed.\n */\nimport { NeetruError } from './errors';\n\n/** Hosts considerados loopback (dev local). */\nconst LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]', '::1']);\n\n/** Suffix oficial de produção/staging Neetru. */\nconst NEETRU_SUFFIX = '.neetru.com';\n\n/** Hostnames apex sem dot (raríssimo, mas defensivo). */\nconst NEETRU_APEX = 'neetru.com';\n\n/**\n * Detecta sub-host de dev TLD seguro (M-02 fix).\n *\n * Antes: `hostname.endsWith('.localhost')` aceitava `evil.com.localhost`\n * (TLD `.localhost` real). Agora regex força que `.localhost`/`.test` seja\n * o SUFFIX TLD e o subdomínio seja simples (sem outros pontos seguindo).\n *\n * Aceita:\n * - `myapp.test`\n * - `frontend.localhost`\n * - `app.localhost`\n * - `localhost` (cai no LOOPBACK_HOSTS, não aqui)\n *\n * Rejeita:\n * - `evil.com.localhost` (TLD `.localhost` malicioso registrado)\n * - `attacker.evil.test` (subdomínio profundo)\n * - `xn--neetr-rta.localhost` (IDN punycode)\n */\nconst SAFE_DEV_HOST_RE = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?\\.(test|localhost)$/;\n\nfunction isSafeDevHost(hostname: string): boolean {\n return SAFE_DEV_HOST_RE.test(hostname);\n}\n\n/** Normaliza trailing-dot FQDN (`api.neetru.com.` → `api.neetru.com`). L-06 fix. */\nfunction normalizeHostname(hostname: string): string {\n return hostname.toLowerCase().replace(/\\.+$/, '');\n}\n\n/**\n * Valida que `baseUrl` é seguro pra enviar Bearer tokens. Retorna URL\n * normalizada (trim trailing slash). Lança `NeetruError('invalid_config')`\n * em rejeição, exceto se override estiver ativo.\n *\n * @param baseUrl URL configurada pelo caller (raw, antes de normalização).\n * @param allowedHosts Hostnames extras permitidos (override do consumer). Suffix match.\n * @returns URL validada e normalizada (sem trailing slash).\n *\n * @throws NeetruError('invalid_config') se URL inválida ou fora da allowlist.\n */\nexport function validateBaseUrl(baseUrl: string, allowedHosts: string[] = []): string {\n if (typeof baseUrl !== 'string' || baseUrl.length === 0) {\n throw new NeetruError('invalid_config', 'baseUrl is required');\n }\n\n let parsed: URL;\n try {\n parsed = new URL(baseUrl);\n } catch {\n throw new NeetruError('invalid_config', `baseUrl is not a valid URL: ${baseUrl}`);\n }\n\n const protocol = parsed.protocol;\n // L-06: normaliza trailing dot (FQDN absoluto). M-02: já em lowercase.\n const hostname = normalizeHostname(parsed.hostname);\n\n // Bypass explícito — útil em tests / staging custom proxies.\n if (isInsecureBypassActive()) {\n if (typeof console !== 'undefined') {\n console.warn(\n `[neetru-sdk] NEETRU_ALLOW_INSECURE_BASEURL=1 ativo. baseUrl=${baseUrl} aceito sem validação.`,\n );\n }\n return baseUrl.replace(/\\/+$/, '');\n }\n\n // Bloqueia file:, javascript:, etc.\n if (protocol !== 'https:' && protocol !== 'http:') {\n throw new NeetruError(\n 'invalid_config',\n `baseUrl protocol must be http: or https:, got ${protocol}`,\n );\n }\n\n // HTTP só pra loopback / dev seguro.\n if (protocol === 'http:') {\n const isLoopback =\n LOOPBACK_HOSTS.has(hostname) ||\n isSafeDevHost(hostname);\n if (!isLoopback) {\n throw new NeetruError(\n 'invalid_config',\n `baseUrl with http: only allowed for localhost/127.0.0.1/*.test/*.localhost. Got: ${hostname}. Use https: or set NEETRU_ALLOW_INSECURE_BASEURL=1 to bypass.`,\n );\n }\n return baseUrl.replace(/\\/+$/, '');\n }\n\n // HTTPS: aceita *.neetru.com automaticamente, ou hostnames em allowedHosts.\n const isNeetruDomain =\n hostname === NEETRU_APEX || hostname.endsWith(NEETRU_SUFFIX);\n const isAllowedHost = allowedHosts.some((allowed) => {\n const norm = allowed.toLowerCase();\n return hostname === norm || hostname.endsWith(`.${norm}`);\n });\n // Loopback HTTPS também aceito (raro mas válido).\n const isLoopbackHttps =\n LOOPBACK_HOSTS.has(hostname) ||\n isSafeDevHost(hostname);\n\n if (!isNeetruDomain && !isAllowedHost && !isLoopbackHttps) {\n throw new NeetruError(\n 'invalid_config',\n `baseUrl ${hostname} is not in the allowlist. Allowed: *.neetru.com, localhost, or configure { allowedHosts: ['...'] }. Bypass: NEETRU_ALLOW_INSECURE_BASEURL=1.`,\n );\n }\n\n return baseUrl.replace(/\\/+$/, '');\n}\n\n/** Lê flag de bypass do env (Node) ou globalThis (browser/Edge). */\nfunction isInsecureBypassActive(): boolean {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const proc = (globalThis as any).process;\n const envVal = proc?.env?.NEETRU_ALLOW_INSECURE_BASEURL;\n if (envVal === '1' || envVal === 'true') return true;\n } catch {\n /* ignore */\n }\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const g = (globalThis as any).NEETRU_ALLOW_INSECURE_BASEURL;\n if (g === '1' || g === 'true' || g === true) return true;\n } catch {\n /* ignore */\n }\n return false;\n}\n","/**\r\n * Tipos públicos do SDK Neetru.\r\n *\r\n * Vendor-neutral: nada aqui referencia `firebase/*`, `stripe`, ou qualquer\r\n * provider interno. Caller só vê superfície neutra (Product, Entitlement, ...).\r\n */\r\n\r\n/** Default base URL pra API pública Neetru. */\r\nexport const DEFAULT_BASE_URL = 'https://api.neetru.com';\r\n\r\n/**\r\n * Configuração passada pra `createNeetruClient`.\r\n */\r\nexport interface NeetruClientConfig {\r\n /**\r\n * Bearer token Neetru (formato `nrt_<keyId>_<secret>`). Opcional —\r\n * se ausente, o SDK tenta `process.env.NEETRU_API_KEY` em Node.\r\n *\r\n * Endpoints públicos (catalog) funcionam sem apiKey. Endpoints autenticados\r\n * (entitlements, telemetry) lançam `missing_api_key` se ausente.\r\n */\r\n apiKey?: string;\r\n /**\r\n * 3.1.3 — `client_id` do client OIDC confidencial do produto, registrado em\r\n * `oidc_clients/{id}` no Core (par id + segredo, modelo Firebase/Facebook).\r\n *\r\n * Usado como `client_id` no fluxo `auth.signIn()` (Authorization Code + PKCE).\r\n * É **distinto** do `keyId` embutido na `apiKey` (`nrt_<keyId>_<secret>`), que\r\n * identifica a API key de máquina — não um client OIDC. Se ausente, `signIn`\r\n * cai no `keyId` por compat, mas o `/authorize` do Core só reconhece um\r\n * `oidc_clients` válido, então registre e passe `oidcClientId` em produção.\r\n */\r\n oidcClientId?: string;\r\n /**\r\n * URL base da API Neetru. Default: `https://api.neetru.com`.\r\n * Útil em testes apontando pra staging ou mock server.\r\n */\r\n baseUrl?: string;\r\n /**\r\n * Implementação de fetch customizada. Default: `globalThis.fetch`.\r\n * Necessário em runtimes que não exponham fetch global por default.\r\n */\r\n fetch?: typeof globalThis.fetch;\r\n /**\r\n * Modo de runtime. `dev` ativa mocks (auth retorna user fixture, usage só\r\n * loga, support retorna lista fake). `workspace` e `prod` chamam HTTP real.\r\n *\r\n * Default: lê `process.env.NEETRU_ENV` (Node) ou `globalThis.NEETRU_ENV`\r\n * (browser); fallback `prod`.\r\n */\r\n env?: 'dev' | 'workspace' | 'prod';\r\n /**\r\n * Override de mocks — útil em tests do consumer pra injetar fixtures\r\n * determinísticos (sem depender de NEETRU_ENV=dev).\r\n */\r\n mocks?: {\r\n auth?: AuthNamespace;\r\n usage?: UsageNamespace;\r\n support?: SupportNamespace;\r\n entitlements?: NeetruClient['entitlements'];\r\n /** v2.0: aceita NeetruDb (inclui MockDb). DbNamespace legado não é mais aceito. */\r\n db?: import('./db/client-db').NeetruDb;\r\n webhooks?: import('./webhooks').WebhooksNamespace;\r\n notifications?: import('./notifications').NotificationsNamespace;\r\n };\r\n /**\r\n * v0.3 — productId default usado por `usage.report()` / `usage.check()` /\r\n * `db.collection()` quando não passado explicitamente nas options.\r\n */\r\n productId?: string;\r\n /**\r\n * v0.3 — tenantId default usado por `usage.report()` / `usage.check()` /\r\n * `db.collection()` quando não passado explicitamente nas options.\r\n */\r\n tenantId?: string;\r\n /**\r\n * v2.0 — Configuração do banco lógico: transport, dbId, coleções.\r\n * Gerado pelo scaffold `neetru db init`. Opcional — padrão é transport='rest'.\r\n *\r\n * Use `transport` (v2.3+) em vez do campo `engine` depreciado.\r\n * Valores: `'rest'` | `'firestore'` | `'nosql-vm'`.\r\n */\r\n db?: import('./db/client-db').NeetruDbOptions;\r\n /**\r\n * 3.0 — hosts adicionais permitidos para `baseUrl`. Por default, SDK aceita\r\n * `*.neetru.com` HTTPS + localhost. Para apontar pra staging/proxy custom em\r\n * `https://meu-proxy.empresa.com`, adicione `['empresa.com']`.\r\n *\r\n * Bypass total: `NEETRU_ALLOW_INSECURE_BASEURL=1` no env.\r\n */\r\n allowedHosts?: string[];\r\n}\r\n\r\n/**\r\n * Status do produto no catálogo público.\r\n */\r\nexport type ProductStatus = 'live' | 'soon' | 'beta';\r\n\r\n/**\r\n * Produto SaaS publicado pelo Neetru Core.\r\n *\r\n * Schema neutro — alinhado com `public_products/{slug}` no backend mas\r\n * nunca expõe campos internos (Firestore Timestamps, draft state, etc).\r\n */\r\nexport interface Product {\r\n /** Identificador estável do produto, ex: `neetru-pulse`. */\r\n slug: string;\r\n /** Nome de exibição, ex: `Neetru Pulse`. */\r\n name: string;\r\n /** Subtítulo curto, ex: `Gestão de operações`. */\r\n tagline?: string;\r\n /** Descrição longa em prosa. */\r\n description?: string;\r\n /** Status público do produto. */\r\n status?: ProductStatus;\r\n /** Hint de ícone (catálogo de keys interno do Core). */\r\n iconKey?: string;\r\n /** Link override do CTA principal (default: página do produto). */\r\n ctaHref?: string;\r\n /** Label override do CTA. */\r\n ctaLabel?: string;\r\n /** Lista opcional de planos cobrados. Pode ser preenchida v0.2+. */\r\n plans?: ProductPlan[];\r\n}\r\n\r\n/** Plano cobrado de um produto (placeholder v0.1 — schema final v0.2). */\r\nexport interface ProductPlan {\r\n id: string;\r\n name: string;\r\n /** Preço mensal em centavos (BRL). Pode ser undefined em planos custom. */\r\n amountCents?: number;\r\n features?: string[];\r\n}\r\n\r\n/**\r\n * Resposta do `client.catalog.list()`.\r\n */\r\nexport interface CatalogListResponse {\r\n products: Product[];\r\n fetchedAt: string;\r\n}\r\n\r\n/**\r\n * Resposta do `client.entitlements.check(productSlug, feature)`.\r\n *\r\n * `allowed` é o sinal forte; `reason` ajuda a debugar (não exibir pro user\r\n * final).\r\n */\r\nexport interface EntitlementCheck {\r\n allowed: boolean;\r\n productSlug: string;\r\n feature: string;\r\n /** Reason code estável: `granted` | `not_subscribed` | `feature_not_in_plan` | `expired`. */\r\n reason?: string;\r\n}\r\n\r\n/**\r\n * Payload pra `client.telemetry.event()`.\r\n */\r\nexport interface TelemetryEventInput {\r\n /** Nome do evento, ex: `dashboard_opened`, `report_exported`. */\r\n name: string;\r\n /** Atributos adicionais (chave → valor primitivo). */\r\n properties?: Record<string, string | number | boolean | null>;\r\n /** Timestamp ISO opcional; default = server time. */\r\n timestamp?: string;\r\n}\r\n\r\n/**\r\n * Confirmação de aceitação do evento de telemetria.\r\n */\r\nexport interface TelemetryEventAck {\r\n ok: true;\r\n /** ID gerado pelo backend pra evento (`usage_events/{id}`). */\r\n eventId: string;\r\n}\r\n\r\n// ─── Sprint 6 — Telemetry log per-product ──────────────────────────────────\r\n\r\nexport type TelemetryLogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal';\r\n\r\nexport interface TelemetryLogInput {\r\n level: TelemetryLogLevel;\r\n message: string;\r\n metadata?: Record<string, unknown>;\r\n /** Override correlationId (default: lê dos headers/env automaticamente). */\r\n correlationId?: string;\r\n /** Slug do produto. Se ausente, o SDK usa `config.productId` como default\r\n * (o backend NÃO infere — exige productSlug no body, fail-closed). */\r\n productSlug?: string;\r\n}\r\n\r\nexport interface TelemetryLogAck {\r\n ok: true;\r\n /** ID do log gravado (`logs/{productId}/{yyyymmdd}/{logId}`) — opcional em mocks. */\r\n logId?: string;\r\n /** Indicador de modo (mock vs http). */\r\n mode: 'mock' | 'http';\r\n}\r\n\r\n/**\r\n * Handle imutável retornado por `createNeetruClient`. Carrega namespaces\r\n * `auth`, `catalog`, `entitlements`, `telemetry`, `usage`, `support`.\r\n *\r\n * Cada namespace é exposto como objeto chamável — espelha API Firebase\r\n * (`auth`, `firestore`) ou Stripe (`paymentIntents`, `customers`).\r\n */\r\nexport interface NeetruClient {\r\n /** Configuração resolvida (apiKey, baseUrl, fetch). Read-only. */\r\n readonly config: ResolvedConfig;\r\n /** Namespace auth (v0.2 — OIDC + mocks dev). */\r\n readonly auth: AuthNamespace;\r\n /** Namespace catálogo público de produtos. */\r\n readonly catalog: {\r\n /** Lista produtos publicados. */\r\n list(opts?: CatalogListOptions): Promise<CatalogListResponse>;\r\n /** Busca produto único por slug. */\r\n get(slug: string): Promise<Product>;\r\n };\r\n /** Namespace entitlements (v1.2: cache LRU 60s TTL). */\r\n readonly entitlements: {\r\n /**\r\n * Verifica se o portador da apiKey pode usar `feature` do produto `slug`.\r\n * Cacheado 60s. `{ cacheBust: true }` força ida ao servidor.\r\n */\r\n check(\r\n productSlug: string,\r\n feature: string,\r\n opts?: { cacheBust?: boolean },\r\n ): Promise<boolean>;\r\n /** Variante que retorna o objeto completo com `reason`. */\r\n checkDetailed(\r\n productSlug: string,\r\n feature: string,\r\n opts?: { cacheBust?: boolean },\r\n ): Promise<EntitlementCheck>;\r\n };\r\n /** Namespace telemetria (v1.2: track fire-and-forget + flush). */\r\n readonly telemetry: {\r\n /** Persiste um evento single-shot. await retorna { ok, eventId }. */\r\n event(input: TelemetryEventInput): Promise<TelemetryEventAck>;\r\n /** Fire-and-forget: enqueue + flush 500ms debounce. Sem retorno. */\r\n track(input: TelemetryEventInput): void;\r\n /** Força flush da queue do track() (chamar antes de unload). */\r\n flush(): Promise<void>;\r\n /**\r\n * Registra um log estruturado per-product (Sprint 6).\r\n *\r\n * - Em `NEETRU_ENV=dev`: apenas console.{level} (sem network).\r\n * - Em `workspace`/`prod`: POST `/api/sdk/v1/telemetry/log` com Bearer + correlationId.\r\n */\r\n log(input: TelemetryLogInput): Promise<TelemetryLogAck>;\r\n };\r\n /** Namespace usage (v0.2 — track + quota; v0.3 — report + check). */\r\n readonly usage: UsageNamespace;\r\n /** Namespace support (v0.2 — tickets). */\r\n readonly support: SupportNamespace;\r\n /**\r\n * Namespace db (v2.0 — Mundo Documentos offline-first + Mundo SQL).\r\n *\r\n * Breaking change v2.0: `client.db` agora é `NeetruDb` em vez de `DbNamespace`.\r\n * - `db.collection(name)` → `DbCollectionRef` (offline-first, com `onSnapshot`,\r\n * `batch`, `doc(id)`, `onDoc`; `list()` retorna `DbListResult` com cursor).\r\n * - `db.sql(schema)` → `Promise<NeetruSqlClient>` (Mundo SQL).\r\n * - `db.syncState` / `db.flush()` / `db.clearCache()` (camada offline).\r\n *\r\n * O antigo `DbNamespace` (list retornava `T[]`) foi removido em v2.0.\r\n */\r\n readonly db: import('./db/client-db').NeetruDb;\r\n /** Namespace checkout (v1.1 — start/get/cancel intent + auto-redirect). */\r\n readonly checkout: import('./checkout').CheckoutNamespace;\r\n /** Namespace webhooks (v1.2 — register/list/unregister/test). */\r\n readonly webhooks: import('./webhooks').WebhooksNamespace;\r\n /** Namespace notifications (v1.2 — send/list/markRead/dismiss). */\r\n readonly notifications: import('./notifications').NotificationsNamespace;\r\n}\r\n\r\n// ─── v0.2 — Auth namespace ──────────────────────────────────────────────────\r\n\r\n/**\r\n * User retornado pelo OIDC ID token. Schema neutro — não vaza Firebase\r\n * decoded token shape. Subset estável do RFC 7519 + custom claims Neetru.\r\n */\r\nexport interface NeetruUser {\r\n /** Subject — uid estável. */\r\n uid: string;\r\n email: string;\r\n emailVerified?: boolean;\r\n displayName?: string;\r\n photoURL?: string;\r\n /** Custom claim Neetru — true quando staff. */\r\n isStaff?: boolean;\r\n /** Custom claim Neetru — true quando customer enrolled. */\r\n isCustomer?: boolean;\r\n /** Tenant assigned (multi-tenant deployments). */\r\n tenantId?: string;\r\n /** Outros claims OIDC (aud, iss, iat, exp). */\r\n [extra: string]: unknown;\r\n}\r\n\r\nexport interface SignInOptions {\r\n /** OIDC redirect_uri override. Default = window.location origin. */\r\n redirectUri?: string;\r\n /** OIDC scope. Default `openid profile email`. */\r\n scope?: string;\r\n /** Onde mandar após login completo. Default = window.location.href. */\r\n postLoginRedirect?: string;\r\n}\r\n\r\nexport type AuthStateListener = (user: NeetruUser | null) => void;\r\n\r\n/**\r\n * 3.1.3 — Resultado de `auth.handleRedirectCallback()`: o material que o **backend\r\n * do produto** (confidential client) usa pra trocar o code por tokens no\r\n * endpoint `/api/v1/oauth/token` (POST x-www-form-urlencoded, `grant_type=\r\n * authorization_code`, autenticação `Basic base64(clientId:clientSecret)`).\r\n *\r\n * O SDK nunca faz essa troca no browser (exigiria o `client_secret`). Ele só\r\n * gera/valida o PKCE + state e entrega estes campos pro lado servidor.\r\n */\r\nexport interface RedirectCallbackResult {\r\n /** `authorization_code` emitido pelo IdP — single-use, TTL curto. */\r\n code: string;\r\n /** PKCE `code_verifier` (RFC 7636) — enviar junto do code no `/token`. */\r\n codeVerifier: string;\r\n /**\r\n * `redirect_uri` exato usado no `/authorize`. O `/token` exige reenvio\r\n * idêntico (exact match) — passe este valor sem alterar.\r\n */\r\n redirectUri: string;\r\n /**\r\n * `nonce` enviado no `/authorize`. O backend deve validar que o claim\r\n * `nonce` do `id_token` retornado bate com este valor (anti-replay OIDC).\r\n */\r\n nonce: string;\r\n /** `state` validado (CSRF). Exposto pra logging/correlação. */\r\n state: string;\r\n /**\r\n * Destino pós-login que o app passou em `signIn({ postLoginRedirect })`.\r\n * `undefined` se não informado.\r\n */\r\n postLoginRedirect?: string;\r\n}\r\n\r\nexport interface AuthNamespace {\r\n /**\r\n * Inicia fluxo de login OIDC (Authorization Code + PKCE). Em dev\r\n * (`NEETRU_ENV=dev`) retorna mock user direto sem redirect. Em browser\r\n * gera `state` (CSRF), `nonce` e o par PKCE `code_verifier`/`code_challenge`\r\n * (S256), persiste a transação em `sessionStorage` e redireciona pro\r\n * `/authorize`. Complete o fluxo no retorno com `handleRedirectCallback()`.\r\n */\r\n signIn(options?: SignInOptions): Promise<NeetruUser | void>;\r\n /**\r\n * 3.1.3 — Processa o retorno do IdP após `signIn`. Lê `code` + `state` da URL\r\n * (default `location.href`; passe `currentUrl` pra override), valida o\r\n * `state` contra a transação salva em `signIn` (CSRF), consome a transação\r\n * (single-use), limpa os params da URL e devolve o material pro backend\r\n * trocar por tokens. Retorna `null` se a URL não é um callback (sem `code`).\r\n *\r\n * @throws {NeetruError} `oidc_state_mismatch` se o `state` não bate ou não há\r\n * transação pendente; ou um erro com `.code` = o `error` do IdP (ex:\r\n * `access_denied`) quando a URL traz `?error=`.\r\n */\r\n handleRedirectCallback(currentUrl?: string): Promise<RedirectCallbackResult | null>;\r\n /**\r\n * 3.1.3 — Retorna o `id_token` cru (string JWT) que o app armazenou em\r\n * `localStorage['neetru_id_token']`, ou `null` se ausente/expirado. Útil pra\r\n * mandar como `Authorization: Bearer` ao BFF do produto. Para os claims\r\n * decodificados use `getUser()`; para validar assinatura use `verifyToken()`.\r\n */\r\n getIdToken(): string | null;\r\n /** Limpa session local + revoga refresh token no servidor. */\r\n signOut(): Promise<void>;\r\n /** Retorna o user atual (do id_token cached) ou `null` se não logado. */\r\n getUser(): NeetruUser | null;\r\n /**\r\n * Subscreve a mudanças de estado de auth. Listener é invocado imediatamente\r\n * com user atual. Retorna função de unsubscribe.\r\n */\r\n onAuthStateChanged(listener: AuthStateListener): () => void;\r\n /**\r\n * Valida um id_token JWT emitido por `auth.neetru.com` server-side.\r\n *\r\n * Usa JWKS local cacheado (1h TTL, configurável via `jwksCacheTtlMs`).\r\n * Ideal para Next.js route handlers, middleware e qualquer ambiente Node/Edge\r\n * server-side onde verificação rápida sem round-trip é necessária.\r\n *\r\n * @param token - JWT id_token obtido do cookie ou header Authorization.\r\n * @param options - Opções opcionais de verificação.\r\n * @returns `NeetruUser` com claims validados.\r\n *\r\n * @throws {NeetruError} com `.code`:\r\n * - `token_expired` — token expirado (`exp` no passado)\r\n * - `token_invalid_signature` — assinatura não verificada pela JWKS\r\n * - `token_invalid_audience` — `aud` não bate com o `clientId` configurado\r\n * - `token_invalid_issuer` — `iss` não é `https://auth.neetru.com`\r\n *\r\n * @example\r\n * ```ts\r\n * // Next.js route handler\r\n * import { createNeetruClient } from '@neetru/sdk';\r\n * const client = createNeetruClient({ apiKey: 'nrt_...' });\r\n *\r\n * export async function POST(req: Request) {\r\n * const token = req.cookies.get('neetru-session')?.value;\r\n * try {\r\n * const user = await client.auth.verifyToken(token);\r\n * // user.uid, user.email, user.isStaff etc disponíveis\r\n * } catch (err) {\r\n * return new Response('Unauthorized', { status: 401 });\r\n * }\r\n * }\r\n * ```\r\n */\r\n verifyToken(token: string, options?: VerifyTokenOptions): Promise<NeetruUser>;\r\n}\r\n\r\n/** Opções para `auth.verifyToken()`. */\r\nexport interface VerifyTokenOptions {\r\n /**\r\n * TTL do cache de JWKS em milissegundos. Default: 3600000 (1h).\r\n * Valores menores aumentam latência (mais fetches); maiores aumentam\r\n * o tempo de janela após rotação de chaves.\r\n */\r\n jwksCacheTtlMs?: number;\r\n /**\r\n * Audience (`aud`) esperada no token. Se ausente, o SDK tenta derivar do\r\n * `apiKey` configurado no client (campo `keyId`). Pelo menos uma das duas\r\n * fontes é **obrigatória** — `verifyToken` lança `invalid_config` se nenhuma\r\n * audience puder ser resolvida, pois verificar um token sem `aud` permitiria\r\n * tokens emitidos para outros clients passarem sem detecção.\r\n */\r\n audience?: string;\r\n}\r\n\r\n// ─── v0.2 — Usage namespace ─────────────────────────────────────────────────\r\n\r\n/**\r\n * 3.0 BREAKING: `UsageEventInput` mantido só como tipo para tests/legacy\r\n * imports — não é mais retorno de método. `usage.track`/`usage.getQuota`\r\n * **REMOVIDOS** em 3.0. Use `usage.report(resource, qty, options)`.\r\n */\r\nexport interface UsageEventInput {\r\n event: string;\r\n properties?: Record<string, string | number | boolean | null>;\r\n quantity?: number;\r\n}\r\n\r\n/**\r\n * 3.0 BREAKING: `UsageQuota` mantido só para compat de imports. Não é mais\r\n * retorno de método ativo. `usage.report()` devolve `{value, limit, remaining}`\r\n * inline; `usage.check()` devolve detalhes do entitlement.\r\n */\r\nexport interface UsageQuota {\r\n metric: string;\r\n used: number;\r\n limit: number;\r\n resetsAt?: string;\r\n plan?: string;\r\n}\r\n\r\n/**\r\n * 3.0 — superfície limpa: `report` (POST metered) + `check` (GET entitlement).\r\n *\r\n * Métodos removidos vs 2.x:\r\n * - `track(event, props)` — vaporware contra Core. Use `report()`.\r\n * - `getQuota(metric)` — endpoint nunca existiu. `report()` devolve quota.\r\n */\r\nexport interface UsageNamespace {\r\n /**\r\n * Reporta consumo metered. Incrementa `usage_counters` no Core atomicamente.\r\n * Idempotency-Key gerado por chamada (defesa anti-dup em retry transient).\r\n *\r\n * `productId`/`tenantId` lidos do contexto do client se ausentes nas options.\r\n */\r\n report(\r\n resource: string,\r\n qty?: number,\r\n options?: { productId?: string; tenantId?: string },\r\n ): Promise<{\r\n ok: true;\r\n counterId?: string;\r\n value?: number;\r\n limit?: number;\r\n remaining?: number;\r\n status?: string;\r\n }>;\r\n /**\r\n * Verifica entitlement de um resource/feature. GET cacheável (HTTP 60s).\r\n * Resposta inclui `allowed`, `reason`, `remaining`, `limit`, `planId`,\r\n * `planFeatures` e `behavior` ('readonly' quando limit_exceeded).\r\n */\r\n check(\r\n resource: string,\r\n options?: { productId?: string; tenantId?: string },\r\n ): Promise<{\r\n allowed: boolean;\r\n reason?: string;\r\n remaining?: number;\r\n limit?: number;\r\n planId?: string | null;\r\n planFeatures?: string[];\r\n behavior?: 'readonly' | null;\r\n }>;\r\n}\r\n\r\n// ─── v0.3 — Datastore namespace ────────────────────────────────────────────\r\n\r\n/**\r\n * Namespace `db` (v0.3) — wrapper minimalista para CRUD em coleções tenant-scoped\r\n * via Core REST. Em dev retorna fixtures in-memory por collection.\r\n *\r\n * O Core injeta automaticamente o tenantId no path do Firestore:\r\n * `tenant_{tid}_{name}/{docId}`.\r\n */\r\n/** Filtro `where` simples — alinhado com endpoint REST `field:op:value`. */\r\nexport interface DbWhereFilter {\r\n field: string;\r\n op: '==' | '!=' | '<' | '<=' | '>' | '>=' | 'in';\r\n value: string | number | boolean | null | Array<string | number | boolean>;\r\n}\r\n\r\nexport interface DbListOptions {\r\n limit?: number;\r\n /** Lista de filtros — máximo 5 (alinhado ao backend). */\r\n where?: DbWhereFilter[];\r\n}\r\n\r\nexport interface DbCollectionRef {\r\n /** Lista documentos com filtros opcionais. */\r\n list<T = Record<string, unknown>>(opts?: DbListOptions): Promise<T[]>;\r\n /** Lê um documento por id. Retorna `null` se não existe. */\r\n get<T = Record<string, unknown>>(id: string): Promise<T | null>;\r\n /** Cria/upsert um documento com id explícito. */\r\n set(id: string, data: Record<string, unknown>): Promise<{ ok: true }>;\r\n /**\r\n * v0.3.1 — Adiciona doc com id auto-gerado pelo backend. Retorna `{id}` do\r\n * doc criado. Diferente de `set(id, data)` que requer caller fornecer id.\r\n */\r\n add(data: Record<string, unknown>): Promise<{ ok: true; id: string }>;\r\n /** Atualiza doc com merge — só campos passados em `data`. */\r\n update(id: string, data: Record<string, unknown>): Promise<{ ok: true }>;\r\n /** Deleta um documento. */\r\n remove(id: string): Promise<{ ok: true }>;\r\n}\r\n\r\nexport interface DbNamespace {\r\n collection(name: string): DbCollectionRef;\r\n}\r\n\r\n// ─── v0.2 — Support namespace ───────────────────────────────────────────────\r\n\r\nexport type SupportSeverity = 'low' | 'normal' | 'high' | 'urgent';\r\nexport type SupportStatus = 'open' | 'pending' | 'resolved' | 'closed';\r\n\r\nexport interface SupportTicket {\r\n id: string;\r\n subject: string;\r\n message: string;\r\n severity: SupportSeverity;\r\n status: SupportStatus;\r\n createdAt: string;\r\n updatedAt?: string;\r\n /** Slug do produto referenciado. */\r\n productSlug?: string;\r\n}\r\n\r\nexport interface CreateTicketInput {\r\n subject: string;\r\n message: string;\r\n severity?: SupportSeverity;\r\n productSlug?: string;\r\n /**\r\n * **L-05 fix (Opus review 2026-05-27):** metadata opcional (Core já aceita\r\n * via `metadata: z.record(...)` no Zod). Útil pra anexar contexto como\r\n * `{ orderId, userAgent, route, sessionId }` sem inflar subject/message.\r\n *\r\n * Chaves limitadas a 64 chars; valores primitive (string/number/boolean/null).\r\n */\r\n metadata?: Record<string, string | number | boolean | null>;\r\n}\r\n\r\nexport interface SupportNamespace {\r\n /**\r\n * Cria um novo ticket. **3.0**: POST `/api/sdk/v1/support/tickets`\r\n * (canonical, requer `productId` no body — default `config.productId`).\r\n * Mock em dev.\r\n */\r\n createTicket(input: CreateTicketInput): Promise<SupportTicket>;\r\n /**\r\n * Lista meus tickets abertos. **3.0**: GET `/api/sdk/v1/support/tickets?productId=...`\r\n * (canonical). `options.productSlug` override do `config.productId` default.\r\n */\r\n listMyTickets(options?: { productSlug?: string }): Promise<SupportTicket[]>;\r\n}\r\n\r\n// ─── v0.2 — Env detection ───────────────────────────────────────────────────\r\n\r\n/**\r\n * Modo do SDK. `dev` ativa mocks automáticos (úteis pra testes e\r\n * desenvolvimento sem precisar de backend rodando).\r\n */\r\nexport type NeetruEnv = 'dev' | 'workspace' | 'prod';\r\n\r\n/**\r\n * Configuração resolvida (defaults aplicados, fetch garantido).\r\n */\r\nexport interface ResolvedConfig {\r\n readonly apiKey?: string;\r\n /** 3.1.3 — client_id OIDC confidencial do produto (vide NeetruClientConfig). */\r\n readonly oidcClientId?: string;\r\n readonly baseUrl: string;\r\n readonly fetch: typeof globalThis.fetch;\r\n /** Resolved env — `dev` | `workspace` | `prod`. Default `prod`. */\r\n readonly env: NeetruEnv;\r\n /** Default productId (v0.3). */\r\n readonly productId?: string;\r\n /** Default tenantId (v0.3). */\r\n readonly tenantId?: string;\r\n}\r\n\r\n/** Opções pra `catalog.list()`. */\r\nexport interface CatalogListOptions {\r\n /** Inclui rascunhos (apenas com Bearer staff). Default false. */\r\n includeDrafts?: boolean;\r\n}\r\n","/**\r\n * Catálogo público de produtos SaaS Neetru.\r\n *\r\n * Endpoints consumidos (v1.2+):\r\n * - `GET /api/sdk/v1/catalog` — listagem pública (sem auth)\r\n * - `GET /api/sdk/v1/catalog/{slug}` — produto único (sem auth)\r\n *\r\n * v1.1 e anteriores usavam `/api/v1/cli/catalog` (staff CLI), o que forçava\r\n * SDK consumers a manter Bearer staff-only. v1.2 separa: SDK consome o\r\n * endpoint público (`published === true`), staff continua usando CLI quando\r\n * precisa de rascunho.\r\n *\r\n * Read-only. Publicação de produto continua via CLI `neetru publish`.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type {\r\n CatalogListOptions,\r\n CatalogListResponse,\r\n Product,\r\n ResolvedConfig,\r\n} from './types';\r\n\r\ninterface RawCatalogListResponse {\r\n ok?: boolean;\r\n count?: number;\r\n products?: unknown[];\r\n fetchedAt?: string;\r\n}\r\n\r\ninterface RawCatalogGetResponse {\r\n ok?: boolean;\r\n product?: unknown;\r\n}\r\n\r\nfunction toProduct(raw: unknown): Product {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Catalog response item is not an object');\r\n }\r\n const r = raw as Record<string, unknown>;\r\n if (typeof r.slug !== 'string' || !r.slug) {\r\n throw new NeetruError('invalid_response', 'Catalog product missing slug');\r\n }\r\n if (typeof r.name !== 'string' || !r.name) {\r\n throw new NeetruError('invalid_response', 'Catalog product missing name');\r\n }\r\n const product: Product = {\r\n slug: r.slug,\r\n name: r.name,\r\n };\r\n if (typeof r.tagline === 'string') product.tagline = r.tagline;\r\n if (typeof r.description === 'string') product.description = r.description;\r\n if (r.status === 'live' || r.status === 'soon' || r.status === 'beta') {\r\n product.status = r.status;\r\n }\r\n if (typeof r.iconKey === 'string') product.iconKey = r.iconKey;\r\n if (typeof r.ctaHref === 'string') product.ctaHref = r.ctaHref;\r\n if (typeof r.ctaLabel === 'string') product.ctaLabel = r.ctaLabel;\r\n // plans é placeholder v0.2 — preservar se backend mandar\r\n if (Array.isArray(r.plans)) {\r\n product.plans = r.plans.filter(\r\n (p): p is { id: string; name: string } =>\r\n typeof p === 'object' &&\r\n p !== null &&\r\n typeof (p as Record<string, unknown>).id === 'string' &&\r\n typeof (p as Record<string, unknown>).name === 'string',\r\n ) as Product['plans'];\r\n }\r\n return product;\r\n}\r\n\r\nexport function createCatalogNamespace(config: ResolvedConfig) {\r\n return {\r\n /**\r\n * Lista produtos publicados. Por default só `published=true`; staff\r\n * pode passar `includeDrafts: true` (requer Bearer com role admin/operator).\r\n */\r\n async list(_opts: CatalogListOptions = {}): Promise<CatalogListResponse> {\r\n // SDK só lê produtos publicados. `includeDrafts` legado é ignorado:\r\n // rascunhos só via CLI staff (`/api/v1/cli/catalog?drafts=true`).\r\n const raw = await httpRequest<RawCatalogListResponse>(config, {\r\n method: 'GET',\r\n path: '/api/sdk/v1/catalog',\r\n });\r\n\r\n if (!raw || !Array.isArray(raw.products)) {\r\n throw new NeetruError(\r\n 'invalid_response',\r\n 'Catalog list response missing products array',\r\n );\r\n }\r\n\r\n return {\r\n products: raw.products.map(toProduct),\r\n fetchedAt: typeof raw.fetchedAt === 'string'\r\n ? raw.fetchedAt\r\n : new Date().toISOString(),\r\n };\r\n },\r\n\r\n /**\r\n * Busca produto único por slug.\r\n *\r\n * @throws {NeetruError} `not_found` se slug inexistente ou não publicado.\r\n */\r\n async get(slug: string): Promise<Product> {\r\n if (!slug || typeof slug !== 'string') {\r\n throw new NeetruError('validation_failed', 'slug is required');\r\n }\r\n const raw = await httpRequest<RawCatalogGetResponse>(config, {\r\n method: 'GET',\r\n path: `/api/sdk/v1/catalog/${encodeURIComponent(slug)}`,\r\n });\r\n\r\n if (!raw || !raw.product) {\r\n throw new NeetruError(\r\n 'invalid_response',\r\n 'Catalog get response missing product',\r\n );\r\n }\r\n return toProduct(raw.product);\r\n },\r\n };\r\n}\r\n","/**\r\n * Entitlements — verifica se o portador da apiKey pode usar feature X\r\n * do produto Y.\r\n *\r\n * **3.0**: endpoint canonical é `GET /api/sdk/v1/entitlements?productId&tenantId&feature`.\r\n * Path legacy `/api/v1/sdk/entitlements/check?slug=X&feature=Y` ainda\r\n * funciona no Core (compat 2.x), mas SDK 3.0 padroniza pra canonical.\r\n *\r\n * **Atenção**: `client.entitlements.check(productSlug, feature)` é o\r\n * **legacy boolean API** (sem tenant). Continua funcional contra\r\n * `/api/v1/sdk/entitlements/check` (que segue ativo). Para o check completo\r\n * com `behavior`/`remaining`/`limit`, use `client.usage.check(resource, opts)`\r\n * que aponta para o canonical `/api/sdk/v1/entitlements`.\r\n *\r\n * v1.2 introduz cache LRU em memória (default 60s TTL, 100 entries). Cada\r\n * (productSlug, feature) pareando o `apiKey` é cacheado. Caller pode invalidar\r\n * via `__resetCache()` (test helper) ou via `cacheBust: true` na chamada.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type { EntitlementCheck, ResolvedConfig } from './types';\r\n\r\ninterface RawEntitlementCheck {\r\n allowed?: boolean;\r\n productSlug?: string;\r\n feature?: string;\r\n reason?: string;\r\n}\r\n\r\nfunction toEntitlementCheck(raw: unknown): EntitlementCheck {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Entitlement response is not an object');\r\n }\r\n const r = raw as RawEntitlementCheck;\r\n if (typeof r.allowed !== 'boolean') {\r\n throw new NeetruError('invalid_response', 'Entitlement response missing `allowed` boolean');\r\n }\r\n return {\r\n allowed: r.allowed,\r\n productSlug: typeof r.productSlug === 'string' ? r.productSlug : '',\r\n feature: typeof r.feature === 'string' ? r.feature : '',\r\n reason: typeof r.reason === 'string' ? r.reason : undefined,\r\n };\r\n}\r\n\r\n/** TTL default — 60s. Pareando com tempo de propagação típico de mudança de plano. */\r\nconst CACHE_TTL_MS = 60_000;\r\n/** Máx entries por instância de namespace — LRU. */\r\nconst CACHE_MAX = 100;\r\n\r\ninterface CacheEntry {\r\n value: EntitlementCheck;\r\n expiresAt: number;\r\n}\r\n\r\nexport interface EntitlementsCheckOptions {\r\n /** Se true, ignora cache local e força ida ao servidor. Default false. */\r\n cacheBust?: boolean;\r\n}\r\n\r\nexport function createEntitlementsNamespace(config: ResolvedConfig) {\r\n // Map preserva ordem de inserção — readequa LRU manualmente em hit.\r\n const cache = new Map<string, CacheEntry>();\r\n\r\n function cacheKey(productSlug: string, feature: string): string {\r\n return `${productSlug}::${feature}`;\r\n }\r\n\r\n function readCache(key: string): EntitlementCheck | null {\r\n const entry = cache.get(key);\r\n if (!entry) return null;\r\n if (entry.expiresAt < Date.now()) {\r\n cache.delete(key);\r\n return null;\r\n }\r\n // LRU touch: reinsere no final.\r\n cache.delete(key);\r\n cache.set(key, entry);\r\n return entry.value;\r\n }\r\n\r\n function writeCache(key: string, value: EntitlementCheck): void {\r\n if (cache.size >= CACHE_MAX) {\r\n const oldest = cache.keys().next().value;\r\n if (oldest !== undefined) cache.delete(oldest);\r\n }\r\n cache.set(key, { value, expiresAt: Date.now() + CACHE_TTL_MS });\r\n }\r\n\r\n async function checkDetailed(\r\n productSlug: string,\r\n feature: string,\r\n opts: EntitlementsCheckOptions = {},\r\n ): Promise<EntitlementCheck> {\r\n if (!productSlug) throw new NeetruError('validation_failed', 'productSlug is required');\r\n if (!feature) throw new NeetruError('validation_failed', 'feature is required');\r\n\r\n const key = cacheKey(productSlug, feature);\r\n if (!opts.cacheBust) {\r\n const cached = readCache(key);\r\n if (cached) return cached;\r\n }\r\n\r\n const raw = await httpRequest<RawEntitlementCheck>(config, {\r\n method: 'GET',\r\n path: '/api/v1/sdk/entitlements/check',\r\n query: { slug: productSlug, feature },\r\n requireAuth: true,\r\n });\r\n const result = toEntitlementCheck(raw);\r\n writeCache(key, result);\r\n return result;\r\n }\r\n\r\n return {\r\n /**\r\n * Verifica se o caller pode usar `feature` no produto `productSlug`.\r\n * Retorno simples: `true` libera, `false` bloqueia. Cache 60s automático.\r\n *\r\n * Use `checkDetailed` se precisar do `reason` pra mensagem de upgrade.\r\n */\r\n async check(\r\n productSlug: string,\r\n feature: string,\r\n opts?: EntitlementsCheckOptions,\r\n ): Promise<boolean> {\r\n const result = await checkDetailed(productSlug, feature, opts);\r\n return result.allowed;\r\n },\r\n checkDetailed,\r\n /** Test helper: limpa o cache LRU. */\r\n __resetCache(): void {\r\n cache.clear();\r\n },\r\n };\r\n}\r\n","/**\r\n * Telemetria — emite eventos do produto cliente pro Core.\r\n *\r\n * APIs disponíveis:\r\n * - `event(input)` — chamada single-shot, await retorna { ok, eventId }.\r\n * `POST /api/sdk/v1/telemetry/event` — persiste em `usage_events/{id}`.\r\n * - `track(input)` — fire-and-forget (v1.2). Enqueue + flush 500ms debounce.\r\n * Reusa o mesmo endpoint mas não bloqueia o caller — ideal pra alta\r\n * frequência (cliques, page-views). Falhas viram warning no console.\r\n * - `flush()` — força flush imediato da queue (chamar antes de unload).\r\n * - `log(input)` — log estruturado `POST /api/sdk/v1/telemetry/log` com\r\n * Bearer + correlationId. Em `NEETRU_ENV=dev` cai pra console.{level}.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type {\r\n ResolvedConfig,\r\n TelemetryEventAck,\r\n TelemetryEventInput,\r\n TelemetryLogAck,\r\n TelemetryLogInput,\r\n TelemetryLogLevel,\r\n} from './types';\r\n\r\ninterface RawTelemetryAck {\r\n ok?: boolean;\r\n eventId?: string;\r\n}\r\n\r\ninterface RawLogAck {\r\n ok?: boolean;\r\n logId?: string;\r\n}\r\n\r\nconst VALID_LOG_LEVELS: readonly TelemetryLogLevel[] = ['debug', 'info', 'warn', 'error', 'fatal'];\r\n\r\nfunction consoleFor(level: TelemetryLogLevel): (message?: unknown, ...optional: unknown[]) => void {\r\n switch (level) {\r\n case 'debug': return console.debug.bind(console);\r\n case 'info': return console.info.bind(console);\r\n case 'warn': return console.warn.bind(console);\r\n case 'error': return console.error.bind(console);\r\n case 'fatal': return console.error.bind(console);\r\n default: return console.log.bind(console);\r\n }\r\n}\r\n\r\n/** Janela de debounce do `track()` antes de drenar a queue. */\r\nconst TRACK_FLUSH_MS = 500;\r\n/** Limite de eventos na queue antes de flush forçado (defensivo). */\r\nconst TRACK_MAX_QUEUE = 50;\r\n\r\nexport function createTelemetryNamespace(config: ResolvedConfig) {\r\n // Queue local pra track() — fire-and-forget batchado.\r\n const queue: TelemetryEventInput[] = [];\r\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\r\n // bug: flush() precisava aguardar drain já em voo p/ não resolver antes do envio\r\n let _inflightDrain: Promise<void> | null = null;\r\n\r\n async function drainQueue(): Promise<void> {\r\n if (queue.length === 0) return;\r\n // (a) Capture the current batch BEFORE the async boundary so that any\r\n // track() call arriving during the await works on a clean queue.\r\n const batch = queue.splice(0, queue.length);\r\n // NOTE: flushTimer is intentionally NOT cleared here. Clearing it before\r\n // the await would let a concurrent track() schedule a second timer, fire\r\n // it while this flush is still in-flight, and produce duplicate concurrent\r\n // drainQueue calls. We clear it only after the await (see below).\r\n const work = Promise.allSettled(\r\n batch.map(async (ev) => {\r\n try {\r\n const body: Record<string, unknown> = { name: ev.name };\r\n if (ev.properties && typeof ev.properties === 'object') {\r\n body.properties = ev.properties;\r\n }\r\n if (ev.timestamp) body.timestamp = ev.timestamp;\r\n await httpRequest<RawTelemetryAck>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/telemetry/event',\r\n body,\r\n requireAuth: true,\r\n retries: 1,\r\n });\r\n } catch (err) {\r\n if (typeof console !== 'undefined') {\r\n console.warn('[neetru-sdk] telemetry.track flush failed for event', ev.name, err);\r\n }\r\n }\r\n }),\r\n );\r\n // Registra promise em voo para que flush() possa aguardar (bug finding 4)\r\n _inflightDrain = work.then(() => { _inflightDrain = null; });\r\n // (b) Release the timer slot AFTER the await so that any track() calls\r\n // that arrived during the flush and called scheduleFlush() were\r\n // correctly suppressed (flushTimer was still set). Now that the\r\n // in-flight requests are done we reset it and, if new events were\r\n // enqueued while we were awaiting, schedule the next flush.\r\n await work;\r\n flushTimer = null;\r\n // (c) If events arrived during the flush window, schedule the next drain.\r\n if (queue.length > 0) {\r\n scheduleFlush();\r\n }\r\n }\r\n\r\n function scheduleFlush(): void {\r\n if (flushTimer) return;\r\n flushTimer = setTimeout(() => {\r\n void drainQueue();\r\n }, TRACK_FLUSH_MS);\r\n }\r\n\r\n return {\r\n /**\r\n * Persiste um evento de uso. Lança `NeetruError` em qualquer falha\r\n * (incluindo rate-limit).\r\n *\r\n * @example\r\n * ```ts\r\n * await client.telemetry.event({\r\n * name: 'dashboard_opened',\r\n * properties: { plan: 'pro', tab: 'overview' },\r\n * });\r\n * ```\r\n */\r\n async event(input: TelemetryEventInput): Promise<TelemetryEventAck> {\r\n if (!input || typeof input !== 'object') {\r\n throw new NeetruError('validation_failed', 'event input is required');\r\n }\r\n if (typeof input.name !== 'string' || input.name.length === 0) {\r\n throw new NeetruError('validation_failed', 'event.name is required');\r\n }\r\n if (input.name.length > 128) {\r\n throw new NeetruError('validation_failed', 'event.name max 128 chars');\r\n }\r\n\r\n const body: Record<string, unknown> = { name: input.name };\r\n if (input.properties && typeof input.properties === 'object') {\r\n body.properties = input.properties;\r\n }\r\n if (input.timestamp) body.timestamp = input.timestamp;\r\n\r\n const raw = await httpRequest<RawTelemetryAck>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/telemetry/event',\r\n body,\r\n requireAuth: true,\r\n });\r\n\r\n if (!raw || raw.ok !== true || typeof raw.eventId !== 'string') {\r\n throw new NeetruError('invalid_response', 'Telemetry response missing eventId');\r\n }\r\n return { ok: true, eventId: raw.eventId };\r\n },\r\n\r\n /**\r\n * Fire-and-forget: enqueue + flush 500ms debounce. Não retorna `eventId`\r\n * — falhas são logadas como warning. Ideal pra alta frequência.\r\n *\r\n * @example\r\n * ```ts\r\n * client.telemetry.track({ name: 'page_view', properties: { path: '/' } });\r\n * // segue execução; flush async em background\r\n * ```\r\n */\r\n track(input: TelemetryEventInput): void {\r\n if (!input || typeof input !== 'object') return;\r\n if (typeof input.name !== 'string' || input.name.length === 0) return;\r\n if (input.name.length > 128) return;\r\n queue.push(input);\r\n if (queue.length >= TRACK_MAX_QUEUE) {\r\n // bug: timer pendente não era cancelado → dois drainQueue() concorrentes\r\n if (flushTimer) { clearTimeout(flushTimer); flushTimer = null; }\r\n void drainQueue();\r\n } else {\r\n scheduleFlush();\r\n }\r\n },\r\n\r\n /**\r\n * Força flush imediato da queue de `track()`. Resolva antes de\r\n * page unload / SSR boundary pra não perder eventos.\r\n */\r\n async flush(): Promise<void> {\r\n if (flushTimer) {\r\n clearTimeout(flushTimer);\r\n flushTimer = null;\r\n }\r\n // bug: flush() resolvia antes do drain já em voo terminar (finding 4)\r\n if (_inflightDrain) await _inflightDrain;\r\n await drainQueue();\r\n },\r\n\r\n /**\r\n * Registra um log estruturado per-product (Sprint 6).\r\n *\r\n * - `NEETRU_ENV=dev`: console.{level}, retorna ack mock.\r\n * - workspace/prod: HTTP POST com Bearer auth + correlationId no header.\r\n *\r\n * @example\r\n * ```ts\r\n * await client.telemetry.log({\r\n * level: 'error',\r\n * message: 'Falha ao calcular total',\r\n * metadata: { orderId: 'o-123' },\r\n * });\r\n * ```\r\n */\r\n async log(input: TelemetryLogInput): Promise<TelemetryLogAck> {\r\n if (!input || typeof input !== 'object') {\r\n throw new NeetruError('validation_failed', 'log input is required');\r\n }\r\n if (!VALID_LOG_LEVELS.includes(input.level)) {\r\n throw new NeetruError('validation_failed', `level must be one of ${VALID_LOG_LEVELS.join(', ')}`);\r\n }\r\n if (typeof input.message !== 'string' || input.message.length === 0) {\r\n throw new NeetruError('validation_failed', 'message is required');\r\n }\r\n if (input.message.length > 4_000) {\r\n throw new NeetruError('validation_failed', 'message max 4000 chars');\r\n }\r\n\r\n // Dev mode: console only, no network.\r\n if (config.env === 'dev') {\r\n const fn = consoleFor(input.level);\r\n fn(`[neetru-sdk] ${input.level}: ${input.message}`, input.metadata ?? {});\r\n return { ok: true, mode: 'mock' };\r\n }\r\n\r\n const body: Record<string, unknown> = {\r\n level: input.level,\r\n message: input.message,\r\n };\r\n if (input.metadata) body.metadata = input.metadata;\r\n // C4 (auditoria 2026-06-10): o Core exige productSlug fail-closed (400 sem\r\n // ele). Quando o consumer não passa explicito, default pro config.productId\r\n // (mesmo contrato de usage.report/support). O backend NÃO infere o slug.\r\n const productSlug = input.productSlug ?? config.productId;\r\n if (productSlug) body.productSlug = productSlug;\r\n\r\n // CorrelationId: explicit input wins; senão tenta lê de globalThis (set\r\n // por instrumentação do consumer).\r\n let cid = input.correlationId;\r\n if (!cid) {\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const g = (globalThis as any).NEETRU_CORRELATION_ID;\r\n if (typeof g === 'string' && g.length > 0) cid = g;\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n\r\n const headers: Record<string, string> = {};\r\n if (cid) headers['x-correlation-id'] = cid;\r\n\r\n const raw = await httpRequest<RawLogAck>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/telemetry/log',\r\n body,\r\n requireAuth: true,\r\n headers,\r\n });\r\n\r\n if (!raw || raw.ok !== true) {\r\n throw new NeetruError('invalid_response', 'Telemetry log response missing ok');\r\n }\r\n return {\r\n ok: true,\r\n logId: typeof raw.logId === 'string' ? raw.logId : undefined,\r\n mode: 'http',\r\n };\r\n },\r\n };\r\n}\r\n","/**\n * Usage namespace — meterar consumo e verificar entitlements (3.0 — breaking).\n *\n * **Mudanças 3.0:**\n * - Paths canônicos `/api/sdk/v1/*` (eram `/sdk/v1/*` errados).\n * - `track(event, props)` **REMOVIDO** — Core não aceita esse shape; era\n * vaporware testado contra mock fetch. Use `report(resource, qty, opts)`.\n * - `getQuota(metric)` **REMOVIDO** — endpoint `/usage/quota` nunca existiu\n * no Core. `report()` já devolve `{value, limit, remaining}` em todo POST.\n * - `report()` e `check()` **agora exigem** `productId` + `tenantId`\n * (no contexto do client OU passados nas options).\n * - `report()` envia `Idempotency-Key` automaticamente (anti dup de\n * incremento em retry transient — Core dedup TTL 24h).\n *\n * Endpoints consumidos:\n * - `POST /api/sdk/v1/usage/record` — `{productId, tenantId, resource, qty}`.\n * Incrementa `usage_counters/{tenantId}_{productId}_{resource}_{yyyymm}.value`.\n * - `GET /api/sdk/v1/entitlements?productId&tenantId&feature` — read-only\n * check de plano + remaining (cache HTTP 60s).\n *\n * Comportamento por env:\n * - `dev` → MockUsage (in-memory, retornado pelo factory).\n * - `workspace`/`prod` → HTTP real.\n */\nimport { NeetruError } from './errors';\nimport { httpRequest } from './http';\nimport { assertValidSdkId } from './validators';\nimport type { ResolvedConfig, UsageNamespace } from './types';\n\nexport function createUsageNamespace(config: ResolvedConfig): UsageNamespace {\n return {\n /**\n * Reporta consumo metered de um resource. Hit no endpoint canônico\n * `POST /api/sdk/v1/usage/record`. Idempotency-Key gerado por chamada;\n * Core dedup serverside TTL 24h.\n *\n * @example\n * ```ts\n * await client.usage.report('api_call', 1);\n * // ou explicit:\n * await client.usage.report('api_call', 5, { productId: 'gestovendas', tenantId: 't-acme' });\n * ```\n */\n async report(\n resource: string,\n qty: number = 1,\n options?: { productId?: string; tenantId?: string },\n ) {\n if (!resource || typeof resource !== 'string') {\n throw new NeetruError('validation_failed', 'resource is required');\n }\n if (!Number.isFinite(qty) || qty <= 0) {\n throw new NeetruError('validation_failed', 'qty must be positive integer');\n }\n const productId = options?.productId ?? config.productId;\n const tenantId = options?.tenantId ?? config.tenantId;\n if (!productId) {\n throw new NeetruError(\n 'validation_failed',\n 'productId required (pass to options or set on createNeetruClient)',\n );\n }\n if (!tenantId) {\n throw new NeetruError(\n 'validation_failed',\n 'tenantId required (pass to options or set on createNeetruClient)',\n );\n }\n // M-03: valida formato canonical (case-insensitive Core já rejeitaria com 400).\n assertValidSdkId('productId', productId);\n assertValidSdkId('tenantId', tenantId);\n\n const raw = await httpRequest<{\n ok?: boolean;\n counterId?: string;\n value?: number;\n limit?: number;\n remaining?: number;\n status?: string;\n }>(config, {\n method: 'POST',\n path: '/api/sdk/v1/usage/record',\n body: { productId, tenantId, resource, qty: Math.floor(qty) },\n requireAuth: true,\n idempotencyKey: true,\n });\n if (!raw || raw.ok !== true) {\n throw new NeetruError('invalid_response', 'usage.report response missing ok');\n }\n return {\n ok: true as const,\n counterId: raw.counterId,\n value: raw.value,\n limit: raw.limit,\n remaining: raw.remaining,\n status: raw.status,\n };\n },\n\n /**\n * Verifica entitlement de um resource via `GET /api/sdk/v1/entitlements`.\n * Resposta inclui `allowed`, `reason` ('granted' | 'not_subscribed' |\n * 'subscription_inactive' | 'feature_not_in_plan' | 'limit_exceeded'),\n * `remaining`, `limit`, `planId`, `planFeatures`.\n */\n async check(\n resource: string,\n options?: { productId?: string; tenantId?: string },\n ) {\n if (!resource || typeof resource !== 'string') {\n throw new NeetruError('validation_failed', 'resource is required');\n }\n const productId = options?.productId ?? config.productId;\n const tenantId = options?.tenantId ?? config.tenantId;\n if (!productId || !tenantId) {\n throw new NeetruError(\n 'validation_failed',\n 'productId and tenantId required (pass to options or set on createNeetruClient)',\n );\n }\n // M-03: valida formato canonical antes do fetch.\n assertValidSdkId('productId', productId);\n assertValidSdkId('tenantId', tenantId);\n\n const raw = await httpRequest<{\n allowed?: boolean;\n reason?: string;\n remaining?: number;\n limit?: number;\n planId?: string | null;\n planFeatures?: string[];\n behavior?: 'readonly' | null;\n }>(config, {\n method: 'GET',\n path: '/api/sdk/v1/entitlements',\n query: { productId, tenantId, feature: resource },\n requireAuth: true,\n });\n if (!raw || typeof raw.allowed !== 'boolean') {\n throw new NeetruError('invalid_response', 'usage.check response missing allowed');\n }\n // Infere behavior='readonly' quando reason='limit_exceeded' e Core\n // ainda não devolve o field explicitamente (vide CORE_CHANGES_REQUIRED §4).\n const behavior =\n raw.behavior ?? (raw.reason === 'limit_exceeded' ? 'readonly' : null);\n return {\n allowed: raw.allowed,\n reason: raw.reason,\n remaining: raw.remaining,\n limit: raw.limit,\n planId: raw.planId,\n planFeatures: raw.planFeatures,\n behavior,\n };\n },\n };\n}\n","/**\n * Validators centralizados pra inputs do SDK que precisam casar com\n * regex do Core.\n *\n * **M-03 fix (Opus review 2026-05-27):** o Core rejeita productId que\n * não bate `/^[a-z0-9][a-z0-9_-]{0,62}$/` com 400 `validation_failed`.\n * O SDK não pré-validava — consumer recebia erro só em runtime de\n * produção, depois do round-trip de rede. Agora SDK throws localmente\n * antes do fetch.\n */\nimport { NeetruError } from './errors';\n\n/**\n * Regex canonical de IDs no Neetru Core (productId, tenantId, etc).\n * Espelha `SDK_ID_RE` em `neetru_core/src/lib/schemas/sdk.ts`.\n */\nexport const SDK_ID_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/;\n\n/**\n * Throws `NeetruError('validation_failed')` se `value` não bater no\n * formato canonical.\n *\n * @example\n * ```ts\n * assertValidSdkId('productId', 'gestovendas'); // ok\n * assertValidSdkId('productId', 'GestoVendas'); // throws\n * ```\n */\nexport function assertValidSdkId(field: string, value: string): void {\n if (typeof value !== 'string' || !SDK_ID_RE.test(value)) {\n throw new NeetruError(\n 'validation_failed',\n `${field} must match ${SDK_ID_RE.source} (lowercase alphanumeric, _, -; first char must be alphanumeric; max 63 chars)`,\n );\n }\n}\n","/**\n * Support namespace — criar e listar tickets via SDK (3.0).\n *\n * **Breaking 3.0**:\n * - Endpoint mudou de `/api/v1/products/{slug}/tickets` (que **NUNCA existiu\n * no Core** — vaporware testado) para `/api/sdk/v1/support/tickets`\n * (canonical SDK path).\n * - `productId` agora é obrigatório no body/query (default resolve do\n * `config.productId`; throw `validation_failed` se ambos ausentes).\n * - `createTicket()` envia `Idempotency-Key` header (anti dup-create\n * em retry transient — Core dedup TTL 24h conforme CORE_CHANGES_REQUIRED §1).\n *\n * **Pré-requisito Core**: endpoint `/api/sdk/v1/support/tickets` (POST + GET)\n * precisa existir no Core antes do SDK 3.0 publish. Vide\n * `docs/CORE_CHANGES_REQUIRED.md` §1 para contrato esperado.\n *\n * Em dev (mocks ativos via factory) tudo é in-memory.\n */\nimport { NeetruError } from './errors';\nimport { httpRequest } from './http';\nimport { assertValidSdkId } from './validators';\nimport type {\n CreateTicketInput,\n ResolvedConfig,\n SupportNamespace,\n SupportSeverity,\n SupportStatus,\n SupportTicket,\n} from './types';\n\nconst VALID_SEVERITIES: readonly SupportSeverity[] = ['low', 'normal', 'high', 'urgent'];\nconst VALID_STATUSES: readonly SupportStatus[] = ['open', 'pending', 'resolved', 'closed'];\n\ninterface RawTicket {\n id?: string;\n productId?: string;\n subject?: string;\n message?: string;\n severity?: string;\n status?: string;\n createdAt?: string;\n updatedAt?: string;\n productSlug?: string;\n}\n\nfunction toTicket(raw: unknown): SupportTicket {\n if (!raw || typeof raw !== 'object') {\n throw new NeetruError('invalid_response', 'Ticket response is not an object');\n }\n const r = raw as RawTicket;\n if (typeof r.id !== 'string') {\n throw new NeetruError('invalid_response', 'Ticket missing id');\n }\n return {\n id: r.id,\n subject: typeof r.subject === 'string' ? r.subject : '',\n message: typeof r.message === 'string' ? r.message : '',\n severity: VALID_SEVERITIES.includes(r.severity as SupportSeverity)\n ? (r.severity as SupportSeverity)\n : 'normal',\n status: VALID_STATUSES.includes(r.status as SupportStatus)\n ? (r.status as SupportStatus)\n : 'open',\n createdAt: typeof r.createdAt === 'string' ? r.createdAt : new Date().toISOString(),\n updatedAt: typeof r.updatedAt === 'string' ? r.updatedAt : undefined,\n productSlug:\n typeof r.productId === 'string'\n ? r.productId\n : typeof r.productSlug === 'string'\n ? r.productSlug\n : undefined,\n };\n}\n\nfunction resolveProductId(\n config: ResolvedConfig,\n ...candidates: Array<string | undefined>\n): string {\n for (const c of candidates) {\n if (typeof c === 'string' && c.length > 0) {\n assertValidSdkId('productSlug', c); // M-03: pré-valida client-side\n return c;\n }\n }\n if (config.productId) {\n assertValidSdkId('productId', config.productId);\n return config.productId;\n }\n throw new NeetruError(\n 'validation_failed',\n 'productId required (pass to input.productSlug or set on createNeetruClient)',\n );\n}\n\nexport function createSupportNamespace(config: ResolvedConfig): SupportNamespace {\n return {\n /**\n * Cria um ticket de suporte. Requer Bearer auth. `productSlug` no input\n * (ou `config.productId` default) vai como `productId` no body do Core.\n *\n * Endpoint canonical: `POST /api/sdk/v1/support/tickets`.\n */\n async createTicket(input: CreateTicketInput): Promise<SupportTicket> {\n if (!input || typeof input !== 'object') {\n throw new NeetruError('validation_failed', 'input is required');\n }\n if (!input.subject || typeof input.subject !== 'string') {\n throw new NeetruError('validation_failed', 'subject is required');\n }\n if (input.subject.length > 200) {\n throw new NeetruError('validation_failed', 'subject max 200 chars');\n }\n if (!input.message || typeof input.message !== 'string') {\n throw new NeetruError('validation_failed', 'message is required');\n }\n if (input.message.length > 10_000) {\n throw new NeetruError('validation_failed', 'message max 10000 chars');\n }\n if (input.severity && !VALID_SEVERITIES.includes(input.severity)) {\n throw new NeetruError(\n 'validation_failed',\n `severity must be one of ${VALID_SEVERITIES.join(', ')}`,\n );\n }\n\n const productId = resolveProductId(config, input.productSlug);\n // M-03: validação acontece dentro de resolveProductId; aqui só usa.\n\n const body: Record<string, unknown> = {\n productId,\n subject: input.subject,\n message: input.message,\n severity: input.severity ?? 'normal',\n };\n\n // L-05 fix: propaga metadata quando consumer enviar.\n if (input.metadata && typeof input.metadata === 'object') {\n body.metadata = input.metadata;\n }\n\n const raw = await httpRequest<RawTicket | { ticket?: RawTicket }>(config, {\n method: 'POST',\n path: '/api/sdk/v1/support/tickets',\n body,\n requireAuth: true,\n idempotencyKey: true,\n });\n\n // Backend pode envelopar como { ticket: {...} } ou retornar direto.\n const candidate =\n raw && typeof raw === 'object' && 'ticket' in raw\n ? (raw as { ticket?: RawTicket }).ticket\n : raw;\n return toTicket(candidate);\n },\n\n /**\n * Lista tickets do customer no produto atual. `productSlug` no contexto.\n *\n * Endpoint canonical: `GET /api/sdk/v1/support/tickets?productId=...`.\n */\n async listMyTickets(options?: { productSlug?: string }): Promise<SupportTicket[]> {\n const productId = resolveProductId(config, options?.productSlug);\n const raw = await httpRequest<{ tickets?: unknown[] } | unknown[]>(config, {\n method: 'GET',\n path: '/api/sdk/v1/support/tickets',\n query: { productId },\n requireAuth: true,\n });\n const list = Array.isArray(raw)\n ? raw\n : raw && typeof raw === 'object' && 'tickets' in raw\n ? ((raw as { tickets?: unknown[] }).tickets ?? [])\n : [];\n return list.map(toTicket);\n },\n };\n}\n","/**\r\n * client-db.ts — Factory do namespace `client.db` (M2 capstone).\r\n *\r\n * Liga os building blocks construídos em M2 em uma superfície unificada\r\n * conforme 02-sdk.md §3.1:\r\n *\r\n * client.db.collection(name) → DbCollectionRef (offline-first, engine-aware)\r\n * client.db.sql(schema) → Promise<NeetruSqlClient>\r\n * client.db.syncState → NeetruSyncState\r\n * client.db.onSyncStateChanged(cb) / flush() / clearCache() / getConflicts()\r\n *\r\n * ## Transport detection\r\n *\r\n * O SDK lê o transport SDK↔Core via:\r\n * 1. Opção explícita `NeetruDbOptions.transport` (injetada pelo product scaffold\r\n * gerado por `neetru db init`, ou pelo `NeetruDbConfig` passado pra\r\n * `createNeetruClient`).\r\n * 2. Fallback legado: `NeetruDbOptions.engine` (depreciado em v2.3, remove em v3.0) —\r\n * emite `console.warn` e usa o valor como `transport`.\r\n * 3. Default: `'rest'` — transporte REST simples (sem realtime nativo;\r\n * compatível com todos os storage engines no MVP, idêntico ao comportamento v1.x).\r\n *\r\n * Transports reconhecidos:\r\n * - `'firestore'` → SyncEngine com FirestoreRealtimeSyncTransport\r\n * - `'nosql-vm'` → SyncEngine com NeetruRealtimeClient como fonte realtime\r\n * - `'rest'` → SyncEngine com FakeRestSyncTransport (REST puro, no-op realtime)\r\n * (default — funciona para cloud-sql-*, vm-postgres-*, etc.)\r\n *\r\n * ## Wiring SQL\r\n *\r\n * `client.db.sql(schema)` delega pra `createSqlClientFromConfig` (src/db/sql/).\r\n * Em dev (`NEETRU_ENV=dev`), retorna um `MockSqlClient` que não abre socket.\r\n *\r\n * ## Backward compatibility com v1.x DbNamespace\r\n *\r\n * O antigo `DbNamespace` (src/db.ts) expunha apenas `collection(name)` retornando\r\n * uma versão REST simples sem offline, sem realtime, sem cursor, sem batch.\r\n * A `NeetruDb` v2.0 É uma breaking change deliberada (major bump):\r\n * - `list()` agora retorna `DbListResult<T>` (com `fromCache`, `stale`, etc.)\r\n * em vez de `T[]`.\r\n * - `db_unavailable` semântica mudou: não significa mais \"sem rede\"\r\n * (offline é transparente), só lifecycle do banco.\r\n * - `batch()`, `onDoc()`, `onSnapshot()`, `doc()`, `sql()` são novos.\r\n *\r\n * Veja CHANGELOG.md §2.0.0 para a lista completa de breaking changes.\r\n *\r\n * @module\r\n */\r\n\r\nimport type { ResolvedConfig } from '../types';\r\nimport { NeetruDbError } from '../db-errors';\r\nimport {\r\n createOfflineDocumentsNamespace,\r\n type NeetruDbDocuments,\r\n type RealtimeTransport,\r\n} from './collection-ref';\r\n// bug_0f836014: createSqlClientFromConfig importa pg + drizzle-orm/node-postgres\r\n// que vazam pro bundle browser (Next.js webpack 'Module not found: fs'). Usamos\r\n// dynamic import dentro do método sql() — server-only contract. Browser bundle\r\n// faz split-chunk e nunca puxa pg em runtime.\r\nimport type { createSqlClientFromConfig as CreateSqlClientFromConfigFn } from './sql/sql-client';\r\nimport type { NeetruSqlClient, SqlOptions } from './sql/types';\r\nimport type { SyncState, ConflictRecord, Unsubscribe, Mutation } from './offline/types';\r\nimport type { PushMutationsResult, PullChangesResult, FullResyncResult } from './offline/sync-engine';\r\nimport { NeetruRealtimeClient } from './realtime/realtime-client';\r\nimport type { TicketProvider } from './realtime/types';\r\n\r\n// ─── Re-exports públicos do módulo db ────────────────────────────────────────\r\n\r\nexport type {\r\n DbCollectionRef,\r\n DbDocRef,\r\n DbQuery,\r\n DbWhereFilter,\r\n DbDoc,\r\n DbListResult,\r\n DbGetResult,\r\n DbBatchOp,\r\n DbChangeType,\r\n NeetruDbDocuments,\r\n RealtimeTransport,\r\n CreateOfflineDocumentsOptions,\r\n WithFieldSentinels,\r\n FieldSentinel,\r\n ServerTimestampSentinel,\r\n IncrementSentinel,\r\n} from './collection-ref';\r\n\r\n// ── Sentinels de escrita server-side (bug_05aedb8b) ──────────────────────────\r\n// `serverTimestamp()` e `increment()` permitem que o produto escreva timestamps\r\n// e contadores resolvidos pelo SERVIDOR — não pelo relógio (spoofável) do cliente.\r\nexport {\r\n serverTimestamp,\r\n increment,\r\n isFieldSentinel,\r\n isServerTimestampSentinel,\r\n isIncrementSentinel,\r\n NEETRU_SENTINEL_KEY,\r\n} from './field-value';\r\n\r\nexport type { NeetruSqlClient, DbSqlLease, SqlOptions } from './sql/types';\r\nexport { NeetruDbError } from '../db-errors';\r\nexport type { NeetruDbErrorCode } from '../db-errors';\r\nexport type { SyncState, ConflictRecord } from './offline/types';\r\n\r\n// ─── Tipos públicos de configuração de DB ────────────────────────────────────\r\n\r\n/**\r\n * Transporte SDK↔Core do banco lógico — determina o protocolo de realtime.\r\n *\r\n * - `'firestore'` — Firestore Web SDK como transporte (memoryLocalCache).\r\n * - `'nosql-vm'` — WebSocket via gateway `neetru-realtime`.\r\n * - `'rest'` — REST puro (default MVP; sem realtime nativo).\r\n *\r\n * Nota: \"transport\" descreve o protocolo SDK↔Core (REST / Firestore / WebSocket).\r\n * Não confundir com \"engine\" de armazenamento do admin database (firestore-instance,\r\n * cloud-sql-postgres, vm-postgres-single…), que é uma configuração do Core —\r\n * um storage engine pode ser acessado por vários SDK transports.\r\n *\r\n * O produto NUNCA vê a diferença de transporte — o comportamento offline\r\n * é idêntico nos dois transportes de Documentos (02-sdk.md §3.7).\r\n */\r\nexport type NeetruDbTransport = 'firestore' | 'nosql-vm' | 'rest';\r\n\r\n/**\r\n * @deprecated Use `NeetruDbTransport`. Este alias será removido em v3.0.\r\n *\r\n * O nome \"engine\" colide com o conceito de storage engine do admin database\r\n * (firestore-instance, cloud-sql-postgres, vm-postgres-single…).\r\n * No contexto do SDK, o campo configura o TRANSPORTE (REST/Firestore/WebSocket),\r\n * não o engine de armazenamento. Use `transport` em vez de `engine`.\r\n */\r\nexport type NeetruDbEngine = NeetruDbTransport;\r\n\r\n/**\r\n * Opções de configuração do banco lógico.\r\n *\r\n * Normalmente geradas pelo scaffold `neetru db init` em `db/client.ts`.\r\n * Em testes, injetar diretamente.\r\n */\r\nexport interface NeetruDbOptions {\r\n /**\r\n * ID opaco do banco lógico — emitido pelo Core em `POST /api/sdk/v1/db`.\r\n * Necessário para o lease SQL e para scoping das coleções.\r\n */\r\n dbId?: string;\r\n\r\n /**\r\n * Transporte SDK↔Core — determina o protocolo de realtime.\r\n * Default: `'rest'` (MVP — funciona para todos os storage engines SQL e Documentos).\r\n *\r\n * Valores:\r\n * - `'rest'` — REST puro (sem realtime nativo; compatível com todos os storage engines).\r\n * - `'firestore'` — Firestore Web SDK como transporte (memoryLocalCache).\r\n * - `'nosql-vm'` — WebSocket via gateway `neetru-realtime`.\r\n *\r\n * Não confundir com o storage engine do admin database (firestore-instance,\r\n * cloud-sql-postgres, vm-postgres-single…). Um storage engine pode ser acessado\r\n * por vários transports SDK (ex.: cloud-sql-postgres funciona com transport='rest').\r\n */\r\n transport?: NeetruDbTransport;\r\n\r\n /**\r\n * @deprecated Use `transport` em vez de `engine`. Será removido em v3.0.\r\n *\r\n * O nome \"engine\" colide com o conceito de storage engine do admin database\r\n * (firestore-instance, cloud-sql-postgres, vm-postgres-single…).\r\n * Se `transport` e `engine` forem passados simultaneamente, `transport` prevalece.\r\n */\r\n engine?: NeetruDbEngine;\r\n\r\n /**\r\n * Opções do transporte Firestore (somente quando `transport === 'firestore'`).\r\n * O `firestore` handle (inicializado com `memoryLocalCache`) é injetado aqui.\r\n *\r\n * Injeção explícita — o SDK não importa `firebase/firestore` diretamente\r\n * para não poluir o bundle de quem não usa este transporte.\r\n */\r\n firestoreTransport?: RealtimeTransport;\r\n\r\n /**\r\n * Opções do transporte WebSocket (somente quando `transport === 'nosql-vm'`).\r\n * URL do gateway `neetru-realtime`.\r\n */\r\n realtimeGatewayUrl?: string;\r\n\r\n /**\r\n * Coleções declaradas pelo produto — necessário para pullChanges/fullResync\r\n * com os transportes Firestore e nosql-vm.\r\n *\r\n * Default: `[]` (o SyncEngine sincroniza coleções conforme são acessadas).\r\n */\r\n collections?: string[];\r\n\r\n /**\r\n * Nome do banco IndexedDB. Convenção: `neetru-db__{productSlug}__{dbId}__{env}`.\r\n * Gerado automaticamente se ausente.\r\n */\r\n dbName?: string;\r\n\r\n /**\r\n * `true` = sem contenção multi-aba (sempre líder).\r\n * Padrão em SSR/testes; em produção usa Web Locks.\r\n */\r\n singleTab?: boolean;\r\n\r\n /**\r\n * Transporte de sync customizado (injetado em testes).\r\n * Se presente, sobrepõe a detecção por `transport`.\r\n */\r\n _transport?: RealtimeTransport;\r\n\r\n /**\r\n * Factory de WebSocket injetável (somente quando `transport === 'nosql-vm'`).\r\n * Default: `(url) => new WebSocket(url)`.\r\n * Injetar em testes para evitar rede real.\r\n */\r\n _wsFactory?: import('./realtime/types').WebSocketFactory;\r\n}\r\n\r\n// ─── NeetruDb — interface pública completa (02-sdk.md §3.1) ─────────────────\r\n\r\n/**\r\n * Superfície pública do namespace `client.db` — alinhada com 02-sdk.md §3.1.\r\n *\r\n * ```ts\r\n * const client = createNeetruClient({ ... });\r\n *\r\n * // Mundo Documentos (offline-first):\r\n * const orders = client.db.collection<Order>('orders');\r\n * await orders.add({ ... });\r\n * orders.onSnapshot(query, snap => renderOrders(snap.docs));\r\n *\r\n * // Mundo SQL (lease + pg.Pool + Drizzle):\r\n * const sql = await client.db.sql(schema);\r\n * const rows = await sql.orm.select().from(schema.orders);\r\n *\r\n * // Camada offline:\r\n * const state = client.db.syncState;\r\n * client.db.onSyncStateChanged(s => console.log(s.pendingWrites));\r\n * await client.db.flush(); // força sync\r\n * ```\r\n */\r\nexport interface NeetruDb {\r\n // ── Mundo Documentos ──────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna uma `DbCollectionRef` para a coleção `name`.\r\n *\r\n * Offline-first: reads vêm do cache local; writes são aplicados\r\n * otimisticamente e enfileirados para sync. Engine-aware: o transporte\r\n * realtime é selecionado automaticamente pelo `engine` configurado.\r\n */\r\n collection<T = Record<string, unknown>>(\r\n name: string,\r\n ): import('./collection-ref').DbCollectionRef<T>;\r\n\r\n // ── Mundo SQL ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Abre o handle SQL: busca o lease no Core, abre o `pg.Pool`, cria o\r\n * handle Drizzle tipado pelo `schema`. Operação async, 1x no startup.\r\n *\r\n * Em `NEETRU_ENV=dev`, retorna um `MockSqlClient` que não abre socket.\r\n *\r\n * @param schema — Schema Drizzle do produto (`pgTable(...)` em `db/schema.ts`).\r\n * @param options — Opções opcionais (contrato C-H).\r\n * `options.database` desambigua quando o produto tem N>1 bancos SQL.\r\n * Quando omitido, o Core resolve o banco padrão/homônimo do produto.\r\n *\r\n * @example\r\n * ```ts\r\n * import * as schema from './db/schema';\r\n * // banco padrão (único ou homônimo):\r\n * export const db = await client.db.sql(schema);\r\n * // banco específico entre N bancos SQL:\r\n * export const analytics = await client.db.sql(schema, { database: 'analytics' });\r\n * ```\r\n */\r\n sql<TSchema extends Record<string, unknown>>(\r\n schema: TSchema,\r\n options?: SqlOptions,\r\n ): Promise<NeetruSqlClient<TSchema>>;\r\n\r\n // ── Camada offline (Mundo Documentos) ────────────────────────────────────\r\n\r\n /** Estado atual de sincronização da camada offline. */\r\n readonly syncState: SyncState;\r\n\r\n /**\r\n * Subscreve a mudanças de `SyncState`.\r\n * Retorna função de unsubscribe.\r\n */\r\n onSyncStateChanged(cb: (s: SyncState) => void): Unsubscribe;\r\n\r\n /**\r\n * Força flush da fila de mutações pendentes.\r\n * Útil antes de um `beforeunload` ou shutdown do produto.\r\n */\r\n flush(): Promise<void>;\r\n\r\n /**\r\n * Limpa o cache local (IndexedDB) — operação destrutiva.\r\n * Use com cuidado: dados não sincronizados serão perdidos.\r\n */\r\n clearCache(): Promise<void>;\r\n\r\n /**\r\n * Retorna os registros de conflito LWW pendentes de entrega.\r\n * Permite ao produto inspecionar escritas perdidas.\r\n */\r\n getConflicts(): Promise<ConflictRecord[]>;\r\n}\r\n\r\n// ─── Endpoints do Core para o transporte REST ─────────────────────────────────\r\n\r\n/** Endpoint de push de mutações (criação de documento). */\r\nconst DATASTORE_COLLECTION_ENDPOINT = (collection: string) =>\r\n `/api/sdk/v1/datastore/${encodeURIComponent(collection)}`;\r\n\r\n/** Endpoint de mutação num documento específico (update/set/delete). */\r\nconst DATASTORE_DOC_ENDPOINT = (collection: string, docId: string) =>\r\n `/api/sdk/v1/datastore/${encodeURIComponent(collection)}/${encodeURIComponent(docId)}`;\r\n\r\n// Note: DATASTORE_COLLECTION_ENDPOINT is reused for both add (POST) and list (GET)\r\n\r\n// ─── Transport detection ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * Seleciona o `RealtimeTransport` com base no transport configurado.\r\n *\r\n * Implementa o seam de injeção de 02-sdk.md §3.7.\r\n *\r\n * Regras:\r\n * 1. Se `opts._transport` foi injetado explicitamente (testes) → usa.\r\n * 2. `transport === 'firestore'` e `opts.firestoreTransport` presente → usa.\r\n * 3. `transport === 'nosql-vm'` e `opts.realtimeGatewayUrl` presente →\r\n * cria adapter WebSocket com push/pull REST + RealtimeClient para subscriptions.\r\n * 4. Qualquer outro caso → `RestSyncTransport` (REST real com `config`).\r\n */\r\nfunction resolveTransport(\r\n transport: NeetruDbTransport,\r\n opts: NeetruDbOptions,\r\n config: ResolvedConfig,\r\n): RealtimeTransport {\r\n // 1. Injeção explícita (testes / mocks avançados)\r\n if (opts._transport) {\r\n return opts._transport;\r\n }\r\n\r\n // 2. Transport Firestore — transporte já montado pelo produto\r\n if (transport === 'firestore') {\r\n if (opts.firestoreTransport) {\r\n return opts.firestoreTransport;\r\n }\r\n // Firestore sem transporte injetado → cai para REST real\r\n }\r\n\r\n // 3. Transport nosql-vm — writes via REST real + realtime via NeetruRealtimeClient\r\n if (transport === 'nosql-vm' && opts.realtimeGatewayUrl) {\r\n return createWebSocketSyncTransport(opts.realtimeGatewayUrl, config, opts);\r\n }\r\n\r\n // 4. Default: REST real (funciona para SQL, Firestore sem injeção, nosql-vm sem URL)\r\n return createRestSyncTransport(config);\r\n}\r\n\r\n// ─── RestSyncTransport (default) ─────────────────────────────────────────────\r\n\r\n/**\r\n * Transporte REST puro — usa os endpoints `/api/sdk/v1/datastore/*` do Core.\r\n *\r\n * BL-2 fix: `pushMutations` agora chama o Core de verdade via `httpRequest`.\r\n * Sem `config`, lança `NeetruDbError('db_unavailable')` — NUNCA retorna\r\n * `confirmed` para uma escrita que não foi enviada.\r\n *\r\n * - `pushMutations` → POST/PATCH/PUT/DELETE `/api/sdk/v1/datastore/{coll}/{id}`\r\n * - `pullChanges` → GET `/api/sdk/v1/datastore/{coll}` (best-effort por coleção)\r\n * - `fullResync` → GET por coleção (lista completa)\r\n *\r\n * Exportado para testes.\r\n */\r\nexport function createRestSyncTransport(\r\n config?: ResolvedConfig,\r\n): RealtimeTransport {\r\n return {\r\n async pushMutations(mutations: Mutation[]): Promise<PushMutationsResult> {\r\n if (!config) {\r\n // BL-2: fail-closed — sem config não há como enviar ao Core.\r\n // Lançar em vez de retornar `confirmed` silenciosamente.\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n '[RestSyncTransport] config não disponível — não é possível enviar ao Core. ' +\r\n 'Inicialize o transporte via createNeetruDb.',\r\n );\r\n }\r\n\r\n const { httpRequest } = await import('../http');\r\n const results: PushMutationsResult['results'] = [];\r\n\r\n // HIGH-2: o datastore do Core requer x-neetru-tenant. O mundo Documentos\r\n // é scoped por produto, não por tenant. Quando tenantId está ausente mas\r\n // productId existe, usamos productId como tenant-scope — o Core namespeia\r\n // a coleção como `tenant_{id}_{collection}`, isolando dados por produto.\r\n // tenantId explícito sempre tem prioridade (cenários multi-tenant).\r\n const tenantScopeId = config.tenantId ?? config.productId;\r\n const tenantHeaders: Record<string, string> | undefined = tenantScopeId\r\n ? { 'x-neetru-tenant': tenantScopeId }\r\n : undefined;\r\n\r\n for (const m of mutations) {\r\n try {\r\n let raw: unknown;\r\n if (m.op === 'add') {\r\n // POST /datastore/{collection} → { ok, id }\r\n // MED-1: add é não-idempotente — NÃO retryar (retries: 0).\r\n // Uma resposta perdida após escrita bem-sucedida causaria doc duplicado.\r\n // Para idempotência futura, considere enviar m.docId como x-neetru-doc-id.\r\n raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: DATASTORE_COLLECTION_ENDPOINT(m.collection),\r\n body: { data: m.payload ?? {} },\r\n requireAuth: true,\r\n retries: 0,\r\n headers: tenantHeaders,\r\n });\r\n } else if (m.op === 'set') {\r\n // PUT /datastore/{collection}/{docId} → { ok, id }\r\n // set é idempotente por docId — retry seguro.\r\n raw = await httpRequest<unknown>(config, {\r\n method: 'PUT',\r\n path: DATASTORE_DOC_ENDPOINT(m.collection, m.docId),\r\n body: { data: m.payload ?? {} },\r\n requireAuth: true,\r\n retries: 2,\r\n headers: tenantHeaders,\r\n });\r\n } else if (m.op === 'update') {\r\n // PATCH /datastore/{collection}/{docId} → { ok, id }\r\n // update (merge) com mesmo payload é idempotente por docId — retry seguro.\r\n raw = await httpRequest<unknown>(config, {\r\n method: 'PATCH',\r\n path: DATASTORE_DOC_ENDPOINT(m.collection, m.docId),\r\n body: { data: m.payload ?? {} },\r\n requireAuth: true,\r\n retries: 2,\r\n headers: tenantHeaders,\r\n });\r\n } else {\r\n // remove — DELETE /datastore/{collection}/{docId}\r\n // delete é idempotente — retry seguro.\r\n raw = await httpRequest<unknown>(config, {\r\n method: 'DELETE',\r\n path: DATASTORE_DOC_ENDPOINT(m.collection, m.docId),\r\n requireAuth: true,\r\n retries: 2,\r\n headers: tenantHeaders,\r\n });\r\n }\r\n\r\n const resp = raw as { ok?: boolean; id?: string; serverVersion?: string } | undefined;\r\n results.push({\r\n mutationId: m.mutationId,\r\n outcome: 'confirmed',\r\n serverVersion: resp?.serverVersion ?? resp?.id ?? `rest_${Date.now()}`,\r\n serverTimestamp: Date.now(),\r\n });\r\n } catch (err) {\r\n // Muta para NeetruDbError para sinalizar falha persistente.\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new NeetruDbError('db_unavailable', `pushMutations falhou: ${msg}`);\r\n }\r\n }\r\n\r\n return { results };\r\n },\r\n\r\n async pullChanges(\r\n _watermark: number | null,\r\n _resumeToken: string | null,\r\n ): Promise<PullChangesResult> {\r\n if (!config) {\r\n // Sem config, não há como consultar o Core — retorna vazio sem crash.\r\n return { docs: [], newWatermark: Date.now(), resyncRequired: false };\r\n }\r\n // C3 (auditoria 2026-06-10): o endpoint REST do Core (`GET /datastore/{coll}`)\r\n // NÃO tem change-feed/delta server-side (sem `?since=<watermark>`). A única\r\n // estratégia correta é sinalizar resyncRequired → o SyncEngine chama\r\n // fullResync, que faz GET por coleção e reconcilia o estado completo.\r\n // Seguro: fullResync é idempotente e barato pro transporte REST (sem\r\n // listener Firestore). Antes: stub vazio → cliente novo NUNCA puxava dados.\r\n return { docs: [], newWatermark: Date.now(), resyncRequired: true };\r\n },\r\n\r\n async fullResync(collections: string[]): Promise<FullResyncResult> {\r\n if (!config) {\r\n return { docs: [], newWatermark: Date.now() };\r\n }\r\n\r\n const { httpRequest } = await import('../http');\r\n\r\n // Mesma convenção de pushMutations: tenantId tem prioridade sobre productId.\r\n const tenantScopeId = config.tenantId ?? config.productId;\r\n const tenantHeaders: Record<string, string> | undefined = tenantScopeId\r\n ? { 'x-neetru-tenant': tenantScopeId }\r\n : undefined;\r\n\r\n const now = Date.now();\r\n const docs: import('./offline/sync-engine').ServerDoc[] = [];\r\n\r\n for (const collection of collections) {\r\n let raw: unknown;\r\n try {\r\n raw = await httpRequest<unknown>(config, {\r\n method: 'GET',\r\n path: DATASTORE_COLLECTION_ENDPOINT(collection),\r\n requireAuth: true,\r\n retries: 2,\r\n headers: tenantHeaders,\r\n // Teto do Core é 200. Coleções > 200 docs truncam silenciosamente\r\n // aqui (paginação cursor é tarefa Core separada) — a detecção de\r\n // deleção-por-ausência do SyncEngine NÃO deve rodar sobre truncamento,\r\n // então mantemos o limite no máximo do servidor por ora.\r\n query: { limit: 200 },\r\n });\r\n } catch (err) {\r\n // Falha numa coleção aborta o resync inteiro; o SyncEngine captura e\r\n // re-tenta o ciclo (não corrompe o cache local).\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n `[RestSyncTransport] fullResync falhou na coleção \"${collection}\": ${msg}`,\r\n );\r\n }\r\n\r\n const resp = raw as { items?: unknown[] } | undefined;\r\n const items = Array.isArray(resp?.items) ? resp.items : [];\r\n\r\n for (const item of items) {\r\n if (!item || typeof item !== 'object') continue;\r\n const record = item as Record<string, unknown>;\r\n\r\n // O Core inlina `id` no objeto de dados; ServerDoc exige id separado.\r\n const id = typeof record['id'] === 'string' ? record['id'] : null;\r\n if (!id) continue;\r\n const { id: _inlinedId, ...data } = record;\r\n\r\n // serverTimestamp a partir de `_updatedAt` (Core carimba via\r\n // FieldValue.serverTimestamp()). Sobre REST chega como número, objeto\r\n // Firestore { _seconds, _nanoseconds } ou ISO — normaliza p/ epoch ms.\r\n // Fallback `now` é seguro pra LWW (todos tratados como atuais).\r\n let serverTimestamp = now;\r\n const updatedAt = data['_updatedAt'];\r\n if (typeof updatedAt === 'number') {\r\n serverTimestamp = updatedAt;\r\n } else if (\r\n updatedAt !== null &&\r\n typeof updatedAt === 'object' &&\r\n typeof (updatedAt as Record<string, unknown>)['_seconds'] === 'number'\r\n ) {\r\n serverTimestamp = (updatedAt as Record<string, number>)['_seconds'] * 1000;\r\n } else if (typeof updatedAt === 'string') {\r\n const parsed = Date.parse(updatedAt);\r\n if (!Number.isNaN(parsed)) serverTimestamp = parsed;\r\n }\r\n\r\n // O REST do Core não expõe ETag/versão — etag opaco determinístico.\r\n const serverVersion = `rest_${id}_${serverTimestamp}`;\r\n\r\n docs.push({\r\n collection,\r\n id,\r\n data: data as Record<string, unknown>,\r\n serverVersion,\r\n serverTimestamp,\r\n deleted: false,\r\n });\r\n }\r\n }\r\n\r\n return { docs, newWatermark: now };\r\n },\r\n };\r\n}\r\n\r\n// ─── WebSocket SyncTransport (nosql-vm) ──────────────────────────────────────\r\n\r\n/**\r\n * Adapter entre `NeetruRealtimeClient` (WebSocket) e `SyncTransport`.\r\n *\r\n * BL-2 fix: `pushMutations` agora delega ao REST real (via `createRestSyncTransport`)\r\n * — o gateway WS é somente para leitura/realtime.\r\n *\r\n * H-10 fix: `getWebSocketRealtimeClient` é chamado aqui com um `ticketProvider`\r\n * real que chama `POST /api/sdk/v1/db/realtime/ticket` via HTTP do SDK.\r\n *\r\n * HIGH-1 fix: implementa `subscribeCollection` para que `DbCollectionRefImpl.onSnapshot`\r\n * registre subscriptions realtime via `NeetruRealtimeClient.subscribe()`.\r\n * Frames `delta` do gateway são traduzidos para changes e entregues ao callback.\r\n * Frames `resync` sinalizam `needsResync: true` para que o SyncEngine recarregue.\r\n */\r\nfunction createWebSocketSyncTransport(\r\n gatewayUrl: string,\r\n config: ResolvedConfig,\r\n opts: NeetruDbOptions,\r\n): RealtimeTransport {\r\n // Writes vão pelo REST real — o gateway WS é somente realtime/read.\r\n const restTransport = createRestSyncTransport(config);\r\n\r\n // HIGH-1: cria e retém o NeetruRealtimeClient para reutilização nas subscriptions.\r\n const realtimeClient = new NeetruRealtimeClient({\r\n gatewayUrl,\r\n ticketProvider: buildTicketProvider(config, opts),\r\n dbId: opts.dbId,\r\n webSocketFactory: opts._wsFactory,\r\n });\r\n\r\n return {\r\n pushMutations: restTransport.pushMutations.bind(restTransport),\r\n pullChanges: restTransport.pullChanges.bind(restTransport),\r\n fullResync: restTransport.fullResync.bind(restTransport),\r\n\r\n // HIGH-1: subscribeCollection — chamado por DbCollectionRefImpl.onSnapshot\r\n // quando o engine é nosql-vm. Registra a subscription no NeetruRealtimeClient\r\n // e traduz os frames inbound para o contrato de `onChange`.\r\n subscribeCollection(\r\n collection: string,\r\n onChange: (\r\n changes: Array<{ type: 'added' | 'modified' | 'removed'; docId: string; data: Record<string, unknown> | null }>,\r\n needsResync: boolean,\r\n ) => void,\r\n ): () => void {\r\n const subId = realtimeClient.subscribe(collection, {}, (frame) => {\r\n if (frame.op === 'resync') {\r\n onChange([], true);\r\n return;\r\n }\r\n if (frame.op === 'stale') {\r\n // Sinaliza que o cache pode estar desatualizado — pede resync.\r\n onChange([], true);\r\n return;\r\n }\r\n if (frame.op === 'delta' && frame.changes) {\r\n const changes = frame.changes.map((c) => ({\r\n type: (\r\n c.type === 'insert' ? 'added'\r\n : c.type === 'delete' ? 'removed'\r\n : 'modified'\r\n ) as 'added' | 'modified' | 'removed',\r\n docId: c.documentId,\r\n data: c.data ?? null,\r\n }));\r\n if (changes.length > 0) {\r\n onChange(changes, false);\r\n }\r\n }\r\n // 'error' e 'pong' são ignorados aqui; pong é tratado pelo heartbeat interno.\r\n });\r\n\r\n return () => {\r\n realtimeClient.unsubscribe(subId);\r\n };\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Constrói o `TicketProvider` real para o engine `nosql-vm` (H-10 fix).\r\n *\r\n * Chama `POST /api/sdk/v1/db/realtime/ticket` via a camada HTTP do SDK com\r\n * o `productId` resolvido do config.\r\n */\r\nfunction buildTicketProvider(\r\n config: ResolvedConfig,\r\n opts: NeetruDbOptions,\r\n): TicketProvider {\r\n return async () => {\r\n const { httpRequest } = await import('../http');\r\n const ticket = await httpRequest<{\r\n ticketId: string;\r\n token: string;\r\n expiresAt: string;\r\n ttlMs: number;\r\n }>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/db/realtime/ticket',\r\n body: {\r\n productId: config.productId ?? '',\r\n collections: opts.collections ?? ['*'],\r\n },\r\n requireAuth: true,\r\n retries: 1,\r\n });\r\n return ticket;\r\n };\r\n}\r\n\r\n/**\r\n * Retorna o `NeetruRealtimeClient` para uso em `subscribeRealtime` fora do\r\n * `SyncTransport` (extensão nosql-vm — não faz parte do contrato base).\r\n *\r\n * H-10 fix: agora aceita um `dbId` opcional que é passado para o cliente\r\n * (BL-8 — o cliente embute `_dbId` nos frames de subscribe).\r\n *\r\n * @param gatewayUrl URL do gateway WebSocket.\r\n * @param ticketProvider Provedor de ticket obrigatório.\r\n * @param dbId ID do banco lógico (BL-8).\r\n * @param wsFactory Factory de WebSocket injetável (testes).\r\n */\r\nexport function getWebSocketRealtimeClient(\r\n gatewayUrl: string,\r\n ticketProvider: TicketProvider,\r\n dbId?: string,\r\n wsFactory?: import('./realtime/types').WebSocketFactory,\r\n) {\r\n return new NeetruRealtimeClient({ gatewayUrl, ticketProvider, dbId, webSocketFactory: wsFactory });\r\n}\r\n\r\n// ─── Factory pública ─────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Cria o namespace `client.db` completo.\r\n *\r\n * **Factory única** — `createNeetruDb` é a única factory pública.\r\n * O split sync/async é um detalhe de implementação interno: o `NeetruDb`\r\n * retornado inicializa a camada offline (IndexedDB) de forma lazy na\r\n * primeira operação real, portanto:\r\n *\r\n * - Pode ser chamado de contextos síncronos (como `createNeetruClient`).\r\n * - Pode ser chamado com `await` quando se deseja garantir que o store\r\n * esteja aquecido antes da primeira op (equivalente a chamar `flush()`).\r\n * - `client.db.flush()` garante que o IndexedDB está aberto.\r\n *\r\n * @param config — config resolvida do cliente (apiKey, baseUrl, env, etc.)\r\n * @param dbOpts — opções do banco lógico (engine, dbId, collections, etc.)\r\n *\r\n * @example\r\n * ```ts\r\n * // Uso síncrono (dentro de createNeetruClient):\r\n * const db = createNeetruDb(resolved, config.db);\r\n *\r\n * // Uso com await (quando se quer garantir warmup):\r\n * const db = await createNeetruDb(resolved, config.db);\r\n * await db.flush(); // opcional — já está aquecido\r\n *\r\n * // O produto usa:\r\n * const orders = db.collection<Order>('orders');\r\n * const sqlDb = await db.sql(schema);\r\n * ```\r\n */\r\nexport function createNeetruDb(\r\n config: ResolvedConfig,\r\n dbOpts: NeetruDbOptions = {},\r\n): NeetruDb {\r\n // Backwards compat: `transport` (v2.3+) takes precedence over deprecated `engine` (v2.x).\r\n // If only `engine` is supplied, emit a deprecation warning and use its value.\r\n let resolvedTransport: NeetruDbTransport;\r\n if (dbOpts.transport !== undefined) {\r\n resolvedTransport = dbOpts.transport;\r\n } else if (dbOpts.engine !== undefined) {\r\n console.warn(\r\n '[neetru/sdk] NeetruDbOptions.engine está depreciado e será removido em v3.0. ' +\r\n 'Use NeetruDbOptions.transport em vez de engine. ' +\r\n 'Valores válidos: \"rest\" | \"firestore\" | \"nosql-vm\". ' +\r\n 'Nota: \"engine\" no SDK configura o TRANSPORTE (REST/Firestore/WebSocket), ' +\r\n 'não o storage engine do admin database (firestore-instance, cloud-sql-postgres, …).',\r\n );\r\n resolvedTransport = dbOpts.engine;\r\n } else {\r\n resolvedTransport = 'rest';\r\n }\r\n const transport = resolveTransport(resolvedTransport, dbOpts, config);\r\n\r\n // Gera um dbName único por produto × dbId × env\r\n const dbId = dbOpts.dbId ?? 'default';\r\n const dbName =\r\n dbOpts.dbName ??\r\n `neetru-db__${config.productId ?? 'sdk'}__${dbId}__${config.env}`;\r\n\r\n // Promise de inicialização — lazy: só dispara na primeira operação real\r\n let _docsPromise: Promise<NeetruDbDocuments> | null = null;\r\n let _docsResolved: NeetruDbDocuments | null = null;\r\n\r\n function getDocsPromise(): Promise<NeetruDbDocuments> {\r\n if (!_docsPromise) {\r\n _docsPromise = createOfflineDocumentsNamespace({\r\n dbName,\r\n transport,\r\n singleTab: dbOpts.singleTab ?? (config.env !== 'prod'),\r\n }).then((docs) => {\r\n _docsResolved = docs;\r\n return docs;\r\n });\r\n }\r\n return _docsPromise;\r\n }\r\n\r\n // Namespace lazy — inicializa o store na primeira operação\r\n return {\r\n collection<T = Record<string, unknown>>(\r\n name: string,\r\n ): import('./collection-ref').DbCollectionRef<T> {\r\n // Se já resolvido, usa diretamente; caso contrário inicia\r\n if (_docsResolved) return _docsResolved.collection<T>(name);\r\n\r\n // Retorna um DbCollectionRef que awaita o namespace antes de cada op.\r\n // A inicialização do IndexedDB é lazy — só dispara na primeira operação\r\n // real (list/get/add/…), não na chamada a collection() em si.\r\n return createLazyCollectionRef<T>(name, getDocsPromise);\r\n },\r\n\r\n async sql<TSchema extends Record<string, unknown>>(\r\n schema: TSchema,\r\n options?: SqlOptions,\r\n ): Promise<NeetruSqlClient<TSchema>> {\r\n if (config.env === 'dev') {\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n '[SDK] db.sql() não disponível em NEETRU_ENV=dev. ' +\r\n 'Use `neetru dev` para subir o container Postgres local.',\r\n );\r\n }\r\n // bug_0f836014: dynamic import — browser bundle nunca puxa pg/drizzle node.\r\n // sql() é server-only por design (precisa pg.Pool TCP socket). Webpack\r\n // do consumer Next.js split-chunks esse import, mas só fetcha em runtime\r\n // quando .sql() é chamado — que nunca acontece em browser.\r\n const sqlClientMod: { createSqlClientFromConfig: typeof CreateSqlClientFromConfigFn } =\r\n await import('./sql/sql-client');\r\n return sqlClientMod.createSqlClientFromConfig(config, schema, options);\r\n },\r\n\r\n get syncState(): SyncState {\r\n return _docsResolved?.syncState ?? {\r\n status: 'idle',\r\n pendingWrites: 0,\r\n lastSyncedAt: null,\r\n isLeaderTab: false,\r\n };\r\n },\r\n\r\n onSyncStateChanged(cb: (s: SyncState) => void) {\r\n if (_docsResolved) return _docsResolved.onSyncStateChanged(cb);\r\n // Aguarda init e então subscreve\r\n let unsub: Unsubscribe | null = null;\r\n let cancelled = false;\r\n getDocsPromise().then((docs) => {\r\n if (!cancelled) {\r\n unsub = docs.onSyncStateChanged(cb);\r\n }\r\n });\r\n return () => {\r\n cancelled = true;\r\n unsub?.();\r\n };\r\n },\r\n\r\n async flush(): Promise<void> {\r\n const docs = await getDocsPromise();\r\n return docs.flush();\r\n },\r\n\r\n async clearCache(): Promise<void> {\r\n const docs = await getDocsPromise();\r\n return docs.clearCache();\r\n },\r\n\r\n async getConflicts(): Promise<ConflictRecord[]> {\r\n const docs = await getDocsPromise();\r\n return docs.getConflicts();\r\n },\r\n };\r\n}\r\n\r\n// ─── Lazy DbCollectionRef ─────────────────────────────────────────────────────\r\n\r\n/**\r\n * Cria um `DbCollectionRef` que aguarda a inicialização do namespace antes de\r\n * qualquer operação. Permite que `createNeetruDb` retorne um ref imediato\r\n * mesmo que o IndexedDB ainda não esteja aberto (lazy-init).\r\n */\r\nfunction createLazyCollectionRef<T = Record<string, unknown>>(\r\n name: string,\r\n getDocsPromise: () => Promise<NeetruDbDocuments>,\r\n): import('./collection-ref').DbCollectionRef<T> {\r\n async function getRef(): Promise<import('./collection-ref').DbCollectionRef<T>> {\r\n const docs = await getDocsPromise();\r\n return docs.collection<T>(name);\r\n }\r\n\r\n return {\r\n async get(id: string) {\r\n return (await getRef()).get(id);\r\n },\r\n async list(q) {\r\n return (await getRef()).list(q);\r\n },\r\n async add(data) {\r\n return (await getRef()).add(data);\r\n },\r\n async set(id, data) {\r\n return (await getRef()).set(id, data);\r\n },\r\n async update(id, data) {\r\n return (await getRef()).update(id, data);\r\n },\r\n async remove(id) {\r\n return (await getRef()).remove(id);\r\n },\r\n async batch(ops) {\r\n return (await getRef()).batch(ops);\r\n },\r\n onDoc(id, cb) {\r\n let unsub: Unsubscribe | null = null;\r\n let cancelled = false;\r\n getRef().then((ref) => {\r\n if (!cancelled) {\r\n unsub = ref.onDoc(id, cb);\r\n }\r\n });\r\n return () => {\r\n cancelled = true;\r\n unsub?.();\r\n };\r\n },\r\n onSnapshot(q, cb) {\r\n let unsub: Unsubscribe | null = null;\r\n let cancelled = false;\r\n getRef().then((ref) => {\r\n if (!cancelled) {\r\n unsub = ref.onSnapshot(q, cb);\r\n }\r\n });\r\n return () => {\r\n cancelled = true;\r\n unsub?.();\r\n };\r\n },\r\n doc(id) {\r\n // Lazy doc ref — expõe id/path/collection imediatamente (sem aguardar init)\r\n return {\r\n get id(): string { return id; },\r\n get path(): string { return `${name}/${id}`; },\r\n get collection(): string { return name; },\r\n async get() {\r\n return (await getRef()).doc(id).get();\r\n },\r\n async set(data) {\r\n return (await getRef()).doc(id).set(data);\r\n },\r\n async update(data) {\r\n return (await getRef()).doc(id).update(data);\r\n },\r\n async remove() {\r\n return (await getRef()).doc(id).remove();\r\n },\r\n onSnapshot(cb) {\r\n let unsub: Unsubscribe | null = null;\r\n let cancelled = false;\r\n getRef().then((ref) => {\r\n if (!cancelled) {\r\n unsub = ref.doc(id).onSnapshot(cb);\r\n }\r\n });\r\n return () => {\r\n cancelled = true;\r\n unsub?.();\r\n };\r\n },\r\n };\r\n },\r\n };\r\n}\r\n","/**\r\n * QueryEngine — avaliador de query offline, puro e determinístico.\r\n *\r\n * Aplica um `QueryDescriptor` (where / orderBy / limit / cursor) sobre um array\r\n * de documentos em memória. Equivale a um motor de query local para o cache do\r\n * IndexedDB, cobrindo o subconjunto definido em I3 §5.2.\r\n *\r\n * Design:\r\n * - ZERO dependências externas.\r\n * - PURO: mesma entrada → mesma saída. Sem side-effects, sem I/O.\r\n * - Semântica compatível com Firestore:\r\n * • campo ausente no doc → doc EXCLUÍDO pelo filtro.\r\n * • ordem canônica de tipos mistos: null < number < string < boolean.\r\n * • tie-break final sempre por docId (lexicográfico).\r\n */\r\n\r\nimport type {\r\n OfflineDoc,\r\n QueryDescriptor,\r\n WhereFilter,\r\n WhereOp,\r\n OrderBy,\r\n QueryCursor,\r\n} from './types';\r\n\r\n// ─── Ordem canônica de tipos mistos ──────────────────────────────────────────\r\n\r\n/**\r\n * Retorna um número de \"rank\" de tipo para garantir ordem estável entre\r\n * valores de tipos diferentes (I3 §5.3): null < number < string < boolean.\r\n */\r\nfunction typeRank(v: unknown): number {\r\n if (v === null || v === undefined) return 0;\r\n if (typeof v === 'number') return 1;\r\n if (typeof v === 'string') return 2;\r\n if (typeof v === 'boolean') return 3;\r\n return 4; // object/array — vai para o fim\r\n}\r\n\r\n/**\r\n * Compara dois valores usando a ordem canônica de tipos mistos.\r\n * Retorna negativo, 0, ou positivo (como `Array.sort` espera).\r\n */\r\nfunction compareValues(a: unknown, b: unknown): number {\r\n const ra = typeRank(a);\r\n const rb = typeRank(b);\r\n if (ra !== rb) return ra - rb;\r\n\r\n // Mesmo tipo\r\n if (a === null || a === undefined) return 0;\r\n if (typeof a === 'number' && typeof b === 'number') return a - b;\r\n if (typeof a === 'string' && typeof b === 'string') return a < b ? -1 : a > b ? 1 : 0;\r\n if (typeof a === 'boolean' && typeof b === 'boolean') return a === b ? 0 : a ? 1 : -1;\r\n // Fallback para outros tipos — converte para string\r\n const sa = String(a);\r\n const sb = String(b);\r\n return sa < sb ? -1 : sa > sb ? 1 : 0;\r\n}\r\n\r\n// ─── Acesso a campo aninhado ──────────────────────────────────────────────────\r\n\r\n/**\r\n * Lê o valor de um campo no doc (suporta paths simples como 'status' ou\r\n * 'address.city' com ponto). Retorna `undefined` se o campo não existir —\r\n * o QueryEngine trata `undefined` como campo ausente (doc excluído).\r\n */\r\nfunction getField(data: Record<string, unknown>, field: string): unknown {\r\n const parts = field.split('.');\r\n let current: unknown = data;\r\n for (const part of parts) {\r\n if (current === null || current === undefined || typeof current !== 'object') {\r\n return undefined;\r\n }\r\n current = (current as Record<string, unknown>)[part];\r\n }\r\n return current;\r\n}\r\n\r\n// ─── Avaliação de filtros ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * Avalia um único `WhereFilter` contra os dados de um documento.\r\n * Campo ausente → false (doc excluído, semântica Firestore).\r\n */\r\nfunction evaluateFilter(\r\n data: Record<string, unknown>,\r\n filter: WhereFilter,\r\n): boolean {\r\n const fieldValue = getField(data, filter.field);\r\n\r\n // Campo ausente — doc excluído\r\n if (fieldValue === undefined) return false;\r\n\r\n const { op, value } = filter;\r\n\r\n switch (op as WhereOp) {\r\n case '==':\r\n return fieldValue === value;\r\n case '!=':\r\n return fieldValue !== value;\r\n case '<':\r\n return compareValues(fieldValue, value) < 0;\r\n case '<=':\r\n return compareValues(fieldValue, value) <= 0;\r\n case '>':\r\n return compareValues(fieldValue, value) > 0;\r\n case '>=':\r\n return compareValues(fieldValue, value) >= 0;\r\n case 'array-contains':\r\n return Array.isArray(fieldValue) && fieldValue.includes(value);\r\n case 'in':\r\n if (!Array.isArray(value)) return false;\r\n return (value as unknown[]).includes(fieldValue);\r\n case 'not-in':\r\n if (!Array.isArray(value)) return true;\r\n return !(value as unknown[]).includes(fieldValue);\r\n default:\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Aplica todos os filtros `where` em AND sobre os dados de um documento.\r\n */\r\nfunction matchesAllFilters(\r\n data: Record<string, unknown>,\r\n filters: WhereFilter[],\r\n): boolean {\r\n return filters.every((f) => evaluateFilter(data, f));\r\n}\r\n\r\n// ─── Ordenação ────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Constrói uma função de comparação para `Array.sort` baseada em um\r\n * `OrderBy` + tie-break final por docId.\r\n */\r\nfunction buildComparator<T>(\r\n orderBy: OrderBy | undefined,\r\n): (a: OfflineDoc<T>, b: OfflineDoc<T>) => number {\r\n return (a, b) => {\r\n if (orderBy) {\r\n const aVal = getField(a.data as Record<string, unknown>, orderBy.field);\r\n const bVal = getField(b.data as Record<string, unknown>, orderBy.field);\r\n const cmp = compareValues(aVal, bVal);\r\n if (cmp !== 0) {\r\n return orderBy.direction === 'desc' ? -cmp : cmp;\r\n }\r\n }\r\n // Tie-break por docId (lexicográfico ascendente, sempre)\r\n return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;\r\n };\r\n}\r\n\r\n// ─── Cursor ───────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Aplica o cursor de paginação ao array **já ordenado**.\r\n *\r\n * - `startAfter`: descarta o doc-cursor e tudo antes dele (inclusive).\r\n * - `endBefore`: mantém apenas os docs antes do cursor (exclusive).\r\n *\r\n * Se o docId do cursor não for encontrado no array, a lista é retornada\r\n * integralmente (falha graceful — cache pode não ter o doc-cursor).\r\n */\r\nfunction applyCursor<T>(\r\n sorted: OfflineDoc<T>[],\r\n cursor: QueryCursor,\r\n): OfflineDoc<T>[] {\r\n const idx = sorted.findIndex((d) => d.id === cursor.docId);\r\n if (idx === -1) {\r\n // Cursor não encontrado — retorna tudo (comportamento conservador)\r\n return sorted;\r\n }\r\n if (cursor.type === 'startAfter') {\r\n return sorted.slice(idx + 1);\r\n } else {\r\n // endBefore\r\n return sorted.slice(0, idx);\r\n }\r\n}\r\n\r\n// ─── QueryEngine ──────────────────────────────────────────────────────────────\r\n\r\n/** Resultado da avaliação de uma query. */\r\nexport interface QueryResult<T = Record<string, unknown>> {\r\n /** Documentos que casaram com a query, na ordem correta, respeitando limit. */\r\n docs: Array<{ id: string; data: T }>;\r\n /**\r\n * Indica que o resultado pode estar incompleto — o cache pode não ter todos\r\n * os documentos da coleção (a query offline só vê o que foi cacheado).\r\n * O chamador deve setar `stale: true` quando `incomplete: true`.\r\n */\r\n incomplete: boolean;\r\n}\r\n\r\n/**\r\n * QueryEngine — avaliador puro de queries sobre documentos em memória.\r\n *\r\n * Uso:\r\n * ```ts\r\n * const engine = new QueryEngine();\r\n * const result = engine.evaluate(docs, query);\r\n * ```\r\n *\r\n * Ou via helper estático:\r\n * ```ts\r\n * const result = QueryEngine.evaluate(docs, query);\r\n * ```\r\n */\r\nexport class QueryEngine {\r\n /**\r\n * Avalia um `QueryDescriptor` contra um array de `OfflineDoc`.\r\n *\r\n * Pipeline (I3 §5.3):\r\n * 1. Filtra docs com `deleted:false`.\r\n * 2. Aplica `where` (AND de todos os filtros).\r\n * 3. Ordena por `orderBy` + tie-break por docId.\r\n * 4. Aplica cursor (`startAfter` / `endBefore`).\r\n * 5. Corta em `limit`.\r\n */\r\n evaluate<T = Record<string, unknown>>(\r\n docs: OfflineDoc<T>[],\r\n query: QueryDescriptor,\r\n ): QueryResult<T> {\r\n // 1. Excluir tombstones\r\n let filtered = docs.filter((d) => !d.meta.deleted);\r\n\r\n // 2. Aplicar filtros where (AND)\r\n const filters = query.where ?? [];\r\n if (filters.length > 0) {\r\n filtered = filtered.filter((d) =>\r\n matchesAllFilters(d.data as Record<string, unknown>, filters),\r\n );\r\n }\r\n\r\n // 3. Ordenar\r\n const comparator = buildComparator<T>(query.orderBy);\r\n const sorted = [...filtered].sort(comparator);\r\n\r\n // 4. Cursor\r\n const afterCursor = query.cursor ? applyCursor(sorted, query.cursor) : sorted;\r\n\r\n // 5. Limit\r\n const limitN = Math.min(query.limit ?? 20, 500);\r\n const limited = afterCursor.slice(0, limitN);\r\n\r\n return {\r\n docs: limited.map((d) => ({ id: d.id, data: d.data })),\r\n // `incomplete` é sempre true aqui — o QueryEngine não sabe se o cache\r\n // tem todos os docs da coleção. É responsabilidade do chamador (LocalStore)\r\n // injetar o flag de completude baseado nos metadados do query_cache.\r\n incomplete: true,\r\n };\r\n }\r\n\r\n // ─── Static helper ─────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Helper estático para uso sem instanciar a classe.\r\n * Equivalente a `new QueryEngine().evaluate(docs, query)`.\r\n */\r\n static evaluate<T = Record<string, unknown>>(\r\n docs: OfflineDoc<T>[],\r\n query: QueryDescriptor,\r\n ): QueryResult<T> {\r\n return new QueryEngine().evaluate(docs, query);\r\n }\r\n}\r\n\r\n// ─── Exports auxiliares (para testes e outros módulos internos) ───────────────\r\n\r\nexport { compareValues, evaluateFilter, matchesAllFilters, getField };\r\n","/**\r\n * LocalStore — cache IndexedDB durável da camada offline do @neetru/sdk.\r\n *\r\n * Implementa o esquema de 5 object stores definido em I3 §3.3:\r\n * - `documents` — espelho dos documentos por coleção (keyPath: [collection, id])\r\n * - `mutations` — fila de escritas pendentes (keyPath: mutationId, índice por seq)\r\n * - `query_cache` — resultados de query materializados (keyPath: queryHash)\r\n * - `sync_meta` — watermarks e estado de sincronização (keyPath: key)\r\n * - `conflict_log`— escritas perdedoras LWW (keyPath: id, autoIncrement)\r\n *\r\n * Wrapper sobre `idb` (Promise-based, ~1KB) — não usa IndexedDB cru.\r\n *\r\n * Design:\r\n * - Todas as escritas são duráveis (IndexedDB transactions).\r\n * - Leituras sempre do IndexedDB — sem camada de memória adicional.\r\n * - Expõe os acessores que MutationQueue usa (putMutation, getMutation,\r\n * listMutations, deleteMutation) mais os métodos de doc/meta/conflict/query_cache.\r\n */\r\n\r\nimport { openDB, type IDBPDatabase } from 'idb';\r\nimport type { OfflineDoc, Mutation, ConflictRecord, QueryDescriptor } from './types';\r\nimport { QueryEngine, type QueryResult } from './query-engine';\r\n\r\n// ─── Versão do schema IndexedDB ───────────────────────────────────────────────\r\n\r\nconst SCHEMA_VERSION = 1;\r\n\r\n// ─── Tipos internos (espelham I3 §3.3) ───────────────────────────────────────\r\n\r\n/** Entrada na store `query_cache`. */\r\nexport interface CachedQuery {\r\n queryHash: string;\r\n collection: string;\r\n resultIds: string[];\r\n nextCursor: string | null;\r\n syncedAt: number;\r\n resumeToken: string | null;\r\n complete: boolean;\r\n}\r\n\r\n/** Opções de filtro para listConflicts. */\r\nexport interface ListConflictsOptions {\r\n /** Se definido, filtra por `delivered`. */\r\n delivered?: boolean;\r\n}\r\n\r\n/** Opções de filtro para listMutations. */\r\nexport interface ListMutationsOptions {\r\n /** Filtra por status. */\r\n status?: Mutation['status'];\r\n /** Filtra por [collection, docId] combinados. */\r\n collection?: string;\r\n docId?: string;\r\n}\r\n\r\n// ─── Nome das stores ──────────────────────────────────────────────────────────\r\n\r\nconst STORE_DOCUMENTS = 'documents';\r\nconst STORE_MUTATIONS = 'mutations';\r\nconst STORE_QUERY_CACHE = 'query_cache';\r\nconst STORE_SYNC_META = 'sync_meta';\r\nconst STORE_CONFLICT_LOG = 'conflict_log';\r\n\r\n// ─── LocalStore ───────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * LocalStore — cache IndexedDB durável.\r\n *\r\n * Uso:\r\n * ```ts\r\n * const store = new LocalStore('neetru-db__my-product__db1__prod');\r\n * await store.open();\r\n * await store.putDoc(doc);\r\n * const doc = await store.getDoc('orders', 'order-1');\r\n * ```\r\n *\r\n * Nomeação do banco: `neetru-db__{productSlug}__{dbId}__{env}` (I3 §3.2).\r\n * O chamador é responsável por montar o nome correto.\r\n */\r\nexport class LocalStore {\r\n private db: IDBPDatabase | null = null;\r\n private readonly dbName: string;\r\n\r\n constructor(dbName: string) {\r\n this.dbName = dbName;\r\n }\r\n\r\n // ─── Ciclo de vida ──────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Abre (ou reabre) o banco IndexedDB e executa o upgrade de schema se necessário.\r\n * Idempotente — chamadas subsequentes são no-ops se o banco já está aberto.\r\n */\r\n async open(): Promise<void> {\r\n if (this.db !== null) return;\r\n\r\n this.db = await openDB(this.dbName, SCHEMA_VERSION, {\r\n upgrade(db) {\r\n // ── documents ────────────────────────────────────────────────────────\r\n if (!db.objectStoreNames.contains(STORE_DOCUMENTS)) {\r\n const docsStore = db.createObjectStore(STORE_DOCUMENTS, {\r\n keyPath: ['collection', 'id'],\r\n });\r\n // I3 §3.3: índices\r\n docsStore.createIndex('by_collection', 'collection');\r\n docsStore.createIndex('by_collection_state', ['collection', 'meta.state']);\r\n docsStore.createIndex('by_updatedAtServer', 'meta.updatedAtServer');\r\n }\r\n\r\n // ── mutations ────────────────────────────────────────────────────────\r\n if (!db.objectStoreNames.contains(STORE_MUTATIONS)) {\r\n const mutStore = db.createObjectStore(STORE_MUTATIONS, {\r\n keyPath: 'mutationId',\r\n });\r\n // seq: índice para listagem em ordem\r\n mutStore.createIndex('by_seq', 'seq');\r\n // I3 §3.3: índices\r\n mutStore.createIndex('by_status', 'status');\r\n mutStore.createIndex('by_doc', ['collection', 'docId']);\r\n mutStore.createIndex('by_batch', 'batchId');\r\n }\r\n\r\n // ── query_cache ──────────────────────────────────────────────────────\r\n if (!db.objectStoreNames.contains(STORE_QUERY_CACHE)) {\r\n db.createObjectStore(STORE_QUERY_CACHE, { keyPath: 'queryHash' });\r\n }\r\n\r\n // ── sync_meta ────────────────────────────────────────────────────────\r\n if (!db.objectStoreNames.contains(STORE_SYNC_META)) {\r\n db.createObjectStore(STORE_SYNC_META, { keyPath: 'key' });\r\n }\r\n\r\n // ── conflict_log ─────────────────────────────────────────────────────\r\n if (!db.objectStoreNames.contains(STORE_CONFLICT_LOG)) {\r\n const conflictStore = db.createObjectStore(STORE_CONFLICT_LOG, {\r\n keyPath: 'id',\r\n autoIncrement: true,\r\n });\r\n conflictStore.createIndex('by_delivered', 'delivered');\r\n conflictStore.createIndex('by_doc', ['collection', 'docId']);\r\n }\r\n },\r\n });\r\n }\r\n\r\n /** Fecha o banco IndexedDB. */\r\n async close(): Promise<void> {\r\n this.db?.close();\r\n this.db = null;\r\n }\r\n\r\n /**\r\n * Apaga completamente o banco IndexedDB e o recria do zero.\r\n *\r\n * Ao contrário de `close()` + `open()` (que reabre o banco existente sem\r\n * apagar dados), `clearAll()` chama `indexedDB.deleteDatabase(dbName)` e\r\n * só então chama `open()` — garantindo que nenhum documento, mutação ou\r\n * metadado sobrevive.\r\n *\r\n * BUG fix: `clearCache()` em `NeetruDbDocumentsImpl` chamava close+open,\r\n * que reabre o mesmo banco. `clearAll()` é o método correto.\r\n */\r\n async clearAll(): Promise<void> {\r\n // Fecha a conexão ativa antes de apagar (IndexedDB rejeita deleteDatabase\r\n // enquanto há conexões abertas sem requisição de \"versionchange\").\r\n if (this.db !== null) {\r\n this.db.close();\r\n this.db = null;\r\n }\r\n await new Promise<void>((resolve, reject) => {\r\n const req = indexedDB.deleteDatabase(this.dbName);\r\n req.onsuccess = () => resolve();\r\n req.onerror = () => reject(req.error);\r\n // onblocked: outro contexto ainda tem o banco aberto — fecha assim que possível.\r\n req.onblocked = () => {\r\n // Não rejeita: o deleteDatabase pode completar depois do blocked.\r\n // O resolve/reject acima cobre o resultado final.\r\n };\r\n });\r\n // Reabre o banco com schema limpo.\r\n await this.open();\r\n }\r\n\r\n private assertOpen(): IDBPDatabase {\r\n if (this.db === null) {\r\n throw new Error('LocalStore: banco não está aberto. Chame open() primeiro.');\r\n }\r\n return this.db;\r\n }\r\n\r\n // ─── Documents ──────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna um documento pelo [collection, id], ou `null` se não existir.\r\n * Retorna tombstones (deleted: true) — o chamador decide se deve mostrá-los.\r\n */\r\n async getDoc<T = Record<string, unknown>>(\r\n collection: string,\r\n id: string,\r\n ): Promise<OfflineDoc<T> | null> {\r\n const db = this.assertOpen();\r\n const result = await db.get(STORE_DOCUMENTS, [collection, id]);\r\n return (result as OfflineDoc<T> | undefined) ?? null;\r\n }\r\n\r\n /**\r\n * Insere ou atualiza um documento na store `documents`.\r\n * O documento é identificado pelo keyPath composto `[collection, id]`.\r\n */\r\n async putDoc<T = Record<string, unknown>>(doc: OfflineDoc<T>): Promise<void> {\r\n const db = this.assertOpen();\r\n await db.put(STORE_DOCUMENTS, doc);\r\n }\r\n\r\n /**\r\n * Marca um documento como tombstone (`deleted: true`).\r\n * Não remove fisicamente — o tombstone é necessário para reconciliação.\r\n * No-op se o documento não existir.\r\n */\r\n async deleteDoc(collection: string, id: string): Promise<void> {\r\n const db = this.assertOpen();\r\n const existing = await db.get(STORE_DOCUMENTS, [collection, id]);\r\n if (!existing) return;\r\n await db.put(STORE_DOCUMENTS, {\r\n ...existing,\r\n meta: {\r\n ...(existing as OfflineDoc).meta,\r\n deleted: true,\r\n updatedAtLocal: Date.now(),\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Lista documentos de uma coleção, aplicando o QueryDescriptor via QueryEngine.\r\n *\r\n * I3 §5.3: a listagem lê todos os docs da coleção pelo índice `by_collection`\r\n * e delega a filtragem/ordenação/paginação ao QueryEngine (que opera em memória).\r\n */\r\n async listDocs<T = Record<string, unknown>>(\r\n collection: string,\r\n query: QueryDescriptor,\r\n ): Promise<QueryResult<T>> {\r\n const db = this.assertOpen();\r\n const rawDocs = await db.getAllFromIndex(STORE_DOCUMENTS, 'by_collection', collection);\r\n return QueryEngine.evaluate<T>(rawDocs as OfflineDoc<T>[], query);\r\n }\r\n\r\n // ─── Sync meta (key-value) ──────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna o valor de uma chave da store `sync_meta`, ou `null` se não existir.\r\n *\r\n * Chaves conhecidas (I3 §3.3):\r\n * 'lastSyncWatermark', 'resumeToken:<col>', 'schemaVersion',\r\n * 'lastFullResyncAt', 'leaderTabId'.\r\n */\r\n async getMeta(key: string): Promise<unknown> {\r\n const db = this.assertOpen();\r\n const entry = await db.get(STORE_SYNC_META, key);\r\n if (!entry) return null;\r\n return (entry as { key: string; value: unknown }).value;\r\n }\r\n\r\n /**\r\n * Armazena ou atualiza um valor na store `sync_meta`.\r\n */\r\n async setMeta(key: string, value: unknown): Promise<void> {\r\n const db = this.assertOpen();\r\n await db.put(STORE_SYNC_META, { key, value });\r\n }\r\n\r\n // ─── Conflict log ───────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Adiciona um registro de conflito ao `conflict_log`.\r\n * O `id` é autoIncrement — não deve ser fornecido pelo chamador.\r\n */\r\n async appendConflict(record: Omit<ConflictRecord, 'id'>): Promise<ConflictRecord> {\r\n const db = this.assertOpen();\r\n const id = await db.add(STORE_CONFLICT_LOG, record);\r\n return { ...record, id: id as number };\r\n }\r\n\r\n /**\r\n * Lista registros do `conflict_log`.\r\n * Filtra por `delivered` se a opção for fornecida.\r\n */\r\n async listConflicts(options?: ListConflictsOptions): Promise<ConflictRecord[]> {\r\n const db = this.assertOpen();\r\n const all = await db.getAll(STORE_CONFLICT_LOG) as ConflictRecord[];\r\n\r\n if (options?.delivered !== undefined) {\r\n return all.filter((r) => r.delivered === options.delivered);\r\n }\r\n return all;\r\n }\r\n\r\n /**\r\n * Marca um registro do `conflict_log` como entregue ao produto.\r\n */\r\n async markConflictDelivered(id: number): Promise<void> {\r\n const db = this.assertOpen();\r\n const existing = await db.get(STORE_CONFLICT_LOG, id) as ConflictRecord | undefined;\r\n if (!existing) return;\r\n await db.put(STORE_CONFLICT_LOG, { ...existing, delivered: true });\r\n }\r\n\r\n // ─── Mutations (acessores usados pelo MutationQueue) ────────────────────────\r\n\r\n /**\r\n * Insere ou atualiza uma mutação na store `mutations`.\r\n * Key: `mutationId`.\r\n */\r\n async putMutation(mutation: Mutation): Promise<void> {\r\n const db = this.assertOpen();\r\n await db.put(STORE_MUTATIONS, mutation);\r\n }\r\n\r\n /**\r\n * Retorna uma mutação pelo `mutationId`, ou `null` se não existir.\r\n */\r\n async getMutation(mutationId: string): Promise<Mutation | null> {\r\n const db = this.assertOpen();\r\n const result = await db.get(STORE_MUTATIONS, mutationId);\r\n return (result as Mutation | undefined) ?? null;\r\n }\r\n\r\n /**\r\n * Lista mutações com filtros opcionais.\r\n * Resultado ordenado por `seq` crescente.\r\n */\r\n async listMutations(options?: ListMutationsOptions): Promise<Mutation[]> {\r\n const db = this.assertOpen();\r\n\r\n let mutations: Mutation[];\r\n\r\n if (options?.status !== undefined) {\r\n mutations = (await db.getAllFromIndex(STORE_MUTATIONS, 'by_status', options.status)) as Mutation[];\r\n } else if (options?.collection !== undefined && options.docId !== undefined) {\r\n mutations = (await db.getAllFromIndex(STORE_MUTATIONS, 'by_doc', [options.collection, options.docId])) as Mutation[];\r\n } else {\r\n // Lê tudo pelo índice by_seq para garantir ordem\r\n mutations = (await db.getAllFromIndex(STORE_MUTATIONS, 'by_seq')) as Mutation[];\r\n }\r\n\r\n // Ordena por seq crescente (defensivo — o índice by_seq já ordena, mas\r\n // leituras por outros índices podem não preservar a ordem)\r\n return mutations.sort((a, b) => a.seq - b.seq);\r\n }\r\n\r\n /**\r\n * Remove uma mutação pelo `mutationId`.\r\n * No-op se não existir.\r\n */\r\n async deleteMutation(mutationId: string): Promise<void> {\r\n const db = this.assertOpen();\r\n await db.delete(STORE_MUTATIONS, mutationId);\r\n }\r\n\r\n // ─── Collection discovery ────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna a lista de coleções únicas presentes na store `documents`.\r\n *\r\n * Usado pelo SyncEngine no full resync para descobrir coleções cujos docs\r\n * precisam ser verificados contra a resposta do servidor (tombstone detection).\r\n *\r\n * Implementação: itera o índice `by_collection` com `openKeyCursor` para\r\n * coletar os valores únicos de forma eficiente (sem carregar os docs completos).\r\n */\r\n async listCollections(): Promise<string[]> {\r\n const db = this.assertOpen();\r\n const allDocs = await db.getAllFromIndex(STORE_DOCUMENTS, 'by_collection') as OfflineDoc[];\r\n const collections = new Set<string>();\r\n for (const doc of allDocs) {\r\n collections.add(doc.collection);\r\n }\r\n return Array.from(collections);\r\n }\r\n\r\n // ─── Query cache ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna a entrada de `query_cache` para um hash de query, ou `null`.\r\n */\r\n async getQueryCache(queryHash: string): Promise<CachedQuery | null> {\r\n const db = this.assertOpen();\r\n const result = await db.get(STORE_QUERY_CACHE, queryHash);\r\n return (result as CachedQuery | undefined) ?? null;\r\n }\r\n\r\n /**\r\n * Insere ou atualiza uma entrada de `query_cache`.\r\n */\r\n async putQueryCache(entry: CachedQuery): Promise<void> {\r\n const db = this.assertOpen();\r\n await db.put(STORE_QUERY_CACHE, entry);\r\n }\r\n\r\n /**\r\n * Remove uma entrada de `query_cache` pelo queryHash.\r\n */\r\n async deleteQueryCache(queryHash: string): Promise<void> {\r\n const db = this.assertOpen();\r\n await db.delete(STORE_QUERY_CACHE, queryHash);\r\n }\r\n}\r\n","/**\n * MemoryStore — implementação em memória do contrato de LocalStore.\n *\n * Usada automaticamente quando IndexedDB não está disponível (Node.js, Workers\n * sem IDB, ambientes de teste sem fake-indexeddb). Implementa exatamente o\n * mesmo conjunto de métodos públicos que LocalStore, garantindo que o restante\n * da stack offline (MutationQueue, SyncEngine, DbCollectionRefImpl) funcione\n * sem qualquer alteração.\n *\n * Características:\n * - Totalmente síncrona internamente, mas expõe a mesma API async de LocalStore.\n * - Sem persistência entre reinicializações (in-process apenas).\n * - open()/close() são no-ops (sem recurso externo a abrir/fechar).\n * - listMutations() preserva a ordenação por `seq` exigida pelo MutationQueue.\n *\n * @internal Não exportado pela superfície pública do SDK — detalhe de implementação.\n */\n\nimport type { OfflineDoc, Mutation, ConflictRecord, QueryDescriptor } from './types';\nimport { QueryEngine, type QueryResult } from './query-engine';\nimport type {\n CachedQuery,\n ListConflictsOptions,\n ListMutationsOptions,\n} from './local-store';\n\n// ─── MemoryStore ──────────────────────────────────────────────────────────────\n\nexport class MemoryStore {\n // store `documents` — key: `${collection}\\0${id}`\n private readonly _docs = new Map<string, OfflineDoc>();\n\n // store `mutations` — key: mutationId\n private readonly _mutations = new Map<string, Mutation>();\n\n // store `sync_meta` — key: string\n private readonly _meta = new Map<string, unknown>();\n\n // store `conflict_log` — autoIncrement int key\n private readonly _conflicts: Array<ConflictRecord & { id: number }> = [];\n private _conflictSeq = 0;\n\n // store `query_cache` — key: queryHash\n private readonly _queryCache = new Map<string, CachedQuery>();\n\n // ─── Ciclo de vida (no-ops) ─────────────────────────────────────────────────\n\n async open(): Promise<void> {\n // Nada a abrir — já está \"aberto\" ao ser construído.\n }\n\n async close(): Promise<void> {\n // No-op: MemoryStore não tem recurso externo a fechar.\n // (Os dados são preservados: apenas LocalStore.close() limpa o handle IDB.)\n }\n\n /**\n * Apaga todos os dados em memória — equivalente ao `indexedDB.deleteDatabase`\n * que `LocalStore.clearAll()` executa em ambientes com IndexedDB.\n */\n async clearAll(): Promise<void> {\n this._docs.clear();\n this._mutations.clear();\n this._meta.clear();\n this._conflicts.splice(0);\n this._conflictSeq = 0;\n this._queryCache.clear();\n }\n\n // ─── Documents ─────────────────────────────────────────────────────────────\n\n async getDoc<T = Record<string, unknown>>(\n collection: string,\n id: string,\n ): Promise<OfflineDoc<T> | null> {\n const key = `${collection}\\0${id}`;\n return (this._docs.get(key) as OfflineDoc<T> | undefined) ?? null;\n }\n\n async putDoc<T = Record<string, unknown>>(doc: OfflineDoc<T>): Promise<void> {\n const key = `${doc.collection}\\0${doc.id}`;\n this._docs.set(key, doc as OfflineDoc);\n }\n\n async deleteDoc(collection: string, id: string): Promise<void> {\n const key = `${collection}\\0${id}`;\n const existing = this._docs.get(key);\n if (!existing) return;\n this._docs.set(key, {\n ...existing,\n meta: {\n ...existing.meta,\n deleted: true,\n updatedAtLocal: Date.now(),\n },\n });\n }\n\n async listDocs<T = Record<string, unknown>>(\n collection: string,\n query: QueryDescriptor,\n ): Promise<QueryResult<T>> {\n const rawDocs = Array.from(this._docs.values()).filter(\n (d) => d.collection === collection,\n ) as OfflineDoc<T>[];\n return QueryEngine.evaluate<T>(rawDocs, query);\n }\n\n // ─── Sync meta ──────────────────────────────────────────────────────────────\n\n async getMeta(key: string): Promise<unknown> {\n return this._meta.get(key) ?? null;\n }\n\n async setMeta(key: string, value: unknown): Promise<void> {\n this._meta.set(key, value);\n }\n\n // ─── Conflict log ────────────────────────────────────────────────────────────\n\n async appendConflict(record: Omit<ConflictRecord, 'id'>): Promise<ConflictRecord> {\n const id = ++this._conflictSeq;\n const full = { ...record, id } as ConflictRecord & { id: number };\n this._conflicts.push(full);\n return full;\n }\n\n async listConflicts(options?: ListConflictsOptions): Promise<ConflictRecord[]> {\n if (options?.delivered !== undefined) {\n return this._conflicts.filter((r) => r.delivered === options.delivered);\n }\n return [...this._conflicts];\n }\n\n async markConflictDelivered(id: number): Promise<void> {\n const entry = this._conflicts.find((r) => r.id === id);\n if (entry) entry.delivered = true;\n }\n\n // ─── Mutations ───────────────────────────────────────────────────────────────\n\n async putMutation(mutation: Mutation): Promise<void> {\n this._mutations.set(mutation.mutationId, { ...mutation });\n }\n\n async getMutation(mutationId: string): Promise<Mutation | null> {\n return this._mutations.get(mutationId) ?? null;\n }\n\n async listMutations(options?: ListMutationsOptions): Promise<Mutation[]> {\n let all = Array.from(this._mutations.values());\n\n if (options?.status !== undefined) {\n all = all.filter((m) => m.status === options.status);\n } else if (options?.collection !== undefined && options.docId !== undefined) {\n all = all.filter(\n (m) => m.collection === options.collection && m.docId === options.docId,\n );\n } else if (options?.collection !== undefined) {\n all = all.filter((m) => m.collection === options.collection);\n }\n\n return all.sort((a, b) => a.seq - b.seq);\n }\n\n async deleteMutation(mutationId: string): Promise<void> {\n this._mutations.delete(mutationId);\n }\n\n // ─── Collection discovery ────────────────────────────────────────────────────\n\n async listCollections(): Promise<string[]> {\n const collections = new Set<string>();\n for (const doc of this._docs.values()) {\n collections.add(doc.collection);\n }\n return Array.from(collections);\n }\n\n // ─── Query cache ─────────────────────────────────────────────────────────────\n\n async getQueryCache(queryHash: string): Promise<CachedQuery | null> {\n return this._queryCache.get(queryHash) ?? null;\n }\n\n async putQueryCache(entry: CachedQuery): Promise<void> {\n this._queryCache.set(entry.queryHash, { ...entry });\n }\n\n async deleteQueryCache(queryHash: string): Promise<void> {\n this._queryCache.delete(queryHash);\n }\n}\n","/**\r\n * MutationQueue — fila durável e atomicamente-ordenada de escritas pendentes.\r\n *\r\n * Implementa I3 §4 e §5 (integração com QueryEngine/LocalStore):\r\n *\r\n * - Enqueue atômico: aplica ao cache de documentos e grava na fila em uma\r\n * única transação IndexedDB — crash mid-enqueue nunca corrompe a ordenação.\r\n * - Seq monotônico: autoIncrement via geração local (não confia no IndexedDB\r\n * autoIncrement para seq para poder controlar coalescing antes da gravação).\r\n * - MutationId: UUID v4 client-generated (I3 §4.2) — idempotência no replay.\r\n * - Coalescing (I3 §4.4): mutações adjacentes do mesmo doc (sem batchId\r\n * diferente, sem inflight no meio) são colapsadas antes do enfileiramento.\r\n * - Drain: retorna mutações queued em ordem de seq (para o SyncEngine).\r\n * - markApplied / markFailed / markInflight: ciclo de vida de cada mutação.\r\n *\r\n * Persistência: totalmente via LocalStore (IndexedDB). Nenhum estado em RAM\r\n * além do ponteiro de seq atual (re-sync ao instanciar se necessário).\r\n */\r\n\r\nimport type { LocalStore } from './local-store';\r\nimport type { Mutation, MutationKind } from './types';\r\n\r\n// ─── Geração de UUID v4 ───────────────────────────────────────────────────────\r\n\r\n/**\r\n * Gera um UUID v4 aleatório (I3 §4.2).\r\n * Usa `crypto.randomUUID()` quando disponível (Node ≥19 / browsers modernos),\r\n * com fallback manual para ambientes mais antigos.\r\n */\r\nfunction generateUUIDv4(): string {\r\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\r\n return crypto.randomUUID();\r\n }\r\n // Fallback RFC 4122 v4\r\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\r\n const r = (Math.random() * 16) | 0;\r\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\r\n return v.toString(16);\r\n });\r\n}\r\n\r\n// ─── Tipos de entrada para enqueue ───────────────────────────────────────────\r\n\r\n/** Parâmetros para enfileirar uma nova mutação. */\r\nexport interface EnqueueParams {\r\n collection: string;\r\n /** Para `add`, pode ser omitido — um UUID v4 será gerado automaticamente. */\r\n docId?: string;\r\n op: MutationKind;\r\n payload: Record<string, unknown> | null;\r\n baseVersion: string | null;\r\n batchId: string | null;\r\n}\r\n\r\n/** Opções para drain(). */\r\nexport interface DrainOptions {\r\n /** Máximo de mutações a retornar. Default: sem limite. */\r\n maxBatch?: number;\r\n}\r\n\r\n// ─── MutationQueue ────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * MutationQueue — fila durável de escritas pendentes.\r\n *\r\n * Construída sobre LocalStore. Cada MutationQueue é ligada a um LocalStore\r\n * (e portanto a um banco IndexedDB). Uma instância por banco lógico Neetru.\r\n *\r\n * ```ts\r\n * const store = new LocalStore(dbName);\r\n * await store.open();\r\n * const queue = new MutationQueue(store);\r\n *\r\n * const mut = await queue.enqueue({\r\n * collection: 'orders',\r\n * op: 'add',\r\n * payload: { total: 100 },\r\n * baseVersion: null,\r\n * batchId: null,\r\n * });\r\n * // mut.id, mut.seq, mut.mutationId disponíveis imediatamente.\r\n * ```\r\n */\r\nexport class MutationQueue {\r\n private readonly store: LocalStore;\r\n /**\r\n * Ponteiro de sequência local.\r\n * Inicializado com 0 — o primeiro enqueue sincroniza o valor real do banco\r\n * (`_syncSeq`), garantindo que nunca sobreponha um seq existente.\r\n */\r\n private seqCounter = 0;\r\n private seqSynced = false;\r\n\r\n constructor(store: LocalStore) {\r\n this.store = store;\r\n }\r\n\r\n // ─── Seq management ─────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Sincroniza o ponteiro de seq com o maior seq existente no banco.\r\n * Chamado lazy no primeiro enqueue.\r\n */\r\n private async syncSeq(): Promise<void> {\r\n if (this.seqSynced) return;\r\n const all = await this.store.listMutations();\r\n if (all.length > 0) {\r\n const maxSeq = Math.max(...all.map((m) => m.seq));\r\n this.seqCounter = maxSeq;\r\n }\r\n this.seqSynced = true;\r\n }\r\n\r\n private nextSeq(): number {\r\n this.seqCounter += 1;\r\n return this.seqCounter;\r\n }\r\n\r\n // ─── Coalescing ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Tenta coalescir `newOp`/`newPayload` com a mutação existente `existing`.\r\n *\r\n * Regras de coalescing (I3 §4.4):\r\n * - update + update → update com merge dos campos (segundo vence nos conflitos)\r\n * - add + update → add com campos mesclados\r\n * - add + remove → nada (remove a mutação existente, retorna null para remove)\r\n * - set + update → set com campos mesclados\r\n * - any + remove (base servidor) → remove\r\n *\r\n * Retorna:\r\n * - `{ coalesced: Mutation }` — substitui a mutação existente (update in-place)\r\n * - `{ removed: true }` — a mutação existente deve ser deletada (add+remove)\r\n * - `null` — não é possível coalescir\r\n */\r\n private tryCoalesce(\r\n existing: Mutation,\r\n newOp: MutationKind,\r\n newPayload: Record<string, unknown> | null,\r\n newBatchId: string | null,\r\n ): { coalesced: Mutation } | { removed: true } | null {\r\n // Não coalesce se batchIds diferentes (um ou ambos definidos e diferentes)\r\n if (existing.batchId !== newBatchId) return null;\r\n\r\n // Não coalesce através de inflight\r\n if (existing.status === 'inflight') return null;\r\n\r\n const existingOp = existing.op;\r\n\r\n // add + remove → remove da fila inteira (doc nunca existiu no servidor)\r\n if (existingOp === 'add' && newOp === 'remove') {\r\n return { removed: true };\r\n }\r\n\r\n // update + update → merge dos campos\r\n if (existingOp === 'update' && newOp === 'update') {\r\n return {\r\n coalesced: {\r\n ...existing,\r\n payload: { ...(existing.payload ?? {}), ...(newPayload ?? {}) },\r\n },\r\n };\r\n }\r\n\r\n // add + update → add com campos mesclados\r\n if (existingOp === 'add' && newOp === 'update') {\r\n return {\r\n coalesced: {\r\n ...existing,\r\n op: 'add',\r\n payload: { ...(existing.payload ?? {}), ...(newPayload ?? {}) },\r\n },\r\n };\r\n }\r\n\r\n // set + update → set com campos mesclados\r\n if (existingOp === 'set' && newOp === 'update') {\r\n return {\r\n coalesced: {\r\n ...existing,\r\n op: 'set',\r\n payload: { ...(existing.payload ?? {}), ...(newPayload ?? {}) },\r\n },\r\n };\r\n }\r\n\r\n // update/set/add + remove (base servidor presente) → remove\r\n if (newOp === 'remove') {\r\n return {\r\n coalesced: {\r\n ...existing,\r\n op: 'remove',\r\n payload: null,\r\n },\r\n };\r\n }\r\n\r\n // Não coalesça nos demais casos (ex: remove + set — nova operação distinta)\r\n return null;\r\n }\r\n\r\n // ─── Enqueue ─────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Enfileira uma nova mutação.\r\n *\r\n * Processo (I3 §4.1):\r\n * 1. Gera docId se op=add e não fornecido.\r\n * 2. Sincroniza seq (lazy).\r\n * 3. Tenta coalescir com a última mutação queued do mesmo [collection, docId].\r\n * 4. Se coalescing:\r\n * - `removed` → deleta mutação existente; retorna sem enfileirar nova.\r\n * - `coalesced` → substitui a mutação existente (mesmo seq, mesmo mutationId).\r\n * 5. Se não coalesce → enfileira nova mutação (novo seq, novo mutationId).\r\n *\r\n * Atômico: a persistência final é uma única operação putMutation.\r\n */\r\n async enqueue(params: EnqueueParams): Promise<Mutation> {\r\n const { collection, op, payload, baseVersion, batchId } = params;\r\n\r\n // 1. docId\r\n const docId = params.docId ?? (op === 'add' ? generateUUIDv4() : '');\r\n\r\n // 2. Sincroniza seq se necessário\r\n await this.syncSeq();\r\n\r\n // 3. Tenta coalescir com mutação existente do mesmo [collection, docId]\r\n // Busca a última mutação queued para este doc (não inflight)\r\n const existingMutations = await this.store.listMutations({ collection, docId });\r\n const lastQueued = existingMutations\r\n .filter((m) => m.status === 'queued')\r\n .sort((a, b) => b.seq - a.seq)[0]; // o mais recente\r\n\r\n if (lastQueued !== undefined) {\r\n const coalesceResult = this.tryCoalesce(lastQueued, op, payload, batchId);\r\n\r\n if (coalesceResult !== null) {\r\n if ('removed' in coalesceResult) {\r\n // add + remove → remove da fila\r\n await this.store.deleteMutation(lastQueued.mutationId);\r\n // Retorna uma mutação \"fantasma\" representando o no-op\r\n // (o chamador recebe o resultado, mas a fila está vazia para este doc)\r\n const phantomMut: Mutation = {\r\n seq: lastQueued.seq,\r\n mutationId: generateUUIDv4(),\r\n collection,\r\n docId,\r\n op: 'remove',\r\n payload: null,\r\n baseVersion,\r\n enqueuedAt: Date.now(),\r\n attempts: 0,\r\n lastError: null,\r\n status: 'queued',\r\n batchId,\r\n };\r\n // Não persiste — este doc foi cancelado\r\n return phantomMut;\r\n }\r\n\r\n // coalesced → atualiza a mutação existente no banco\r\n const { coalesced } = coalesceResult;\r\n await this.store.putMutation(coalesced);\r\n return coalesced;\r\n }\r\n }\r\n\r\n // 4. Nova mutação\r\n const seq = this.nextSeq();\r\n const mutation: Mutation = {\r\n seq,\r\n mutationId: generateUUIDv4(),\r\n collection,\r\n docId,\r\n op,\r\n payload,\r\n baseVersion,\r\n enqueuedAt: Date.now(),\r\n attempts: 0,\r\n lastError: null,\r\n status: 'queued',\r\n batchId,\r\n };\r\n\r\n await this.store.putMutation(mutation);\r\n return mutation;\r\n }\r\n\r\n // ─── Leitura da fila ─────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna a primeira mutação com status `queued` (menor seq), ou `null`.\r\n */\r\n async peek(): Promise<Mutation | null> {\r\n const pending = await this.listPending();\r\n return pending[0] ?? null;\r\n }\r\n\r\n /**\r\n * Retorna todas as mutações com status `queued`, ordenadas por seq crescente.\r\n */\r\n async listPending(): Promise<Mutation[]> {\r\n return this.store.listMutations({ status: 'queued' });\r\n }\r\n\r\n /**\r\n * Retorna TODAS as mutações (qualquer status), ordenadas por seq crescente.\r\n * Útil para inspeção e testes.\r\n */\r\n async listAll(): Promise<Mutation[]> {\r\n return this.store.listMutations();\r\n }\r\n\r\n /**\r\n * Conta o número de mutações com status `queued`.\r\n */\r\n async countPending(): Promise<number> {\r\n const pending = await this.listPending();\r\n return pending.length;\r\n }\r\n\r\n /**\r\n * Retorna um lote de mutações `queued` para drenagem (I3 §6.2 FASE 1).\r\n * Ordena por seq crescente. O SyncEngine chama drain(), itera, e marca\r\n * cada mutação como applied/failed.\r\n */\r\n async drain(options?: DrainOptions): Promise<Mutation[]> {\r\n const pending = await this.listPending();\r\n if (options?.maxBatch !== undefined && options.maxBatch > 0) {\r\n return pending.slice(0, options.maxBatch);\r\n }\r\n return pending;\r\n }\r\n\r\n // ─── Ciclo de vida de mutações ────────────────────────────────────────────────\r\n\r\n /**\r\n * Marca uma mutação como `inflight` (está sendo enviada ao Core).\r\n * Chamado pelo SyncEngine antes de enviar o request.\r\n */\r\n async markInflight(mutationId: string): Promise<void> {\r\n const mut = await this.store.getMutation(mutationId);\r\n if (!mut) return;\r\n await this.store.putMutation({ ...mut, status: 'inflight' });\r\n }\r\n\r\n /**\r\n * Remove a mutação da fila (sucesso de replay).\r\n * Chamado pelo SyncEngine ao receber confirmação do Core.\r\n */\r\n async markApplied(mutationId: string): Promise<void> {\r\n await this.store.deleteMutation(mutationId);\r\n }\r\n\r\n /**\r\n * Marca uma mutação como `failed` e registra o erro.\r\n * Incrementa `attempts`. Chamado pelo SyncEngine em falha permanente.\r\n */\r\n async markFailed(mutationId: string, error: string): Promise<void> {\r\n const mut = await this.store.getMutation(mutationId);\r\n if (!mut) return;\r\n await this.store.putMutation({\r\n ...mut,\r\n status: 'failed',\r\n lastError: error,\r\n attempts: mut.attempts + 1,\r\n });\r\n }\r\n\r\n /**\r\n * Incrementa `attempts` e volta para `queued` (falha transiente com backoff).\r\n * Chamado pelo SyncEngine em falha transiente (5xx, timeout).\r\n */\r\n async markRetry(mutationId: string, error: string): Promise<void> {\r\n const mut = await this.store.getMutation(mutationId);\r\n if (!mut) return;\r\n await this.store.putMutation({\r\n ...mut,\r\n status: 'queued',\r\n lastError: error,\r\n attempts: mut.attempts + 1,\r\n });\r\n }\r\n}\r\n","/**\r\n * field-value.ts — Sentinels de escrita server-side para o Mundo Documentos.\r\n *\r\n * Resolve duas lacunas confirmadas (bug_05aedb8b) da superfície `client.db`:\r\n *\r\n * 1. **Timestamp resolvido no servidor** — antes deste módulo, o produto que\r\n * quisesse `createdAt`/`updatedAt` confiáveis tinha que usar `Date.now()`\r\n * no CLIENTE, que é spoofável e sofre clock-skew. Agora:\r\n *\r\n * await orders.add({ total: 99, createdAt: serverTimestamp() });\r\n *\r\n * O marcador atravessa o transporte REST como um objeto JSON namespaceado\r\n * e o Core o substitui por `FieldValue.serverTimestamp()` no momento da\r\n * escrita — relógio do SERVIDOR, não do cliente.\r\n *\r\n * 2. **Increment atômico** — antes, `update(id, { n: x+1 })` era read-modify-write\r\n * no cliente, sujeito a lost-update sob concorrência. Agora:\r\n *\r\n * await counters.update('global', { hits: increment(1) });\r\n *\r\n * O Core aplica `FieldValue.increment(1)` atomicamente no documento.\r\n *\r\n * ## Contrato de fio (wire format)\r\n *\r\n * Os sentinels são objetos JSON simples — sobrevivem `JSON.stringify` no\r\n * transporte REST e ao `IndexedDB structured clone` da camada offline:\r\n *\r\n * serverTimestamp() → `{ \"__neetru__\": \"serverTimestamp\" }`\r\n * increment(n) → `{ \"__neetru__\": \"increment\", \"operand\": n }`\r\n *\r\n * A chave-âncora `__neetru__` é deliberadamente improvável de colidir com\r\n * dados de produto. O Core valida e resolve esses marcadores; qualquer objeto\r\n * com `__neetru__` desconhecido é rejeitado server-side (fail-closed).\r\n *\r\n * ## Aplicação otimista (offline-first)\r\n *\r\n * A camada offline aplica uma APROXIMAÇÃO local imediata (para a UI não piscar):\r\n * - `serverTimestamp()` → `Date.now()` local (substituído pelo valor real no sync).\r\n * - `increment(n)` → soma `n` ao valor numérico atual do campo (0 se ausente).\r\n * O valor canônico vem sempre do servidor no pull/confirm subsequente.\r\n *\r\n * @module\r\n */\r\n\r\n/** Chave-âncora dos marcadores de sentinel no wire format. */\r\nexport const NEETRU_SENTINEL_KEY = '__neetru__' as const;\r\n\r\n/** Marcador de timestamp resolvido pelo servidor. */\r\nexport interface ServerTimestampSentinel {\r\n readonly __neetru__: 'serverTimestamp';\r\n}\r\n\r\n/** Marcador de incremento atômico aplicado pelo servidor. */\r\nexport interface IncrementSentinel {\r\n readonly __neetru__: 'increment';\r\n /** Delta a somar (pode ser negativo para decremento). */\r\n readonly operand: number;\r\n}\r\n\r\n/**\r\n * União de todos os sentinels de campo. Use `serverTimestamp()` / `increment()`\r\n * para construir — nunca monte o objeto à mão.\r\n */\r\nexport type FieldSentinel = ServerTimestampSentinel | IncrementSentinel;\r\n\r\n/**\r\n * Sentinel que instrui o servidor a gravar o timestamp do MOMENTO da escrita\r\n * usando o relógio do servidor (não do cliente).\r\n *\r\n * @example\r\n * ```ts\r\n * import { serverTimestamp } from '@neetru/sdk/db';\r\n * await orders.add({ total: 99, createdAt: serverTimestamp() });\r\n * ```\r\n */\r\nexport function serverTimestamp(): ServerTimestampSentinel {\r\n return { __neetru__: 'serverTimestamp' };\r\n}\r\n\r\n/**\r\n * Sentinel que instrui o servidor a incrementar atomicamente o campo numérico\r\n * por `n` (negativo decrementa). Se o campo não existir/não for numérico, o\r\n * servidor o trata como `0` antes de somar (semântica `FieldValue.increment`).\r\n *\r\n * @param n — delta inteiro ou fracionário a somar.\r\n * @example\r\n * ```ts\r\n * import { increment } from '@neetru/sdk/db';\r\n * await counters.update('global', { hits: increment(1) });\r\n * await wallet.update(uid, { balance: increment(-50) });\r\n * ```\r\n */\r\nexport function increment(n: number): IncrementSentinel {\r\n if (typeof n !== 'number' || !Number.isFinite(n)) {\r\n throw new TypeError(\r\n `increment(n): n deve ser um número finito (recebido: ${String(n)}).`,\r\n );\r\n }\r\n return { __neetru__: 'increment', operand: n };\r\n}\r\n\r\n// ─── Type guards ────────────────────────────────────────────────────────────\r\n\r\n/** `true` se `v` é qualquer sentinel de campo Neetru. */\r\nexport function isFieldSentinel(v: unknown): v is FieldSentinel {\r\n return (\r\n typeof v === 'object' &&\r\n v !== null &&\r\n NEETRU_SENTINEL_KEY in v &&\r\n typeof (v as Record<string, unknown>)[NEETRU_SENTINEL_KEY] === 'string'\r\n );\r\n}\r\n\r\n/** `true` se `v` é o sentinel `serverTimestamp()`. */\r\nexport function isServerTimestampSentinel(v: unknown): v is ServerTimestampSentinel {\r\n return isFieldSentinel(v) && v.__neetru__ === 'serverTimestamp';\r\n}\r\n\r\n/** `true` se `v` é o sentinel `increment(n)` com `operand` numérico válido. */\r\nexport function isIncrementSentinel(v: unknown): v is IncrementSentinel {\r\n return (\r\n isFieldSentinel(v) &&\r\n v.__neetru__ === 'increment' &&\r\n typeof (v as IncrementSentinel).operand === 'number' &&\r\n Number.isFinite((v as IncrementSentinel).operand)\r\n );\r\n}\r\n\r\n// ─── Aplicação otimista local (offline-first) ────────────────────────────────\r\n\r\n/**\r\n * Resolve sentinels para valores LOCAIS aproximados, para aplicação otimista\r\n * no cache offline. O valor canônico vem sempre do servidor no sync seguinte.\r\n *\r\n * - `serverTimestamp()` → `Date.now()` (epoch ms local).\r\n * - `increment(n)` → `baseValue` numérico atual (ou 0) + n.\r\n * - valores normais → retornados inalterados.\r\n *\r\n * @param value — o valor do campo (pode ser sentinel ou valor literal).\r\n * @param baseValue — valor atual do campo no doc existente (para increment).\r\n */\r\nexport function resolveSentinelLocally(value: unknown, baseValue: unknown): unknown {\r\n if (isServerTimestampSentinel(value)) {\r\n return Date.now();\r\n }\r\n if (isIncrementSentinel(value)) {\r\n const base = typeof baseValue === 'number' && Number.isFinite(baseValue) ? baseValue : 0;\r\n return base + value.operand;\r\n }\r\n return value;\r\n}\r\n\r\n/**\r\n * Aplica `resolveSentinelLocally` a cada campo top-level de `data`, usando\r\n * `existing` como base para increments. Não recursa em objetos aninhados\r\n * (sentinels só são suportados em campos top-level, espelhando a resolução\r\n * top-level do Core).\r\n *\r\n * @param data — payload da mutação (pode conter sentinels).\r\n * @param existing — dados atuais do documento (para base de increment).\r\n */\r\nexport function resolveSentinelsLocally(\r\n data: Record<string, unknown>,\r\n existing: Record<string, unknown> | undefined,\r\n): Record<string, unknown> {\r\n let touched = false;\r\n const out: Record<string, unknown> = {};\r\n for (const [k, v] of Object.entries(data)) {\r\n if (isFieldSentinel(v)) {\r\n touched = true;\r\n out[k] = resolveSentinelLocally(v, existing?.[k]);\r\n } else {\r\n out[k] = v;\r\n }\r\n }\r\n // Micro-opt: se nenhum sentinel, devolve o objeto original (evita realocar).\r\n return touched ? out : data;\r\n}\r\n\r\n/** `true` se algum campo top-level de `data` é um sentinel. */\r\nexport function hasFieldSentinel(data: Record<string, unknown>): boolean {\r\n for (const v of Object.values(data)) {\r\n if (isFieldSentinel(v)) return true;\r\n }\r\n return false;\r\n}\r\n","/**\r\n * SyncEngine — orquestrador da camada offline do @neetru/sdk.\r\n *\r\n * Implementa as 3 fases de sincronização definidas em I3 §6:\r\n *\r\n * FASE 1 — DRENAR A FILA (push)\r\n * Envia mutações pendentes ao Core via SyncTransport.\r\n * Cada mutação é marcada inflight, enviada e depois:\r\n * - CONFIRMADA → removida da fila (markApplied)\r\n * - SUPERADA (LWW)→ ConflictRecord gravado, cache atualizado\r\n * - REJEITADA → resolveRejected + ConflictRecord + removida\r\n * - FALHA TRANSIENTE → markRetry + PARA a drenagem (ordem preservada)\r\n *\r\n * FASE 2 — RECONCILIAR O CACHE (pull)\r\n * Busca mudanças do servidor desde o watermark ou resume token.\r\n * Cada documento passa pelo ConflictResolver (LWW) e é gravado no LocalStore.\r\n * Changes são emitidos pelo ChangeBus.\r\n * Se `resyncRequired` → aciona full resync em vez de pull incremental.\r\n *\r\n * FASE 3 — REABRIR LISTENERS (realtime)\r\n * Atualiza SyncState para refletir que o cache está reconciliado.\r\n * O ChangeBus já foi alimentado nas fases anteriores — os listeners\r\n * ativos na camada superior (onSnapshot/onDoc) recebem snapshots frescos.\r\n *\r\n * Garantias:\r\n * - SOMENTE a aba LÍDER executa o sync (TabCoordinator.isLeader()).\r\n * - Re-entrante-safe: um sync em progresso bloqueia novos disparos.\r\n * - Fail-closed: falha transiente retém a mutação; falha de pull não\r\n * corrompe o cache nem o watermark.\r\n * - Idempotente: o SyncTransport usa mutationId como chave de idempotência.\r\n *\r\n * O SyncTransport é INJETADO — a ligação real com o Core acontece na camada\r\n * de adaptação, não aqui. Isso torna o SyncEngine 100% testável com fake.\r\n */\r\n\r\nimport type { LocalStore } from './local-store';\r\nimport type { MutationQueue } from './mutation-queue';\r\nimport type { ConflictResolver } from './conflict-resolver';\r\nimport type { ChangeBus } from './change-bus';\r\nimport type { Mutation, SyncState, Change, Unsubscribe } from './types';\r\nimport { isFieldSentinel, hasFieldSentinel } from '../field-value';\r\n\r\n// ─── Helpers de sentinel (defesa do cache contra marcadores crus) ─────────────\r\n\r\n/** `true` se o payload da mutação contém ao menos um sentinel cru top-level. */\r\nfunction hasSentinels(payload: Record<string, unknown> | null): boolean {\r\n return payload !== null && hasFieldSentinel(payload);\r\n}\r\n\r\n/**\r\n * Remove campos-sentinel CRUS (`{__neetru__:...}`) de um payload de mutação,\r\n * devolvendo só os campos LITERAIS. Garante que um marcador cru nunca aterre no\r\n * LocalStore num confirm que não trouxe `serverData`.\r\n *\r\n * - `null` → `null` (passa direto; ex.: `remove`).\r\n * - sem sentinel → devolve o mesmo objeto (evita realocar).\r\n * - com sentinel → novo objeto só com os campos literais (sentinels DROPADOS;\r\n * a aproximação otimista deles já vive em `existing.data`).\r\n */\r\nfunction sanitizeSentinelPayload(\r\n payload: Record<string, unknown> | null,\r\n): Record<string, unknown> | null {\r\n if (payload === null) return null;\r\n if (!hasFieldSentinel(payload)) return payload;\r\n const out: Record<string, unknown> = {};\r\n for (const [k, v] of Object.entries(payload)) {\r\n if (!isFieldSentinel(v)) out[k] = v;\r\n }\r\n return out;\r\n}\r\n\r\n// ─── SyncTransport — interface injetável ──────────────────────────────────────\r\n\r\n/**\r\n * Documento retornado pelo servidor em push/pull/resync.\r\n */\r\nexport interface ServerDoc {\r\n collection: string;\r\n id: string;\r\n data: Record<string, unknown>;\r\n serverVersion: string;\r\n serverTimestamp: number;\r\n /** `true` se o doc foi deletado no servidor. */\r\n deleted: boolean;\r\n}\r\n\r\n/**\r\n * Resultado individual de uma mutação enviada ao Core (FASE 1).\r\n */\r\nexport type MutationResult =\r\n | {\r\n mutationId: string;\r\n outcome: 'confirmed';\r\n serverVersion: string;\r\n serverTimestamp: number;\r\n }\r\n | {\r\n mutationId: string;\r\n outcome: 'superseded';\r\n serverVersion: string;\r\n serverTimestamp: number;\r\n serverData: Record<string, unknown>;\r\n }\r\n | {\r\n mutationId: string;\r\n outcome: 'rejected';\r\n reason: 'rejected_permission' | 'rejected_validation';\r\n serverVersion: string | null;\r\n serverData: Record<string, unknown> | null;\r\n };\r\n\r\n/** Retorno de pushMutations. */\r\nexport interface PushMutationsResult {\r\n results: MutationResult[];\r\n}\r\n\r\n/** Retorno de pullChanges. */\r\nexport interface PullChangesResult {\r\n docs: ServerDoc[];\r\n newWatermark: number | null;\r\n /** `true` quando o resume token / watermark ficou inválido (gap grande). */\r\n resyncRequired: boolean;\r\n}\r\n\r\n/** Retorno de fullResync. */\r\nexport interface FullResyncResult {\r\n docs: ServerDoc[];\r\n newWatermark: number | null;\r\n}\r\n\r\n/**\r\n * Contrato do transporte de sync — injetado no SyncEngine.\r\n *\r\n * A implementação real usa os endpoints `/api/sdk/v1/db/*` do Core.\r\n * Em testes, usa-se um FakeSyncTransport.\r\n *\r\n * Per I3 §6:\r\n * - `pushMutations` → FASE 1: envia mutações em ordem de seq.\r\n * - `pullChanges` → FASE 2: busca delta desde o watermark/resumeToken.\r\n * - `fullResync` → FASE 2 (fallback): lista completa das coleções ativas.\r\n */\r\nexport interface SyncTransport {\r\n /**\r\n * Envia um lote de mutações ao Core.\r\n * O Core aplica, verifica conflito LWW e retorna um resultado por mutação.\r\n * A ordem do array deve ser preservada (seq crescente).\r\n */\r\n pushMutations(mutations: Mutation[]): Promise<PushMutationsResult>;\r\n\r\n /**\r\n * Busca documentos modificados no servidor desde `sinceWatermark`.\r\n * `sinceWatermark === null` indica primeiro sync (sem base conhecida).\r\n * `resumeToken` é o token de change stream (nosql-vm); pode ser null.\r\n *\r\n * Retorna `resyncRequired: true` se o gap é grande demais para pull incremental.\r\n */\r\n pullChanges(\r\n sinceWatermark: number | null,\r\n resumeToken: string | null,\r\n ): Promise<PullChangesResult>;\r\n\r\n /**\r\n * Faz um full resync das coleções informadas.\r\n * Retorna TODOS os documentos atuais (paginado internamente pelo transporte).\r\n * Docs ausentes na resposta foram deletados durante o gap.\r\n */\r\n fullResync(collections: string[]): Promise<FullResyncResult>;\r\n\r\n /**\r\n * (Opcional) Registra uma subscription realtime para uma coleção específica.\r\n *\r\n * Implementado pelo WebSocket transport (nosql-vm): chama\r\n * `NeetruRealtimeClient.subscribe()` e alimenta os frames delta/resync\r\n * no `ChangeBus` da camada offline.\r\n *\r\n * Transportes REST e Firestore não implementam este método (undefined).\r\n * O chamador (`DbCollectionRefImpl.onSnapshot`) verifica antes de invocar.\r\n *\r\n * @param collection - Nome da coleção a subscrever.\r\n * @param onChange - Callback que recebe changes quando um delta/resync chega.\r\n * `null` payload = resync full necessário.\r\n * @returns Função de unsubscribe.\r\n */\r\n subscribeCollection?: (\r\n collection: string,\r\n onChange: (\r\n changes: Array<{ type: 'added' | 'modified' | 'removed'; docId: string; data: Record<string, unknown> | null }>,\r\n needsResync: boolean,\r\n ) => void,\r\n ) => () => void;\r\n}\r\n\r\n// ─── Interface dos colaboradores (subset usado pelo SyncEngine) ───────────────\r\n\r\n/** Subset de TabCoordinator usado pelo SyncEngine. */\r\ninterface TabCoordinatorLike {\r\n isLeader(): boolean;\r\n onRoleChange(cb: (role: 'leader' | 'follower') => void): Unsubscribe;\r\n}\r\n\r\n/** Subset de ConnectivityMonitor usado pelo SyncEngine. */\r\ninterface ConnectivityMonitorLike {\r\n readonly isOnline: boolean;\r\n subscribe(cb: (state: 'online' | 'offline') => void): Unsubscribe;\r\n}\r\n\r\n// ─── Opções de configuração ───────────────────────────────────────────────────\r\n\r\nexport interface SyncEngineOptions {\r\n store: LocalStore;\r\n queue: MutationQueue;\r\n resolver: ConflictResolver;\r\n bus: ChangeBus;\r\n transport: SyncTransport;\r\n tabCoordinator: TabCoordinatorLike;\r\n connectivity: ConnectivityMonitorLike;\r\n /**\r\n * Intervalo do resync periódico em ms.\r\n * `0` desativa (útil em testes). Default: 5 * 60 * 1000 (5 min).\r\n */\r\n periodicSyncIntervalMs?: number;\r\n}\r\n\r\n// ─── SyncEngine ───────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * SyncEngine — orquestra as 3 fases de sincronização offline (I3 §6).\r\n *\r\n * ```ts\r\n * const engine = new SyncEngine({ store, queue, resolver, bus, transport,\r\n * tabCoordinator, connectivity });\r\n *\r\n * // Estado atual (snapshot síncrono)\r\n * const state = engine.getSyncState();\r\n *\r\n * // Observar mudanças de estado\r\n * const unsub = engine.onSyncStateChange((s) => console.log(s));\r\n *\r\n * // Forçar sync imediato (ex.: botão \"sincronizar agora\")\r\n * await engine.flush();\r\n *\r\n * // Teardown\r\n * engine.destroy();\r\n * ```\r\n *\r\n * O engine também é disparado automaticamente por:\r\n * - transição offline → online (ConnectivityMonitor)\r\n * - promoção a líder (TabCoordinator.onRoleChange)\r\n * - periodicSyncIntervalMs (resync de segurança)\r\n */\r\nexport class SyncEngine {\r\n private readonly _store: LocalStore;\r\n private readonly _queue: MutationQueue;\r\n private readonly _resolver: ConflictResolver;\r\n private readonly _bus: ChangeBus;\r\n private readonly _transport: SyncTransport;\r\n private readonly _tabCoordinator: TabCoordinatorLike;\r\n private readonly _connectivity: ConnectivityMonitorLike;\r\n\r\n /** `true` se um sync está atualmente em progresso — guarda re-entrância. */\r\n private _syncing = false;\r\n\r\n /** `true` se destroy() foi chamado. */\r\n private _destroyed = false;\r\n\r\n /**\r\n * Conjunto de coleções \"conhecidas\" pelo engine.\r\n * Populado ao aplicar docs do servidor (Fase 1 e 2) e ao ler do cache.\r\n * Persiste em sync_meta['activeCollections'] para sobreviver a reloads.\r\n */\r\n private _activeCollections = new Set<string>();\r\n\r\n /** Estado de sync atual (fonte de verdade em RAM). */\r\n private _state: SyncState;\r\n\r\n /** Listeners de mudança de SyncState. */\r\n private readonly _stateListeners = new Set<(state: SyncState) => void>();\r\n\r\n /** Cleanup functions dos listeners externos. */\r\n private readonly _cleanups: Unsubscribe[] = [];\r\n\r\n /** Timer de resync periódico. */\r\n private _periodicTimer: ReturnType<typeof setInterval> | null = null;\r\n\r\n constructor(opts: SyncEngineOptions) {\r\n this._store = opts.store;\r\n this._queue = opts.queue;\r\n this._resolver = opts.resolver;\r\n this._bus = opts.bus;\r\n this._transport = opts.transport;\r\n this._tabCoordinator = opts.tabCoordinator;\r\n this._connectivity = opts.connectivity;\r\n\r\n // Estado inicial\r\n this._state = this._buildInitialState();\r\n\r\n // Conecta os gatilhos externos\r\n this._wireListeners();\r\n\r\n // Timer periódico\r\n const intervalMs = opts.periodicSyncIntervalMs ?? 5 * 60 * 1000;\r\n if (intervalMs > 0) {\r\n this._periodicTimer = setInterval(() => {\r\n this._triggerSync('periodic');\r\n }, intervalMs);\r\n }\r\n }\r\n\r\n // ─── API pública ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Expõe o transporte de sync para acesso direto por `DbCollectionRefImpl`.\r\n * Necessário para que `onSnapshot` possa chamar `subscribeCollection` no\r\n * transport nosql-vm (HIGH-1 fix — realtime deltas).\r\n */\r\n get transport(): SyncTransport {\r\n return this._transport;\r\n }\r\n\r\n /**\r\n * Retorna o estado de sync atual (snapshot síncrono).\r\n * Equivale a `client.db.syncState` na API pública do SDK (I3 §10.3).\r\n *\r\n * `pendingWrites` reflete o valor mais recente calculado de forma assíncrona.\r\n * Para garantir o valor mais atualizado, aguarde `refreshPendingWrites()` antes.\r\n */\r\n getSyncState(): SyncState {\r\n return { ...this._state };\r\n }\r\n\r\n /**\r\n * Força a atualização de `pendingWrites` e retorna o estado atualizado.\r\n * Útil quando o chamador precisa do pendingWrites fresco sem aguardar um sync.\r\n */\r\n async refreshPendingWrites(): Promise<SyncState> {\r\n await this._refreshPendingWrites();\r\n return { ...this._state };\r\n }\r\n\r\n /**\r\n * Registra um listener de mudanças no SyncState.\r\n * Retorna uma função de unsubscribe.\r\n */\r\n onSyncStateChange(cb: (state: SyncState) => void): Unsubscribe {\r\n this._stateListeners.add(cb);\r\n return () => {\r\n this._stateListeners.delete(cb);\r\n };\r\n }\r\n\r\n /**\r\n * Força um sync imediato (I3 §10.3 `flush()`).\r\n * Resolve quando a fila esvazia OU rejeita se o engine estiver destruído.\r\n */\r\n async flush(): Promise<void> {\r\n if (this._destroyed) return;\r\n await this.sync();\r\n }\r\n\r\n /**\r\n * Executa as 3 fases de sincronização.\r\n *\r\n * Guarda re-entrância: se já está em progresso, retorna imediatamente.\r\n * NÃO executa se esta aba não é líder ou se está offline.\r\n */\r\n async sync(): Promise<void> {\r\n if (this._destroyed) return;\r\n\r\n // Somente o líder sincroniza (I3 §6.1)\r\n if (!this._tabCoordinator.isLeader()) return;\r\n\r\n // Offline — não tenta sincronizar\r\n if (!this._connectivity.isOnline) return;\r\n\r\n // Re-entrância: não double-run\r\n if (this._syncing) return;\r\n\r\n this._syncing = true;\r\n this._updateState({ status: 'syncing' });\r\n\r\n try {\r\n // ── FASE 1: DRENAR A FILA (push) ────────────────────────────────────────\r\n const phase1Ok = await this._phase1Push();\r\n if (!phase1Ok) {\r\n // Falha transiente na Fase 1 — aborta o ciclo (I3 §6.2: PARA a drenagem).\r\n // bug: sem refresh o pendingWrites ficava desatualizado após markRetry()\r\n this._updateState({ status: 'idle' });\r\n this._refreshPendingWrites().catch(() => {});\r\n this._syncing = false;\r\n return;\r\n }\r\n\r\n // ── FASE 2: RECONCILIAR O CACHE (pull) ──────────────────────────────────\r\n await this._phase2Pull();\r\n\r\n // ── FASE 3: REABRIR LISTENERS (realtime) ─────────────────────────────────\r\n this._phase3Realtime();\r\n\r\n // Atualiza lastSyncedAt\r\n this._updateState({ status: 'idle', lastSyncedAt: Date.now() });\r\n } catch (err) {\r\n // Erro inesperado nas fases — log silencioso, estado de erro\r\n this._updateState({ status: 'idle' });\r\n } finally {\r\n this._syncing = false;\r\n }\r\n }\r\n\r\n /**\r\n * Teardown: para timers, remove listeners, marca como destroyed.\r\n */\r\n destroy(): void {\r\n if (this._destroyed) return;\r\n this._destroyed = true;\r\n\r\n if (this._periodicTimer !== null) {\r\n clearInterval(this._periodicTimer);\r\n this._periodicTimer = null;\r\n }\r\n\r\n for (const cleanup of this._cleanups) {\r\n try { cleanup(); } catch { /* silencioso */ }\r\n }\r\n this._cleanups.length = 0;\r\n this._stateListeners.clear();\r\n }\r\n\r\n // ─── FASE 1 — push (drenar a fila) ───────────────────────────────────────────\r\n\r\n /**\r\n * Drena a MutationQueue, enviando mutações em ordem de seq.\r\n *\r\n * Retorna `true` se a fase completou sem falhas transientes.\r\n * Retorna `false` se houve falha transiente (ciclo deve ser abortado).\r\n */\r\n private async _phase1Push(): Promise<boolean> {\r\n const mutations = await this._queue.drain();\r\n if (mutations.length === 0) return true;\r\n\r\n // Marca todas como inflight\r\n for (const mut of mutations) {\r\n await this._queue.markInflight(mut.mutationId);\r\n }\r\n\r\n let result: PushMutationsResult;\r\n try {\r\n result = await this._transport.pushMutations(mutations);\r\n } catch (err) {\r\n // Falha transiente no transporte — volta todas para queued\r\n for (const mut of mutations) {\r\n const errMsg = err instanceof Error ? err.message : String(err);\r\n await this._queue.markRetry(mut.mutationId, errMsg);\r\n }\r\n return false; // aborta o ciclo\r\n }\r\n\r\n // Processa resultados\r\n const busChanges: Change[] = [];\r\n\r\n for (const res of result.results) {\r\n const mut = mutations.find((m) => m.mutationId === res.mutationId);\r\n if (!mut) continue;\r\n\r\n if (res.outcome === 'confirmed') {\r\n // Sucesso — remove da fila e atualiza doc no cache\r\n await this._queue.markApplied(mut.mutationId);\r\n await this._applySyncedDoc(\r\n mut.collection,\r\n mut.docId,\r\n res.serverVersion,\r\n res.serverTimestamp,\r\n mut,\r\n busChanges,\r\n );\r\n } else if (res.outcome === 'superseded') {\r\n // LWW: escrita local foi superada pelo servidor\r\n await this._queue.markApplied(mut.mutationId);\r\n await this._applySuperseded(mut, res, busChanges);\r\n } else if (res.outcome === 'rejected') {\r\n // Rejeição permanente\r\n await this._queue.markApplied(mut.mutationId); // remove da fila\r\n await this._applyRejected(mut, res, busChanges);\r\n }\r\n }\r\n\r\n if (busChanges.length > 0) {\r\n this._bus.emit(busChanges);\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /** Atualiza o cache após confirmação de escrita (outcome=confirmed). */\r\n private async _applySyncedDoc(\r\n collection: string,\r\n docId: string,\r\n serverVersion: string,\r\n serverTimestamp: number,\r\n mut: Mutation,\r\n busChanges: Change[],\r\n ): Promise<void> {\r\n const existing = await this._store.getDoc(collection, docId);\r\n\r\n if (mut.op === 'remove') {\r\n // Remoção confirmada → tombstone\r\n if (existing) {\r\n await this._store.putDoc({\r\n ...existing,\r\n meta: {\r\n ...existing.meta,\r\n serverVersion,\r\n updatedAtServer: serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced',\r\n deleted: true,\r\n pendingMutationIds: [],\r\n },\r\n });\r\n busChanges.push({ type: 'removed', collection, doc: { id: docId, data: existing.data } });\r\n }\r\n return;\r\n }\r\n\r\n // O payload da mutação carrega os sentinels CRUS (`serverTimestamp()` /\r\n // `increment()`) — eles existem só para o Core resolver no wire. Um outcome\r\n // 'confirmed' traz apenas serverVersion/serverTimestamp, NUNCA serverData, então\r\n // NÃO podemos gravar `mut.payload` cru no cache: isso vazaria `{__neetru__:...}`\r\n // para qualquer get()/onSnapshot() lido antes do próximo pull completo.\r\n //\r\n // O cache local JÁ contém a aproximação otimista escrita em add()/set()/update()\r\n // (números/timestamps, base de increment já somada). Quando o payload tem\r\n // sentinels, preservamos esse `existing.data` otimista em vez de re-resolver\r\n // (re-resolver contra `existing.data` somaria o increment de novo — double-count).\r\n // Só campos LITERAIS do payload são re-aplicados por cima (merge p/ update).\r\n const literalPayload = sanitizeSentinelPayload(mut.payload);\r\n const newData = literalPayload ?? (existing?.data ?? {});\r\n const updatedDoc = {\r\n collection,\r\n id: docId,\r\n data:\r\n mut.op === 'update'\r\n ? { ...(existing?.data ?? {}), ...newData }\r\n : // add/set: se o payload tinha sentinels, o cache otimista (existing.data)\r\n // é a fonte de verdade até o pull; senão usa o payload literal.\r\n hasSentinels(mut.payload)\r\n ? { ...(existing?.data ?? {}), ...newData }\r\n : newData,\r\n meta: {\r\n serverVersion,\r\n updatedAtServer: serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced' as const,\r\n pendingMutationIds: [],\r\n deleted: false,\r\n ownerId: existing?.meta.ownerId ?? null,\r\n },\r\n };\r\n\r\n await this._store.putDoc(updatedDoc);\r\n busChanges.push({\r\n type: existing ? 'modified' : 'added',\r\n collection,\r\n doc: { id: docId, data: updatedDoc.data },\r\n });\r\n }\r\n\r\n /** Processa resultado 'superseded' (LWW: servidor venceu). */\r\n private async _applySuperseded(\r\n mut: Mutation,\r\n res: Extract<MutationResult, { outcome: 'superseded' }>,\r\n busChanges: Change[],\r\n ): Promise<void> {\r\n const localDoc = await this._store.getDoc(mut.collection, mut.docId);\r\n\r\n // Constrói envelope do servidor com timestamp maior para forçar server_wins\r\n const serverDocEnvelope = {\r\n collection: mut.collection,\r\n id: mut.docId,\r\n data: res.serverData,\r\n meta: {\r\n serverVersion: res.serverVersion,\r\n updatedAtServer: res.serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced' as const,\r\n pendingMutationIds: [],\r\n deleted: false,\r\n ownerId: localDoc?.meta.ownerId ?? null,\r\n },\r\n };\r\n\r\n // Usa ConflictResolver para gerar o ConflictRecord\r\n // Cria um doc local com updatedAtServer anterior para garantir server_wins\r\n const localDocForResolver = localDoc ?? {\r\n collection: mut.collection,\r\n id: mut.docId,\r\n data: (mut.payload ?? {}) as Record<string, unknown>,\r\n meta: {\r\n serverVersion: mut.baseVersion,\r\n updatedAtServer: res.serverTimestamp - 1, // garante server é mais novo\r\n updatedAtLocal: mut.enqueuedAt,\r\n state: 'pending' as const,\r\n pendingMutationIds: [mut.mutationId],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n };\r\n\r\n const resolveResult = this._resolver.resolve(\r\n localDocForResolver,\r\n serverDocEnvelope,\r\n mut,\r\n );\r\n\r\n // Sempre grava ConflictRecord em superseded (independente do resultado do resolver)\r\n const conflictRecord = resolveResult.conflictRecord ?? {\r\n collection: mut.collection,\r\n docId: mut.docId,\r\n mutationId: mut.mutationId,\r\n losingData: (mut.payload ?? {}) as Record<string, unknown>,\r\n winningData: res.serverData,\r\n reason: 'lww_server_newer' as const,\r\n detectedAt: Date.now(),\r\n delivered: false,\r\n };\r\n await this._store.appendConflict(conflictRecord);\r\n\r\n // Atualiza cache com o dado do servidor\r\n const updatedDoc = {\r\n collection: mut.collection,\r\n id: mut.docId,\r\n data: res.serverData,\r\n meta: {\r\n serverVersion: res.serverVersion,\r\n updatedAtServer: res.serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced' as const,\r\n pendingMutationIds: [],\r\n deleted: false,\r\n ownerId: localDoc?.meta.ownerId ?? null,\r\n },\r\n };\r\n await this._store.putDoc(updatedDoc);\r\n busChanges.push({\r\n type: localDoc ? 'modified' : 'added',\r\n collection: mut.collection,\r\n doc: { id: mut.docId, data: res.serverData },\r\n });\r\n }\r\n\r\n /** Processa resultado 'rejected' (permissão/validação negada). */\r\n private async _applyRejected(\r\n mut: Mutation,\r\n res: Extract<MutationResult, { outcome: 'rejected' }>,\r\n busChanges: Change[],\r\n ): Promise<void> {\r\n // Obtém ou reconstrói o doc local para o resolver\r\n const storedDoc = await this._store.getDoc(mut.collection, mut.docId);\r\n const localDoc = storedDoc ?? {\r\n collection: mut.collection,\r\n id: mut.docId,\r\n data: (mut.payload ?? {}) as Record<string, unknown>,\r\n meta: {\r\n serverVersion: mut.baseVersion,\r\n updatedAtServer: null,\r\n updatedAtLocal: mut.enqueuedAt,\r\n state: 'pending' as const,\r\n pendingMutationIds: [mut.mutationId],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n };\r\n\r\n const serverDocEnvelope = res.serverData\r\n ? {\r\n ...localDoc,\r\n data: res.serverData,\r\n meta: {\r\n ...localDoc.meta,\r\n serverVersion: res.serverVersion ?? localDoc.meta.serverVersion,\r\n },\r\n }\r\n : null;\r\n\r\n const resolveResult = this._resolver.resolveRejected(\r\n localDoc,\r\n serverDocEnvelope,\r\n mut,\r\n res.reason,\r\n );\r\n\r\n // Sempre grava ConflictRecord em rejected\r\n const conflictRecord = resolveResult.conflictRecord ?? {\r\n collection: mut.collection,\r\n docId: mut.docId,\r\n mutationId: mut.mutationId,\r\n losingData: (mut.payload ?? {}) as Record<string, unknown>,\r\n winningData: (res.serverData ?? {}) as Record<string, unknown>,\r\n reason: res.reason,\r\n detectedAt: Date.now(),\r\n delivered: false,\r\n };\r\n await this._store.appendConflict(conflictRecord);\r\n\r\n // Reverte cache ao estado do servidor (ou mantém se não há serverData)\r\n if (res.serverData) {\r\n await this._store.putDoc({\r\n ...localDoc,\r\n data: res.serverData,\r\n meta: {\r\n ...localDoc.meta,\r\n state: 'synced',\r\n pendingMutationIds: [],\r\n },\r\n });\r\n busChanges.push({\r\n type: 'modified',\r\n collection: mut.collection,\r\n doc: { id: mut.docId, data: res.serverData },\r\n });\r\n } else {\r\n // Sem dado do servidor → mantém o que há, mas limpa pendências\r\n await this._store.putDoc({\r\n ...localDoc,\r\n meta: {\r\n ...localDoc.meta,\r\n state: 'synced',\r\n pendingMutationIds: [],\r\n },\r\n });\r\n }\r\n }\r\n\r\n // ─── FASE 2 — pull (reconciliar o cache) ─────────────────────────────────────\r\n\r\n /**\r\n * Busca mudanças do servidor e aplica ao cache via ConflictResolver.\r\n *\r\n * Se `resyncRequired === true`, faz full resync em vez de pull incremental.\r\n */\r\n private async _phase2Pull(): Promise<void> {\r\n const watermark = (await this._store.getMeta('lastSyncWatermark')) as number | null;\r\n const resumeToken = (await this._store.getMeta('lastResumeToken')) as string | null;\r\n\r\n let pullResult: PullChangesResult;\r\n try {\r\n pullResult = await this._transport.pullChanges(watermark, resumeToken);\r\n } catch {\r\n // Falha no pull — não corrompe cache nem watermark; tenta no próximo ciclo\r\n return;\r\n }\r\n\r\n if (pullResult.resyncRequired) {\r\n await this._phase2FullResync();\r\n return;\r\n }\r\n\r\n // Pull incremental bem-sucedido\r\n const busChanges: Change[] = [];\r\n await this._applyServerDocs(pullResult.docs, busChanges, false);\r\n\r\n if (pullResult.newWatermark !== null) {\r\n await this._store.setMeta('lastSyncWatermark', pullResult.newWatermark);\r\n }\r\n\r\n if (busChanges.length > 0) {\r\n this._bus.emit(busChanges);\r\n }\r\n }\r\n\r\n /** Full resync: lista completa + detecta deleções por ausência. */\r\n private async _phase2FullResync(): Promise<void> {\r\n // Coleta as coleções que têm documentos no cache local\r\n const collections = await this._getActiveCollections();\r\n\r\n let resyncResult: FullResyncResult;\r\n try {\r\n resyncResult = await this._transport.fullResync(collections);\r\n } catch {\r\n // Falha no resync — não corrompe cache; tenta no próximo ciclo\r\n return;\r\n }\r\n\r\n const busChanges: Change[] = [];\r\n\r\n // Aplica os docs retornados\r\n await this._applyServerDocs(resyncResult.docs, busChanges, true);\r\n\r\n // Detecta deleções: docs locais que não vieram no resync → tombstone (I3 §6.3)\r\n const returnedKeys = new Set(\r\n resyncResult.docs.map((d) => `${d.collection}::${d.id}`),\r\n );\r\n\r\n for (const col of collections) {\r\n // listDocs retorna { id, data } sem meta — precisamos dos docs completos\r\n const queryResult = await this._store.listDocs(col, {});\r\n for (const { id } of queryResult.docs) {\r\n const key = `${col}::${id}`;\r\n if (!returnedKeys.has(key)) {\r\n // Busca o doc completo com meta para verificar e atualizar\r\n const fullDoc = await this._store.getDoc(col, id);\r\n if (fullDoc && !fullDoc.meta.deleted) {\r\n // Doc sumiu do servidor → tombstone\r\n await this._store.putDoc({\r\n ...fullDoc,\r\n meta: {\r\n ...fullDoc.meta,\r\n deleted: true,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced',\r\n },\r\n });\r\n busChanges.push({\r\n type: 'removed',\r\n collection: col,\r\n doc: { id, data: fullDoc.data },\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (resyncResult.newWatermark !== null) {\r\n await this._store.setMeta('lastSyncWatermark', resyncResult.newWatermark);\r\n }\r\n await this._store.setMeta('lastFullResyncAt', Date.now());\r\n\r\n if (busChanges.length > 0) {\r\n this._bus.emit(busChanges);\r\n }\r\n }\r\n\r\n /**\r\n * Aplica uma lista de ServerDoc ao cache local via ConflictResolver.\r\n *\r\n * `isFullResync = true` indica que o conjunto é completo — usamos isso para\r\n * otimizar a path (sempre sobrescreve docs synced; pending passam pelo LWW).\r\n */\r\n private async _applyServerDocs(\r\n docs: ServerDoc[],\r\n busChanges: Change[],\r\n _isFullResync: boolean,\r\n ): Promise<void> {\r\n for (const serverDoc of docs) {\r\n const localDoc = await this._store.getDoc(serverDoc.collection, serverDoc.id);\r\n\r\n if (serverDoc.deleted) {\r\n // Doc deletado no servidor → tombstone\r\n if (localDoc && !localDoc.meta.deleted) {\r\n await this._store.putDoc({\r\n ...localDoc,\r\n meta: {\r\n ...localDoc.meta,\r\n deleted: true,\r\n serverVersion: serverDoc.serverVersion,\r\n updatedAtServer: serverDoc.serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced',\r\n },\r\n });\r\n busChanges.push({\r\n type: 'removed',\r\n collection: serverDoc.collection,\r\n doc: { id: serverDoc.id, data: localDoc.data },\r\n });\r\n }\r\n continue;\r\n }\r\n\r\n // Se o doc local está 'pending' (tem mutações não enviadas ainda),\r\n // passa pelo ConflictResolver (§6.2: não sobrescreve cegamente).\r\n // Na prática, após a Fase 1 a maioria dos pendentes já virou synced.\r\n if (localDoc && localDoc.meta.state === 'pending') {\r\n // Constrói envelope do servidor para o resolver\r\n const serverEnvelope = {\r\n collection: serverDoc.collection,\r\n id: serverDoc.id,\r\n data: serverDoc.data,\r\n meta: {\r\n serverVersion: serverDoc.serverVersion,\r\n updatedAtServer: serverDoc.serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced' as const,\r\n pendingMutationIds: [],\r\n deleted: false,\r\n ownerId: localDoc.meta.ownerId,\r\n },\r\n };\r\n\r\n // Busca a primeira mutação pendente para este doc (para o resolver).\r\n // bug: drain() retorna só 'queued', perdendo mutações 'inflight' — usar listAll()\r\n const pendingMuts = await this._queue.listAll();\r\n const docMut = pendingMuts.find(\r\n (m) => m.collection === serverDoc.collection && m.docId === serverDoc.id,\r\n );\r\n\r\n if (docMut) {\r\n const result = this._resolver.resolve(localDoc, serverEnvelope, docMut);\r\n if (result.conflictRecord) {\r\n await this._store.appendConflict(result.conflictRecord);\r\n }\r\n // Marca o doc como conflito para resolver na próxima Fase 1\r\n await this._store.putDoc({\r\n ...localDoc,\r\n meta: { ...localDoc.meta, state: 'conflict' },\r\n });\r\n continue;\r\n }\r\n }\r\n\r\n // Doc local synced ou não existente → sobrescreve com servidor\r\n const isNew = !localDoc;\r\n const newDoc = {\r\n collection: serverDoc.collection,\r\n id: serverDoc.id,\r\n data: serverDoc.data,\r\n meta: {\r\n serverVersion: serverDoc.serverVersion,\r\n updatedAtServer: serverDoc.serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced' as const,\r\n pendingMutationIds: [],\r\n deleted: false,\r\n ownerId: localDoc?.meta.ownerId ?? null,\r\n },\r\n };\r\n await this._store.putDoc(newDoc);\r\n busChanges.push({\r\n type: isNew ? 'added' : 'modified',\r\n collection: serverDoc.collection,\r\n doc: { id: serverDoc.id, data: serverDoc.data },\r\n });\r\n }\r\n }\r\n\r\n // ─── FASE 3 — reabre listeners (realtime) ─────────────────────────────────────\r\n\r\n /**\r\n * Fase 3: sinaliza que o cache está reconciliado.\r\n *\r\n * O transporte de tempo real (Firestore onSnapshot / WebSocket) é gerido\r\n * pela camada superior — aqui apenas garantimos que o SyncState reflita\r\n * o término do sync, o que notifica os listeners `onSyncStateChange` e\r\n * transitivamente os `onSnapshot` da UI.\r\n */\r\n private _phase3Realtime(): void {\r\n // O ChangeBus já foi alimentado nas Fases 1 e 2.\r\n // A Fase 3 garante que o estado de sync reflita \"cache fresco\".\r\n // Em implementação futura, reabre o WebSocket ou onSnapshot do Firestore.\r\n // Por ora, o sinal é a mudança de status para 'idle' + lastSyncedAt.\r\n }\r\n\r\n // ─── Helpers ──────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna a lista de coleções com documentos no cache local.\r\n * Usado pelo full resync para saber quais coleções checar.\r\n *\r\n * Combina:\r\n * 1. Set em memória `_activeCollections` (populado ao aplicar docs)\r\n * 2. Coleções de mutações pendentes\r\n * 3. Coleções de conflict_log\r\n * 4. Coleções persistas em sync_meta['activeCollections']\r\n */\r\n private async _getActiveCollections(): Promise<string[]> {\r\n const collectionSet = new Set<string>(this._activeCollections);\r\n\r\n // Coleções de mutações pendentes\r\n const mutations = await this._queue.listAll();\r\n for (const m of mutations) collectionSet.add(m.collection);\r\n\r\n // Coleções de conflict_log\r\n const conflicts = await this._store.listConflicts();\r\n for (const c of conflicts) collectionSet.add(c.collection);\r\n\r\n // Coleções persistidas em sync_meta (sobrevivem reload)\r\n const persistedRaw = (await this._store.getMeta('activeCollections')) as string[] | null;\r\n if (persistedRaw) {\r\n for (const col of persistedRaw) collectionSet.add(col);\r\n }\r\n\r\n // Coleções descobertas diretamente do IndexedDB (cobre docs pré-populados\r\n // externamente, ex.: pelo SyncTransport em sessões anteriores)\r\n const storedCollections = await this._store.listCollections();\r\n for (const col of storedCollections) collectionSet.add(col);\r\n\r\n return Array.from(collectionSet);\r\n }\r\n\r\n\r\n /** Constrói o estado inicial com base no estado atual dos colaboradores. */\r\n private _buildInitialState(): SyncState {\r\n const isOnline = this._connectivity.isOnline;\r\n return {\r\n status: isOnline ? 'idle' : 'offline',\r\n pendingWrites: 0,\r\n lastSyncedAt: null,\r\n isLeaderTab: this._tabCoordinator.isLeader(),\r\n };\r\n }\r\n\r\n /**\r\n * Atualiza o SyncState em RAM e notifica os listeners.\r\n * Só emite se algo realmente mudou.\r\n */\r\n private _updateState(partial: Partial<SyncState>): void {\r\n const prev = this._state;\r\n const next: SyncState = { ...prev, ...partial };\r\n\r\n // Garante que pendingWrites é sempre recalculado de forma assíncrona\r\n // Nota: não podemos tornar _updateState async aqui (breaking the sync chain),\r\n // então atualizamos o pendingWrites via side-effect lazy.\r\n\r\n const changed =\r\n prev.status !== next.status ||\r\n prev.pendingWrites !== next.pendingWrites ||\r\n prev.lastSyncedAt !== next.lastSyncedAt ||\r\n prev.isLeaderTab !== next.isLeaderTab;\r\n\r\n this._state = next;\r\n\r\n if (changed) {\r\n this._emitState(next);\r\n }\r\n }\r\n\r\n private _emitState(state: SyncState): void {\r\n for (const listener of this._stateListeners) {\r\n try {\r\n listener({ ...state });\r\n } catch { /* listener com erro não interrompe */ }\r\n }\r\n }\r\n\r\n /**\r\n * Atualiza `pendingWrites` no estado.\r\n * Chamado de forma assíncrona quando necessário.\r\n */\r\n private async _refreshPendingWrites(): Promise<void> {\r\n if (this._destroyed) return;\r\n try {\r\n const count = await this._queue.countPending();\r\n if (count !== this._state.pendingWrites) {\r\n this._updateState({ pendingWrites: count });\r\n }\r\n } catch { /* silencioso */ }\r\n }\r\n\r\n /** Dispara um sync de forma fire-and-forget (para gatilhos externos). */\r\n private _triggerSync(_reason: string): void {\r\n if (this._destroyed) return;\r\n this._refreshPendingWrites().catch(() => {});\r\n this.sync().catch(() => {});\r\n }\r\n\r\n /** Carrega activeCollections do sync_meta e popula o Set em memória. */\r\n private _loadActiveCollections(): void {\r\n // Assíncrono — chamado fire-and-forget no constructor\r\n this._store.getMeta('activeCollections')\r\n .then((raw) => {\r\n const cols = raw as string[] | null;\r\n if (cols) {\r\n for (const c of cols) this._activeCollections.add(c);\r\n }\r\n })\r\n .catch(() => {});\r\n }\r\n\r\n /** Conecta os listeners de ConnectivityMonitor e TabCoordinator. */\r\n private _wireListeners(): void {\r\n this._loadActiveCollections();\r\n // ConnectivityMonitor: offline → atualiza status; online → aciona sync\r\n const unsubConn = this._connectivity.subscribe((state) => {\r\n if (state === 'offline') {\r\n this._updateState({ status: 'offline' });\r\n } else {\r\n // Voltou online — atualiza estado e aciona sync\r\n if (this._state.status === 'offline') {\r\n this._updateState({ status: 'idle' });\r\n }\r\n this._triggerSync('connectivity:online');\r\n }\r\n });\r\n this._cleanups.push(unsubConn);\r\n\r\n // TabCoordinator: promoção → aciona sync; rebaixamento → para (status idle)\r\n const unsubRole = this._tabCoordinator.onRoleChange((role) => {\r\n const isLeader = role === 'leader';\r\n this._updateState({ isLeaderTab: isLeader });\r\n\r\n if (isLeader) {\r\n this._triggerSync('role:leader');\r\n }\r\n });\r\n this._cleanups.push(unsubRole);\r\n }\r\n}\r\n","/**\r\n * ConflictResolver — resolução de conflito Last-Write-Wins (LWW).\r\n *\r\n * Implementa a política LWW definida em I3 §7:\r\n * - **Documento-nível** (para `set` e `add`): o documento inteiro com o\r\n * `updatedAtServer` mais recente vence.\r\n * - **Campo-restrito** (para `update`): apenas os campos declarados na mutação\r\n * são comparados; campos não tocados pela mutação são preservados do estado\r\n * atual (server ou local).\r\n *\r\n * Design:\r\n * - ZERO dependências externas.\r\n * - PURO: mesma entrada → mesma saída. Sem side-effects, sem I/O.\r\n * - O timestamp autoritativo é o do SERVIDOR (`updatedAtServer`), não do\r\n * cliente (`enqueuedAt`) — I3 §7.3.\r\n * - A comparação de versão/timestamp acontece no CLIENTE apenas para leitura\r\n * otimista. A palavra final é do servidor (no replay o Core decide). Este\r\n * módulo implementa a lógica de resolução local (para preview otimista e para\r\n * o feedback ao produto).\r\n */\r\n\r\nimport type {\r\n OfflineDoc,\r\n Mutation,\r\n ConflictRecord,\r\n ConflictReason,\r\n} from './types';\r\n\r\n// ─── Tipos do resultado ───────────────────────────────────────────────────────\r\n\r\n/** Resultado da resolução de conflito para um par (local, server). */\r\nexport type ConflictOutcome =\r\n | 'local_wins' // a escrita local é mantida\r\n | 'server_wins' // o estado do servidor prevalece (escrita local descartada)\r\n | 'merged' // merge campo-restrito (update): campos do server + campos locais\r\n | 'no_conflict'; // sem conflito detectável (doc local === doc server, ou nenhum estava presente)\r\n\r\nexport interface ResolveResult<T = Record<string, unknown>> {\r\n outcome: ConflictOutcome;\r\n /** Documento resultante após resolução. */\r\n resolvedData: T;\r\n /**\r\n * `ConflictRecord` preenchido quando `outcome === 'server_wins'` ou\r\n * `outcome === 'merged'` (campos conflitantes perdedores).\r\n * `null` caso contrário.\r\n */\r\n conflictRecord: Omit<ConflictRecord, 'id'> | null;\r\n}\r\n\r\n// ─── Helpers ──────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Retorna true se o estado do servidor é \"mais novo\" do que o estado local,\r\n * baseando-se no timestamp do servidor (I3 §7.3).\r\n *\r\n * Quando `serverUpdatedAt` é null o servidor nunca confirmou — considera o local\r\n * como mais recente (o doc pode ser um `add` otimista ainda não sincronizado).\r\n * Quando ambos são null há empate → `false` (mantém local como default).\r\n */\r\nfunction isServerNewer(\r\n localUpdatedAtServer: number | null,\r\n remoteUpdatedAtServer: number | null,\r\n): boolean {\r\n if (remoteUpdatedAtServer === null) return false;\r\n if (localUpdatedAtServer === null) return true; // server tem timestamp, local não\r\n return remoteUpdatedAtServer > localUpdatedAtServer;\r\n}\r\n\r\n// ─── ConflictResolver ─────────────────────────────────────────────────────────\r\n\r\n/**\r\n * ConflictResolver — aplica LWW doc-nível ou campo-restrito.\r\n *\r\n * Uso:\r\n * ```ts\r\n * const resolver = new ConflictResolver();\r\n *\r\n * // LWW doc-nível (set/add):\r\n * const result = resolver.resolveDocLevel(localDoc, serverDoc, mutation);\r\n *\r\n * // LWW campo-restrito (update):\r\n * const result = resolver.resolveFieldRestricted(localDoc, serverDoc, mutation);\r\n *\r\n * // Auto-dispatch baseado na op da mutação:\r\n * const result = resolver.resolve(localDoc, serverDoc, mutation);\r\n * ```\r\n */\r\nexport class ConflictResolver {\r\n /**\r\n * Resolve um conflito com base na operação da mutação (auto-dispatch).\r\n *\r\n * - `add` / `set` → `resolveDocLevel`\r\n * - `update` → `resolveFieldRestricted`\r\n * - `remove` → a remoção sempre vence (LWW: operação mais recente é a destruição)\r\n */\r\n resolve<T = Record<string, unknown>>(\r\n localDoc: OfflineDoc<T> | null,\r\n serverDoc: OfflineDoc<T> | null,\r\n pendingMutation: Mutation,\r\n ): ResolveResult<T> {\r\n switch (pendingMutation.op) {\r\n case 'remove':\r\n return this.resolveRemove(localDoc, serverDoc, pendingMutation);\r\n case 'update':\r\n return this.resolveFieldRestricted(localDoc, serverDoc, pendingMutation);\r\n case 'add':\r\n case 'set':\r\n default:\r\n return this.resolveDocLevel(localDoc, serverDoc, pendingMutation);\r\n }\r\n }\r\n\r\n /**\r\n * LWW documento-nível (para `set` e `add`).\r\n *\r\n * O documento inteiro com o timestamp de servidor mais recente vence.\r\n * Se o servidor for mais novo, a escrita local é descartada e um\r\n * `ConflictRecord` é emitido.\r\n */\r\n resolveDocLevel<T = Record<string, unknown>>(\r\n localDoc: OfflineDoc<T> | null,\r\n serverDoc: OfflineDoc<T> | null,\r\n pendingMutation: Mutation,\r\n ): ResolveResult<T> {\r\n // Sem doc no servidor — escrita local não tem concorrente, sem conflito.\r\n if (serverDoc === null) {\r\n const data = (pendingMutation.payload ?? {}) as T;\r\n return { outcome: 'no_conflict', resolvedData: data, conflictRecord: null };\r\n }\r\n\r\n // Sem doc local (não deveria ocorrer, mas defesa de programação)\r\n if (localDoc === null) {\r\n return {\r\n outcome: 'server_wins',\r\n resolvedData: serverDoc.data,\r\n conflictRecord: null,\r\n };\r\n }\r\n\r\n const serverNewer = isServerNewer(\r\n localDoc.meta.updatedAtServer,\r\n serverDoc.meta.updatedAtServer,\r\n );\r\n\r\n if (!serverNewer) {\r\n // Escrita local é mais recente (ou empate → local vence por default)\r\n return {\r\n outcome: 'local_wins',\r\n resolvedData: localDoc.data,\r\n conflictRecord: null,\r\n };\r\n }\r\n\r\n // Servidor mais novo — LWW: servidor vence, escrita local descartada\r\n const conflictRecord: Omit<ConflictRecord, 'id'> = {\r\n collection: pendingMutation.collection,\r\n docId: pendingMutation.docId,\r\n mutationId: pendingMutation.mutationId,\r\n losingData: localDoc.data as Record<string, unknown>,\r\n winningData: serverDoc.data as Record<string, unknown>,\r\n reason: 'lww_server_newer' as ConflictReason,\r\n detectedAt: Date.now(),\r\n delivered: false,\r\n };\r\n\r\n return {\r\n outcome: 'server_wins',\r\n resolvedData: serverDoc.data,\r\n conflictRecord,\r\n };\r\n }\r\n\r\n /**\r\n * LWW campo-restrito (para `update`).\r\n *\r\n * Apenas os campos declarados no payload da mutação são comparados.\r\n * Campos não tocados pela mutação são preservados do estado do servidor\r\n * (se disponível) ou do estado local (I3 §7.2).\r\n *\r\n * Resultado:\r\n * - Se o servidor for mais novo nos campos conflitantes → `server_wins`\r\n * para esses campos; o doc resultante é uma mescla de server (campos\r\n * conflitantes) + estado antes da mutação para os demais.\r\n * - Se o local for mais recente → `local_wins`; os campos do update são\r\n * aplicados sobre o server.\r\n * - Campos do server não tocados pelo update sempre preservados → `merged`.\r\n */\r\n resolveFieldRestricted<T = Record<string, unknown>>(\r\n localDoc: OfflineDoc<T> | null,\r\n serverDoc: OfflineDoc<T> | null,\r\n pendingMutation: Mutation,\r\n ): ResolveResult<T> {\r\n const mutatedFields = Object.keys(pendingMutation.payload ?? {});\r\n\r\n // Sem doc no servidor — sem conflito, aplica o update sobre o local\r\n if (serverDoc === null) {\r\n const base = (localDoc?.data ?? {}) as Record<string, unknown>;\r\n const resolved = { ...base, ...(pendingMutation.payload ?? {}) } as T;\r\n return { outcome: 'no_conflict', resolvedData: resolved, conflictRecord: null };\r\n }\r\n\r\n // Base do documento no servidor (campos não tocados pelo update)\r\n const serverData = serverDoc.data as Record<string, unknown>;\r\n\r\n // Se não há doc local (doc nunca foi cacheado), sem conflito — aplica o update sobre o server\r\n if (localDoc === null) {\r\n const resolved = { ...serverData, ...(pendingMutation.payload ?? {}) } as T;\r\n return { outcome: 'no_conflict', resolvedData: resolved, conflictRecord: null };\r\n }\r\n\r\n const serverNewer = isServerNewer(\r\n localDoc.meta.updatedAtServer,\r\n serverDoc.meta.updatedAtServer,\r\n );\r\n\r\n if (!serverNewer) {\r\n // Update local é mais recente — aplica os campos do update sobre o server\r\n const resolved = { ...serverData, ...(pendingMutation.payload ?? {}) } as T;\r\n return { outcome: 'local_wins', resolvedData: resolved, conflictRecord: null };\r\n }\r\n\r\n // Servidor mais novo — campos conflitantes: server vence; campos do update\r\n // não existentes no server: server ainda vence (server é a fonte de verdade\r\n // pós-conflito, consistente com doc-level LWW).\r\n const losingFields: Record<string, unknown> = {};\r\n for (const field of mutatedFields) {\r\n losingFields[field] = (localDoc.data as Record<string, unknown>)[field];\r\n }\r\n\r\n const conflictRecord: Omit<ConflictRecord, 'id'> = {\r\n collection: pendingMutation.collection,\r\n docId: pendingMutation.docId,\r\n mutationId: pendingMutation.mutationId,\r\n losingData: losingFields,\r\n winningData: serverData,\r\n reason: 'lww_server_newer' as ConflictReason,\r\n detectedAt: Date.now(),\r\n delivered: false,\r\n };\r\n\r\n // Doc resultante: estado do servidor completo (o update perdeu todos os\r\n // campos conflitantes — comportamento conservador e auditável)\r\n return {\r\n outcome: 'server_wins',\r\n resolvedData: serverData as T,\r\n conflictRecord,\r\n };\r\n }\r\n\r\n /**\r\n * Resolve uma operação `remove`.\r\n *\r\n * A remoção sempre vence no LWW (I3 §7.4: \"a última operação é a destruição\").\r\n * Se o servidor modificou o doc depois que o cliente enfileirou o remove, a\r\n * remoção ainda prevalece — comportamento documentado.\r\n */\r\n resolveRemove<T = Record<string, unknown>>(\r\n _localDoc: OfflineDoc<T> | null,\r\n serverDoc: OfflineDoc<T> | null,\r\n _pendingMutation: Mutation,\r\n ): ResolveResult<T> {\r\n // A remoção vence — o doc resultante é um tombstone (dados vazios)\r\n // O chamador é responsável por marcar `deleted: true` no cache.\r\n const emptyDoc = {} as T;\r\n\r\n // Se o servidor tem um estado mais recente E foi modificado depois da\r\n // intenção de remoção, registra um conflito para audit trail (mas ainda remove)\r\n if (serverDoc !== null && serverDoc.meta.updatedAtServer !== null) {\r\n const conflictRecord: Omit<ConflictRecord, 'id'> = {\r\n collection: _pendingMutation.collection,\r\n docId: _pendingMutation.docId,\r\n mutationId: _pendingMutation.mutationId,\r\n losingData: serverDoc.data as Record<string, unknown>,\r\n winningData: {},\r\n reason: 'lww_server_newer' as ConflictReason,\r\n detectedAt: Date.now(),\r\n delivered: false,\r\n };\r\n // A remoção ainda vence, mas registra o conflito\r\n return { outcome: 'local_wins', resolvedData: emptyDoc, conflictRecord };\r\n }\r\n\r\n return { outcome: 'local_wins', resolvedData: emptyDoc, conflictRecord: null };\r\n }\r\n\r\n /**\r\n * Resolve conflito com razão de rejeição explícita (servidor retornou\r\n * `rejected_permission` ou `rejected_validation`).\r\n *\r\n * Usado pelo SyncEngine quando o Core rejeita o replay por motivo não-LWW.\r\n */\r\n resolveRejected<T = Record<string, unknown>>(\r\n localDoc: OfflineDoc<T>,\r\n serverDoc: OfflineDoc<T> | null,\r\n pendingMutation: Mutation,\r\n reason: 'rejected_permission' | 'rejected_validation',\r\n ): ResolveResult<T> {\r\n const winningData = (serverDoc?.data ?? {}) as Record<string, unknown>;\r\n\r\n const conflictRecord: Omit<ConflictRecord, 'id'> = {\r\n collection: pendingMutation.collection,\r\n docId: pendingMutation.docId,\r\n mutationId: pendingMutation.mutationId,\r\n losingData: localDoc.data as Record<string, unknown>,\r\n winningData,\r\n reason,\r\n detectedAt: Date.now(),\r\n delivered: false,\r\n };\r\n\r\n return {\r\n outcome: 'server_wins',\r\n resolvedData: (serverDoc?.data ?? localDoc.data),\r\n conflictRecord,\r\n };\r\n }\r\n\r\n // ─── Static helpers ─────────────────────────────────────────────────────────\r\n\r\n static resolve<T = Record<string, unknown>>(\r\n localDoc: OfflineDoc<T> | null,\r\n serverDoc: OfflineDoc<T> | null,\r\n pendingMutation: Mutation,\r\n ): ResolveResult<T> {\r\n return new ConflictResolver().resolve(localDoc, serverDoc, pendingMutation);\r\n }\r\n}\r\n","/**\r\n * ChangeBus — barramento in-process de eventos de mudança.\r\n *\r\n * Fan-out de eventos `Change` para todos os listeners registrados\r\n * (onSnapshot / onDoc). Cola o cache (LocalStore) ao tempo real.\r\n *\r\n * Design (I3 §2.2 / §6.5 / §9):\r\n * - ZERO dependências externas.\r\n * - Em memória por aba (não persiste).\r\n * - Sem memory leaks: `unsubscribe()` remove o listener imediatamente.\r\n * - Deduplicação básica por `[collection, id, serverVersion]` (I3 §6.5):\r\n * o bus não emite o mesmo evento duas vezes pra o mesmo listener no mesmo\r\n * tick (evita a Fase 1 + Fase 2 do SyncEngine gerando dois eventos para o\r\n * mesmo doc confirmado).\r\n * - Erro em um listener não propaga para os demais (isolamento).\r\n */\r\n\r\nimport type { Change, Unsubscribe } from './types';\r\n\r\n// ─── Tipos internos ───────────────────────────────────────────────────────────\r\n\r\n/** Função listener que recebe um array de Changes emitidos juntos. */\r\nexport type ChangeBusListener<T = Record<string, unknown>> = (\r\n changes: Change<T>[],\r\n) => void;\r\n\r\n/** Chave de deduplicação para um change event. */\r\nfunction dedupeKey<T>(c: Change<T>): string {\r\n // usa `serverVersion` se presente; fallback para 'local' (sem versão server)\r\n return `${c.collection}::${c.doc.id}`;\r\n}\r\n\r\n// ─── ChangeBus ────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * ChangeBus — pub/sub in-process para eventos de mudança de documento.\r\n *\r\n * ```ts\r\n * const bus = new ChangeBus();\r\n *\r\n * // Subscrever a uma coleção (filtra por collection automaticamente)\r\n * const unsub = bus.subscribe('orders', (changes) => {\r\n * console.log(changes);\r\n * });\r\n *\r\n * // Emitir events\r\n * bus.emit([{ type: 'modified', collection: 'orders', doc: { id: '1', data: {} } }]);\r\n *\r\n * // Cancelar subscrição — sem memory leak\r\n * unsub();\r\n * ```\r\n *\r\n * Listeners globais (sem filtro de coleção):\r\n * ```ts\r\n * const unsub = bus.subscribeAll((changes) => { ... });\r\n * ```\r\n */\r\nexport class ChangeBus<T = Record<string, unknown>> {\r\n /** Listeners filtrados por coleção. */\r\n private readonly _collectionListeners = new Map<\r\n string,\r\n Set<ChangeBusListener<T>>\r\n >();\r\n /** Listeners globais (todas as coleções). */\r\n private readonly _globalListeners = new Set<ChangeBusListener<T>>();\r\n\r\n /**\r\n * Subscreve a eventos de uma coleção específica.\r\n *\r\n * @param collection - Nome da coleção a filtrar.\r\n * @param listener - Callback que recebe os changes da coleção.\r\n * @returns Função de unsubscribe.\r\n */\r\n subscribe(collection: string, listener: ChangeBusListener<T>): Unsubscribe {\r\n if (!this._collectionListeners.has(collection)) {\r\n this._collectionListeners.set(collection, new Set());\r\n }\r\n this._collectionListeners.get(collection)!.add(listener);\r\n\r\n return () => {\r\n const set = this._collectionListeners.get(collection);\r\n if (set) {\r\n set.delete(listener);\r\n if (set.size === 0) {\r\n this._collectionListeners.delete(collection);\r\n }\r\n }\r\n };\r\n }\r\n\r\n /**\r\n * Subscreve a eventos de TODAS as coleções.\r\n *\r\n * @param listener - Callback que recebe todos os changes, de qualquer coleção.\r\n * @returns Função de unsubscribe.\r\n */\r\n subscribeAll(listener: ChangeBusListener<T>): Unsubscribe {\r\n this._globalListeners.add(listener);\r\n return () => {\r\n this._globalListeners.delete(listener);\r\n };\r\n }\r\n\r\n /**\r\n * Emite um array de `Change` events para todos os listeners relevantes.\r\n *\r\n * Agrupa os changes por coleção antes de despachar, para que cada listener\r\n * receba apenas os events da sua coleção.\r\n *\r\n * Deduplicação: events com o mesmo `[collection, id]` dentro do mesmo `emit()`\r\n * são compactados: apenas o último do array é mantido (o mais recente vence).\r\n * Isso cobre o caso Fase 1 + Fase 2 do SyncEngine emitindo o mesmo doc.\r\n *\r\n * Erros em listeners individuais são capturados e não interrompem os demais.\r\n */\r\n emit(changes: Change<T>[]): void {\r\n if (changes.length === 0) return;\r\n\r\n // Deduplica: mapa de dedupeKey → último change (o mais recente)\r\n const deduped = new Map<string, Change<T>>();\r\n for (const c of changes) {\r\n deduped.set(dedupeKey(c), c);\r\n }\r\n const uniqueChanges = Array.from(deduped.values());\r\n\r\n // Agrupa por coleção\r\n const byCollection = new Map<string, Change<T>[]>();\r\n for (const c of uniqueChanges) {\r\n if (!byCollection.has(c.collection)) {\r\n byCollection.set(c.collection, []);\r\n }\r\n byCollection.get(c.collection)!.push(c);\r\n }\r\n\r\n // Despacha para listeners de coleção\r\n for (const [collection, collChanges] of byCollection) {\r\n const listeners = this._collectionListeners.get(collection);\r\n if (listeners) {\r\n for (const listener of listeners) {\r\n this._safeCall(listener, collChanges);\r\n }\r\n }\r\n }\r\n\r\n // Despacha para listeners globais (com todos os changes únicos)\r\n for (const listener of this._globalListeners) {\r\n this._safeCall(listener, uniqueChanges);\r\n }\r\n }\r\n\r\n /**\r\n * Número de listeners ativos (útil em testes).\r\n */\r\n get listenerCount(): number {\r\n let count = this._globalListeners.size;\r\n for (const set of this._collectionListeners.values()) {\r\n count += set.size;\r\n }\r\n return count;\r\n }\r\n\r\n /**\r\n * Remove todos os listeners registrados.\r\n * Útil para teardown em testes ou no shutdown do SDK.\r\n */\r\n clear(): void {\r\n this._collectionListeners.clear();\r\n this._globalListeners.clear();\r\n }\r\n\r\n // ─── Privado ────────────────────────────────────────────────────────────────\r\n\r\n private _safeCall(listener: ChangeBusListener<T>, changes: Change<T>[]): void {\r\n try {\r\n listener(changes);\r\n } catch {\r\n // Listener com erro não interrompe os demais.\r\n // Em produção, o SyncEngine pode logar via telemetry.\r\n // Aqui silenciamos para manter o contrato de fan-out total.\r\n }\r\n }\r\n}\r\n","/**\r\n * ConnectivityMonitor — rastreia estado online/offline via `navigator.onLine`\r\n * e os eventos `online`/`offline` do window.\r\n *\r\n * Design (I3 §2.2):\r\n * - ZERO dependências externas.\r\n * - Injetável: aceita `navigator` e `EventTarget` como parâmetros para ser\r\n * totalmente testável sem DOM real.\r\n * - Debounce de flapping: transições rápidas online → offline → online dentro\r\n * de `debounceMs` (default 300ms) não disparam callbacks intermediários.\r\n * - Nota I3 §2.2: o ConnectivityMonitor base usa `navigator.onLine` + eventos\r\n * do window. Uma camada adicional (heartbeat real ao Core + sinal do\r\n * WebSocket) é responsabilidade do SyncEngine — este módulo é a base injetável.\r\n */\r\n\r\nimport type { Unsubscribe } from './types';\r\n\r\n// ─── Tipos ────────────────────────────────────────────────────────────────────\r\n\r\n/** Estado de conectividade. */\r\nexport type ConnectivityState = 'online' | 'offline';\r\n\r\n/** Listener de mudança de estado de conectividade. */\r\nexport type ConnectivityListener = (state: ConnectivityState) => void;\r\n\r\n/**\r\n * Contrato de injeção do `navigator` (subconjunto usado pelo monitor).\r\n * Permite testar sem um `navigator` real.\r\n */\r\nexport interface NavigatorLike {\r\n readonly onLine: boolean;\r\n}\r\n\r\n/**\r\n * Contrato de injeção do event target (subconjunto de `window` / `EventTarget`).\r\n */\r\nexport interface EventTargetLike {\r\n addEventListener(type: string, listener: EventListenerOrEventListenerObject): void;\r\n removeEventListener(type: string, listener: EventListenerOrEventListenerObject): void;\r\n}\r\n\r\n/** Opções de configuração do ConnectivityMonitor. */\r\nexport interface ConnectivityMonitorOptions {\r\n /**\r\n * `navigator`-like para leitura de `navigator.onLine`.\r\n * Default: `globalThis.navigator` (quando disponível).\r\n */\r\n navigator?: NavigatorLike;\r\n /**\r\n * EventTarget para subscrever os eventos `online` / `offline`.\r\n * Default: `globalThis.window` (quando disponível).\r\n */\r\n eventTarget?: EventTargetLike;\r\n /**\r\n * Debounce em ms para evitar flapping.\r\n * Default: 300ms.\r\n */\r\n debounceMs?: number;\r\n}\r\n\r\n// ─── ConnectivityMonitor ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * ConnectivityMonitor — monitora online/offline via `navigator.onLine` +\r\n * eventos `online`/`offline` do window, com debounce de flapping.\r\n *\r\n * ```ts\r\n * // Com injeção (testes):\r\n * const monitor = new ConnectivityMonitor({\r\n * navigator: { onLine: true },\r\n * eventTarget: myFakeTarget,\r\n * });\r\n *\r\n * // Em browser real:\r\n * const monitor = new ConnectivityMonitor();\r\n * monitor.start();\r\n *\r\n * const unsub = monitor.subscribe((state) => {\r\n * console.log('Conectividade:', state);\r\n * });\r\n *\r\n * monitor.destroy(); // cleanup\r\n * ```\r\n */\r\nexport class ConnectivityMonitor {\r\n private _state: ConnectivityState;\r\n private readonly _listeners = new Set<ConnectivityListener>();\r\n private readonly _nav: NavigatorLike | undefined;\r\n private readonly _target: EventTargetLike | undefined;\r\n private readonly _debounceMs: number;\r\n private _debounceTimer: ReturnType<typeof setTimeout> | null = null;\r\n private _started = false;\r\n\r\n // Handlers bound para remoção correta em removeEventListener\r\n private readonly _onOnline: () => void;\r\n private readonly _onOffline: () => void;\r\n\r\n constructor(options: ConnectivityMonitorOptions = {}) {\r\n this._nav = options.navigator ?? (typeof navigator !== 'undefined' ? navigator : undefined);\r\n this._target =\r\n options.eventTarget ??\r\n (typeof window !== 'undefined' ? window : undefined);\r\n this._debounceMs = options.debounceMs ?? 300;\r\n\r\n // Estado inicial: lê navigator.onLine; fallback = online\r\n this._state = this._nav?.onLine === false ? 'offline' : 'online';\r\n\r\n // Bind para poder remover depois\r\n this._onOnline = () => this._handleNativeEvent('online');\r\n this._onOffline = () => this._handleNativeEvent('offline');\r\n }\r\n\r\n // ─── Ciclo de vida ──────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Inicia a escuta de eventos. Deve ser chamado após instanciar.\r\n * Sem efeito se já foi iniciado.\r\n */\r\n start(): void {\r\n if (this._started) return;\r\n this._started = true;\r\n this._target?.addEventListener('online', this._onOnline);\r\n this._target?.addEventListener('offline', this._onOffline);\r\n }\r\n\r\n /**\r\n * Para a escuta e remove todos os listeners.\r\n * Deve ser chamado no shutdown para evitar memory leaks.\r\n */\r\n destroy(): void {\r\n this._started = false;\r\n this._target?.removeEventListener('online', this._onOnline);\r\n this._target?.removeEventListener('offline', this._onOffline);\r\n if (this._debounceTimer !== null) {\r\n clearTimeout(this._debounceTimer);\r\n this._debounceTimer = null;\r\n }\r\n this._listeners.clear();\r\n }\r\n\r\n // ─── Estado atual ───────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna o estado de conectividade atual.\r\n */\r\n getState(): ConnectivityState {\r\n return this._state;\r\n }\r\n\r\n /**\r\n * True se o estado atual é `'online'`.\r\n */\r\n get isOnline(): boolean {\r\n return this._state === 'online';\r\n }\r\n\r\n /**\r\n * True se o estado atual é `'offline'`.\r\n */\r\n get isOffline(): boolean {\r\n return this._state === 'offline';\r\n }\r\n\r\n // ─── Subscrições ────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Subscreve a mudanças de estado de conectividade.\r\n *\r\n * @param listener - Callback chamado ao mudar o estado.\r\n * @returns Função de unsubscribe (sem memory leak).\r\n */\r\n subscribe(listener: ConnectivityListener): Unsubscribe {\r\n this._listeners.add(listener);\r\n return () => {\r\n this._listeners.delete(listener);\r\n };\r\n }\r\n\r\n /**\r\n * Número de listeners ativos (útil em testes).\r\n */\r\n get listenerCount(): number {\r\n return this._listeners.size;\r\n }\r\n\r\n // ─── Força de estado (para testes e heartbeat externo) ─────────────────────\r\n\r\n /**\r\n * Força o estado para um valor específico, ignorando eventos nativos.\r\n * Útil para o SyncEngine injetar o resultado de um heartbeat real ao Core.\r\n * Respeita o debounce.\r\n */\r\n forceState(state: ConnectivityState): void {\r\n this._scheduleTransition(state);\r\n }\r\n\r\n // ─── Privado ────────────────────────────────────────────────────────────────\r\n\r\n private _handleNativeEvent(type: 'online' | 'offline'): void {\r\n const newState: ConnectivityState = type === 'online' ? 'online' : 'offline';\r\n this._scheduleTransition(newState);\r\n }\r\n\r\n private _scheduleTransition(newState: ConnectivityState): void {\r\n // Cancela transição pendente (debounce de flapping)\r\n if (this._debounceTimer !== null) {\r\n clearTimeout(this._debounceTimer);\r\n this._debounceTimer = null;\r\n }\r\n\r\n if (this._debounceMs <= 0) {\r\n // Sem debounce — aplica imediatamente\r\n this._applyTransition(newState);\r\n return;\r\n }\r\n\r\n this._debounceTimer = setTimeout(() => {\r\n this._debounceTimer = null;\r\n this._applyTransition(newState);\r\n }, this._debounceMs);\r\n }\r\n\r\n private _applyTransition(newState: ConnectivityState): void {\r\n if (newState === this._state) return; // sem mudança real\r\n this._state = newState;\r\n this._notifyListeners(newState);\r\n }\r\n\r\n private _notifyListeners(state: ConnectivityState): void {\r\n for (const listener of this._listeners) {\r\n try {\r\n listener(state);\r\n } catch {\r\n // Listener com erro não interrompe os demais\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * TabCoordinator — coordenação multi-aba via Web Locks API.\r\n *\r\n * Elege uma aba **líder** de forma exclusiva: apenas a aba líder roda o\r\n * SyncEngine e drena a MutationQueue. Abas seguidoras leem o LocalStore\r\n * compartilhado e recebem notificações via BroadcastChannel.\r\n *\r\n * Design (I3 §12.5 / §2.2):\r\n *\r\n * - **Eleição via Web Locks:** `navigator.locks.request(name, callback)` com\r\n * uma Promise interna que nunca resolve enquanto a aba estiver viva. O\r\n * processo que segura o lock é o líder. Ao destruir, a Promise interna\r\n * resolve → lock liberado → próxima aba na fila adquire o lock.\r\n *\r\n * - **BroadcastChannel:** o líder transmite `cache_updated` / `sync_state`\r\n * para que seguidores reavaliem suas queries; seguidores enviam\r\n * `mutation_request` ao líder quando querem que ele drene a fila.\r\n *\r\n * - **Fallback:** se `navigator.locks` não estiver disponível (SSR, ambiente\r\n * sem suporte), a aba assume liderança imediatamente sem contenção.\r\n *\r\n * - **Injetabilidade:** todas as APIs do browser (`navigator.locks`,\r\n * `BroadcastChannel`) são injetáveis via `TabCoordinatorOptions` — o\r\n * componente é totalmente testável sem DOM/browser real.\r\n *\r\n * - **Idempotência:** `start()` e `destroy()` são seguros de chamar\r\n * múltiplas vezes.\r\n */\r\n\r\nimport type { Unsubscribe } from './types';\r\n\r\n// ─── Protocolo de mensagens BroadcastChannel ──────────────────────────────────\r\n\r\n/**\r\n * O líder transmite que o cache foi atualizado.\r\n * Seguidores devem reavaliar queries afetadas pela `collection`.\r\n */\r\nexport interface CacheUpdatedMessage {\r\n type: 'cache_updated';\r\n /** Coleção que foi modificada. `*` = todas. */\r\n collection: string;\r\n}\r\n\r\n/**\r\n * O líder transmite seu estado de sync para que seguidores atualizem o\r\n * `isLeaderTab` em seus `NeetruSyncState`.\r\n */\r\nexport interface SyncStateMessage {\r\n type: 'sync_state';\r\n /** ID único da aba líder. */\r\n leaderTabId: string;\r\n /** Se `true`, o líder está sincronizando no momento. */\r\n syncing: boolean;\r\n /** Número de mutações pendentes na fila. */\r\n pendingWrites: number;\r\n}\r\n\r\n/**\r\n * Um seguidor solicita ao líder que drene a fila (ex.: após enfileirar\r\n * uma mutação localmente). O líder pode ignorar se já estiver drenando.\r\n */\r\nexport interface MutationRequestMessage {\r\n type: 'mutation_request';\r\n mutationId: string;\r\n collection: string;\r\n op: string;\r\n docId: string;\r\n payload: Record<string, unknown> | null;\r\n}\r\n\r\n/**\r\n * União discriminada de todas as mensagens do protocolo TabCoordinator.\r\n * Mensagens de tipo desconhecido devem ser ignoradas silenciosamente\r\n * (compatibilidade futura).\r\n */\r\nexport type TabMessage =\r\n | CacheUpdatedMessage\r\n | SyncStateMessage\r\n | MutationRequestMessage;\r\n\r\n// ─── Contratos de injeção de browser APIs ─────────────────────────────────────\r\n\r\n/**\r\n * Subconjunto de `Lock` usado pelo TabCoordinator.\r\n */\r\nexport interface LockLike {\r\n readonly name: string;\r\n}\r\n\r\n/**\r\n * Subconjunto de `LockManager` (`navigator.locks`).\r\n * Permite injeção de fake em testes sem o browser real.\r\n */\r\nexport interface LockManagerLike {\r\n request(\r\n name: string,\r\n callback: (lock: LockLike) => Promise<void>,\r\n ): Promise<void>;\r\n}\r\n\r\n/**\r\n * Subconjunto de `BroadcastChannel`.\r\n * Permite injeção de fake em testes sem o browser real.\r\n */\r\nexport interface BroadcastChannelLike {\r\n onmessage: ((msg: TabMessage) => void) | null;\r\n postMessage(msg: TabMessage): void;\r\n close(): void;\r\n}\r\n\r\n// ─── Papel da aba ──────────────────────────────────────────────────────────────\r\n\r\n/** Papel atual desta aba no protocolo multi-aba. */\r\nexport type TabRole = 'leader' | 'follower';\r\n\r\n/** Callback de mudança de papel. */\r\nexport type RoleChangeListener = (role: TabRole) => void;\r\n\r\n// ─── Opções ───────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Opções de configuração do TabCoordinator.\r\n * Todos os campos de browser API são opcionais para facilitar testes.\r\n */\r\nexport interface TabCoordinatorOptions {\r\n /**\r\n * Nome do lock Web Locks (deve ser único por banco lógico / origem).\r\n * Exemplo: `'neetru-offline:produto-slug:db-id'`.\r\n */\r\n lockName: string;\r\n\r\n /**\r\n * Nome do BroadcastChannel (geralmente igual ao lockName).\r\n */\r\n channelName: string;\r\n\r\n /**\r\n * `navigator.locks`-like. Quando `undefined`, o TabCoordinator usa o\r\n * `navigator.locks` global se disponível; caso contrário, usa fallback\r\n * (assume liderança imediatamente).\r\n */\r\n lockManager?: LockManagerLike;\r\n\r\n /**\r\n * Instância de `BroadcastChannel`-like pré-criada. Quando `undefined`,\r\n * o TabCoordinator tenta criar um `BroadcastChannel` real se disponível.\r\n */\r\n broadcastChannel?: BroadcastChannelLike;\r\n}\r\n\r\n// ─── TabCoordinator ───────────────────────────────────────────────────────────\r\n\r\n/**\r\n * TabCoordinator — coordenação multi-aba via Web Locks + BroadcastChannel.\r\n *\r\n * ```ts\r\n * // Com injeção (testes):\r\n * const coordinator = new TabCoordinator({\r\n * lockName: 'neetru-offline:mydb',\r\n * channelName: 'neetru-offline:mydb',\r\n * lockManager: fakeLockManager,\r\n * broadcastChannel: fakeBroadcastChannel,\r\n * });\r\n *\r\n * // Em browser real:\r\n * const coordinator = new TabCoordinator({\r\n * lockName: `neetru-offline:${productId}:${dbId}`,\r\n * channelName: `neetru-offline:${productId}:${dbId}`,\r\n * });\r\n *\r\n * coordinator.start();\r\n *\r\n * // Saber se esta aba é líder\r\n * coordinator.isLeader();\r\n *\r\n * // Reagir a mudança de papel\r\n * const unsub = coordinator.onRoleChange((role) => {\r\n * if (role === 'leader') syncEngine.start();\r\n * else syncEngine.stop();\r\n * });\r\n *\r\n * // Transmitir a seguidores\r\n * coordinator.broadcast({ type: 'cache_updated', collection: 'orders' });\r\n *\r\n * // Receber mensagens de outras abas\r\n * coordinator.onMessage((msg) => {\r\n * if (msg.type === 'mutation_request') syncEngine.drainQueue();\r\n * });\r\n *\r\n * // Cleanup\r\n * coordinator.destroy();\r\n * ```\r\n */\r\nexport class TabCoordinator {\r\n private readonly _lockName: string;\r\n private readonly _channelName: string;\r\n private readonly _lockManager: LockManagerLike | undefined;\r\n private _channel: BroadcastChannelLike | undefined;\r\n private readonly _channelFactory: (() => BroadcastChannelLike) | undefined;\r\n\r\n /** ID único desta aba (para debug e `sync_state`). */\r\n private readonly _tabId: string;\r\n\r\n /** Estado de papel atual. */\r\n private _role: TabRole = 'follower';\r\n\r\n /** Promise resolve que libera o lock perpétuo. */\r\n private _releaseLock: (() => void) | null = null;\r\n\r\n /** `true` se destroy() já foi chamado. */\r\n private _destroyed = false;\r\n\r\n /** `true` se start() já foi chamado. */\r\n private _started = false;\r\n\r\n /** Listeners de mudança de papel. */\r\n private readonly _roleListeners = new Set<RoleChangeListener>();\r\n\r\n /** Listeners de mensagem recebida. */\r\n private readonly _messageListeners = new Set<(msg: TabMessage) => void>();\r\n\r\n constructor(options: TabCoordinatorOptions) {\r\n this._lockName = options.lockName;\r\n this._channelName = options.channelName;\r\n this._tabId = `tab-${Math.random().toString(36).slice(2, 10)}-${Date.now()}`;\r\n\r\n // Resolve o lockManager: opção injetada > navigator.locks global > undefined\r\n this._lockManager =\r\n options.lockManager !== undefined\r\n ? options.lockManager\r\n : typeof navigator !== 'undefined' &&\r\n 'locks' in navigator &&\r\n navigator.locks != null\r\n ? (navigator.locks as unknown as LockManagerLike)\r\n : undefined;\r\n\r\n // Resolve o canal: opção injetada > factory para BroadcastChannel real\r\n if (options.broadcastChannel !== undefined) {\r\n this._channel = options.broadcastChannel;\r\n } else if (typeof BroadcastChannel !== 'undefined') {\r\n // No browser real, armazena uma factory para criação lazy\r\n const channelName = this._channelName;\r\n this._channelFactory = () => {\r\n const bc = new BroadcastChannel(channelName);\r\n const wrapper: BroadcastChannelLike = {\r\n get onmessage() {\r\n return (bc.onmessage as ((msg: TabMessage) => void) | null);\r\n },\r\n set onmessage(cb: ((msg: TabMessage) => void) | null) {\r\n bc.onmessage = cb\r\n ? (event: MessageEvent) => cb(event.data as TabMessage)\r\n : null;\r\n },\r\n postMessage: (msg: TabMessage) => bc.postMessage(msg),\r\n close: () => bc.close(),\r\n };\r\n return wrapper;\r\n };\r\n }\r\n }\r\n\r\n // ─── Ciclo de vida ───────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Inicia o processo de eleição de líder.\r\n * Idempotente: sem efeito se já foi chamado.\r\n */\r\n start(): void {\r\n if (this._started || this._destroyed) return;\r\n this._started = true;\r\n\r\n // Cria o canal se ainda não foi injetado\r\n if (!this._channel && this._channelFactory) {\r\n this._channel = this._channelFactory();\r\n }\r\n\r\n // Configura o handler de mensagens do BroadcastChannel\r\n if (this._channel) {\r\n this._channel.onmessage = (msg: TabMessage) => {\r\n this._handleIncomingMessage(msg);\r\n };\r\n }\r\n\r\n // Inicia eleição\r\n if (this._lockManager) {\r\n this._electWithLocks();\r\n } else {\r\n // Fallback: sem Web Locks → assume liderança imediatamente\r\n this._becomeLeader();\r\n }\r\n }\r\n\r\n /**\r\n * Para o TabCoordinator: libera o lock, fecha o canal.\r\n * Idempotente: pode ser chamado múltiplas vezes.\r\n */\r\n destroy(): void {\r\n if (this._destroyed) return;\r\n this._destroyed = true;\r\n this._started = false;\r\n\r\n // Libera o lock perpétuo (se líder)\r\n if (this._releaseLock) {\r\n this._releaseLock();\r\n this._releaseLock = null;\r\n }\r\n\r\n // Fecha o canal de broadcast\r\n if (this._channel) {\r\n this._channel.onmessage = null;\r\n this._channel.close();\r\n this._channel = undefined;\r\n }\r\n\r\n // Atualiza papel local (sem notificar — aba está sendo destruída)\r\n this._role = 'follower';\r\n\r\n // Limpa listeners\r\n this._roleListeners.clear();\r\n this._messageListeners.clear();\r\n }\r\n\r\n // ─── Estado ──────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna `true` se esta aba é atualmente a líder.\r\n */\r\n isLeader(): boolean {\r\n return !this._destroyed && this._role === 'leader';\r\n }\r\n\r\n /**\r\n * Retorna o papel atual desta aba.\r\n */\r\n getRole(): TabRole {\r\n return this._destroyed ? 'follower' : this._role;\r\n }\r\n\r\n /**\r\n * ID único desta aba (para diagnóstico).\r\n */\r\n get tabId(): string {\r\n return this._tabId;\r\n }\r\n\r\n // ─── Subscrições ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Registra um listener para mudanças de papel (`'leader'` | `'follower'`).\r\n *\r\n * @returns Função de unsubscribe.\r\n */\r\n onRoleChange(listener: RoleChangeListener): Unsubscribe {\r\n this._roleListeners.add(listener);\r\n return () => {\r\n this._roleListeners.delete(listener);\r\n };\r\n }\r\n\r\n /**\r\n * Registra um listener para mensagens recebidas de outras abas via\r\n * BroadcastChannel. O remetente NÃO recebe suas próprias mensagens.\r\n *\r\n * @returns Função de unsubscribe.\r\n */\r\n onMessage(listener: (msg: TabMessage) => void): Unsubscribe {\r\n this._messageListeners.add(listener);\r\n return () => {\r\n this._messageListeners.delete(listener);\r\n };\r\n }\r\n\r\n // ─── Comunicação ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Transmite uma mensagem para todas as outras abas via BroadcastChannel.\r\n * Sem efeito se o canal não estiver disponível ou o coordinator foi destroyed.\r\n */\r\n broadcast(msg: TabMessage): void {\r\n if (this._destroyed) return;\r\n try {\r\n this._channel?.postMessage(msg);\r\n } catch {\r\n // BroadcastChannel pode estar fechado — ignora silenciosamente\r\n }\r\n }\r\n\r\n // ─── Privado — eleição ───────────────────────────────────────────────────────\r\n\r\n /**\r\n * Inicia a disputa pelo lock Web Locks.\r\n *\r\n * `navigator.locks.request` com uma Promise-interna que nunca resolve:\r\n * enquanto a aba vive e o lock está ativo, a callback não retorna.\r\n * Ao chamar `destroy()` a Promise interna resolve → lock liberado.\r\n */\r\n private _electWithLocks(): void {\r\n const lockPromise = new Promise<void>((resolve) => {\r\n this._releaseLock = resolve;\r\n });\r\n\r\n // Notifica que esta aba está aguardando o lock (papel follower).\r\n // Feito de forma assíncrona para garantir que o chamador já registrou\r\n // seus listeners via onRoleChange() antes do primeiro disparo.\r\n Promise.resolve().then(() => {\r\n if (!this._destroyed && this._role === 'follower') {\r\n this._notifyRoleChange('follower');\r\n }\r\n });\r\n\r\n // `request` retorna uma Promise que resolve quando o lock é adquirido\r\n // e a callback retorna. Enquanto a callback não retornar, o lock é mantido.\r\n this._lockManager!.request(this._lockName, (_lock: LockLike) => {\r\n if (this._destroyed) {\r\n // Se foi destroyed antes de adquirir o lock, libera imediatamente\r\n return Promise.resolve();\r\n }\r\n this._becomeLeader();\r\n return lockPromise;\r\n }).catch(() => {\r\n // request rejeitado (ex.: lock request abortado) — sem crash\r\n });\r\n }\r\n\r\n /**\r\n * Transição para o papel de líder.\r\n */\r\n private _becomeLeader(): void {\r\n if (this._destroyed) return;\r\n this._setRole('leader');\r\n // Anuncia liderança para seguidores após o tick atual, garantindo que\r\n // todos os seguidores já registraram seus handlers de onmessage.\r\n Promise.resolve().then(() => {\r\n if (!this._destroyed) this._broadcastSyncState();\r\n });\r\n }\r\n\r\n /**\r\n * Muda o papel e notifica os listeners.\r\n */\r\n private _setRole(role: TabRole): void {\r\n const previous = this._role;\r\n this._role = role;\r\n if (previous !== role) {\r\n this._notifyRoleChange(role);\r\n }\r\n }\r\n\r\n /**\r\n * Transmite o estado de sync atual (chamado ao se tornar líder).\r\n */\r\n private _broadcastSyncState(): void {\r\n this.broadcast({\r\n type: 'sync_state',\r\n leaderTabId: this._tabId,\r\n syncing: false,\r\n pendingWrites: 0,\r\n });\r\n }\r\n\r\n // ─── Privado — mensagens ─────────────────────────────────────────────────────\r\n\r\n /**\r\n * Processa mensagem recebida de outra aba.\r\n * Mensagens de tipo desconhecido são ignoradas silenciosamente.\r\n */\r\n private _handleIncomingMessage(msg: TabMessage): void {\r\n if (this._destroyed) return;\r\n if (!msg || typeof msg.type !== 'string') return;\r\n\r\n // Entrega a todos os listeners registrados\r\n for (const listener of this._messageListeners) {\r\n try {\r\n listener(msg);\r\n } catch {\r\n // Listener com erro não interrompe os demais\r\n }\r\n }\r\n }\r\n\r\n // ─── Privado — notificações ───────────────────────────────────────────────────\r\n\r\n private _notifyRoleChange(role: TabRole): void {\r\n for (const listener of this._roleListeners) {\r\n try {\r\n listener(role);\r\n } catch {\r\n // Listener com erro não interrompe os demais\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * DbCollectionRef — superfície de Documentos offline-first do @neetru/sdk (M2).\r\n *\r\n * Implementa a API pública conforme especificada em:\r\n * - 02-sdk.md §3.2 (contrato TypeScript DbCollectionRef)\r\n * - I2-mundo-documentos.md §3.2 (superfície dupla CRUD + realtime)\r\n * - I3-sdk-offline.md §10 (camada offline, lifecycle, SyncState)\r\n *\r\n * ### Semântica de Promise de escrita (02-sdk.md §3.2 nota negrito)\r\n * `add/set/update/remove` resolvem quando a escrita está **durável localmente**\r\n * (cache + fila), NÃO quando o servidor confirma. Isso é offline-first por design:\r\n * sem rede, `add()` resolve imediatamente. Para saber quando sincronizou, o produto\r\n * observa `onWriteResult` (future / SyncEngine). A Promise só rejeita por:\r\n * - validação síncrona (nome de coleção inválido, id vazio)\r\n * - `offline_quota_exceeded` (IndexedDB cheio)\r\n *\r\n * ### Injeção do transporte realtime\r\n * O `RealtimeTransport` é injetado via `createOfflineDocumentsNamespace({ transport })`.\r\n * A implementação atual usa o `SyncEngine` para push/pull (sync offline ↔ servidor).\r\n * Transportes futuros (Firestore Web SDK / WebSocket gateway) são injetados aqui —\r\n * sem alterar a superfície pública.\r\n */\r\n\r\nimport { LocalStore } from './offline/local-store';\r\nimport { MemoryStore } from './offline/memory-store';\r\nimport { MutationQueue } from './offline/mutation-queue';\r\nimport { SyncEngine, type SyncTransport } from './offline/sync-engine';\r\nimport { ConflictResolver } from './offline/conflict-resolver';\r\nimport { ChangeBus } from './offline/change-bus';\r\nimport { ConnectivityMonitor } from './offline/connectivity-monitor';\r\nimport { TabCoordinator } from './offline/tab-coordinator';\r\nimport { NeetruDbError } from '../db-errors';\r\nimport { resolveSentinelsLocally } from './field-value';\r\nimport type { FieldSentinel } from './field-value';\r\nimport type {\r\n QueryDescriptor,\r\n Change,\r\n Unsubscribe,\r\n SyncState,\r\n ConflictRecord,\r\n} from './offline/types';\r\n\r\n// ─── Runtime detection ────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Retorna `true` quando o runtime NÃO tem IndexedDB — i.e., Node.js, Bun,\r\n * Edge Workers sem IDB (Cloudflare Workers base, Vercel Edge Runtime).\r\n *\r\n * A heurística combinada é mais robusta do que checar apenas `typeof window`:\r\n * - `typeof indexedDB === 'undefined'` → ausente no runtime atual\r\n * - `typeof window === 'undefined'` → contexto não-browser\r\n *\r\n * Qualquer uma das condições sendo verdadeira sinaliza que IndexedDB não está\r\n * disponível e o fallback MemoryStore deve ser usado.\r\n */\r\nfunction isIndexedDBUnavailable(): boolean {\r\n return (\r\n typeof indexedDB === 'undefined' ||\r\n typeof window === 'undefined'\r\n );\r\n}\r\n\r\n// ─── Re-exportar tipos públicos ───────────────────────────────────────────────\r\n\r\nexport type { DbSnapshot } from './offline/types';\r\nexport { NeetruDbError } from '../db-errors';\r\nexport {\r\n serverTimestamp,\r\n increment,\r\n isFieldSentinel,\r\n isServerTimestampSentinel,\r\n isIncrementSentinel,\r\n NEETRU_SENTINEL_KEY,\r\n} from './field-value';\r\nexport type {\r\n FieldSentinel,\r\n ServerTimestampSentinel,\r\n IncrementSentinel,\r\n} from './field-value';\r\n\r\n// ─── Tipos de escrita com sentinels ───────────────────────────────────────────\r\n\r\n/**\r\n * Permite que cada campo de `T` aceite, além do seu tipo declarado, um sentinel\r\n * de escrita server-side (`serverTimestamp()` / `increment()`).\r\n *\r\n * Sem isso, um produto que tipa `createdAt: number` veria erro de tipo ao passar\r\n * `serverTimestamp()`. Esta projeção mantém o autocomplete dos campos do produto\r\n * e ainda autoriza os sentinels onde fizer sentido.\r\n *\r\n * @example\r\n * ```ts\r\n * interface Order { total: number; createdAt: number; hits: number }\r\n * orders.add({ total: 10, createdAt: serverTimestamp(), hits: increment(1) });\r\n * ```\r\n */\r\nexport type WithFieldSentinels<T> = {\r\n [K in keyof T]: T[K] | FieldSentinel;\r\n};\r\n\r\n// ─── Tipos públicos da superfície de Documentos ───────────────────────────────\r\n\r\nexport interface DbWhereFilter {\r\n field: string;\r\n op: '==' | '!=' | '<' | '<=' | '>' | '>=' | 'array-contains' | 'in' | 'not-in';\r\n value: unknown;\r\n}\r\n\r\nexport interface DbQuery {\r\n where?: DbWhereFilter[];\r\n orderBy?: { field: string; direction?: 'asc' | 'desc' };\r\n /** Máximo de documentos. Default 20, max 500. */\r\n limit?: number;\r\n /** Cursor opaco — devolvido em `DbListResult.nextCursor`. */\r\n cursor?: string;\r\n}\r\n\r\nexport interface DbDoc<T = Record<string, unknown>> {\r\n id: string;\r\n data: T;\r\n}\r\n\r\nexport interface DbListResult<T = Record<string, unknown>> {\r\n docs: DbDoc<T>[];\r\n nextCursor: string | null;\r\n fromCache: boolean;\r\n stale: boolean;\r\n hasPendingWrites: boolean;\r\n changes: Array<{ type: 'added' | 'modified' | 'removed'; doc: DbDoc<T> }>;\r\n}\r\n\r\nexport interface DbGetResult<T = Record<string, unknown>> {\r\n docs: Array<DbDoc<T>>;\r\n fromCache: boolean;\r\n stale: boolean;\r\n hasPendingWrites: boolean;\r\n changes: Array<{ type: 'added' | 'modified' | 'removed'; doc: DbDoc<T> }>;\r\n}\r\n\r\nexport type DbChangeType = 'added' | 'modified' | 'removed';\r\n\r\n/**\r\n * Operação atômica para uso em `DbCollectionRef.batch()`.\r\n *\r\n * Discriminated union pelo campo `kind` — cada variante deixa claro\r\n * quais campos são obrigatórios:\r\n *\r\n * - `add` — insere com id gerado pelo cliente; `data` obrigatório.\r\n * - `set` — cria ou sobrescreve pelo `id`; `data` obrigatório.\r\n * - `update` — mescla campos em doc existente pelo `id`; `data` obrigatório.\r\n * - `remove` — tombstone pelo `id`; sem `data`.\r\n *\r\n * @example\r\n * ```ts\r\n * const ops: DbBatchOp[] = [\r\n * { kind: 'add', data: { name: 'produto A', price: 10 } },\r\n * { kind: 'set', id: 'sku-1', data: { name: 'produto B', price: 20 } },\r\n * { kind: 'update', id: 'sku-2', data: { price: 25 } },\r\n * { kind: 'remove', id: 'sku-3' },\r\n * ];\r\n * await col.batch(ops);\r\n * ```\r\n */\r\nexport type DbBatchOp<T = Record<string, unknown>> =\r\n | { kind: 'add'; data: WithFieldSentinels<Omit<T, 'id'>> }\r\n | { kind: 'set'; id: string; data: WithFieldSentinels<Omit<T, 'id'>> }\r\n | { kind: 'update'; id: string; data: Partial<WithFieldSentinels<Omit<T, 'id'>>> }\r\n | { kind: 'remove'; id: string };\r\n\r\n/**\r\n * Contrato do transporte de realtime — injetado no namespace.\r\n *\r\n * A implementação real usa os endpoints `/api/sdk/v1/db/*` do Core.\r\n * Em testes, usa-se um fake in-memory.\r\n *\r\n * Este é o **seam de injeção** que conecta a camada offline ao servidor real.\r\n * Transportes futuros (Firestore Web SDK direto / WebSocket gateway) são\r\n * implementados aqui, sem modificar a superfície pública `DbCollectionRef`.\r\n */\r\nexport type RealtimeTransport = SyncTransport;\r\n\r\n// ─── Validação de nome de coleção ─────────────────────────────────────────────\r\n\r\nconst COLL_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/;\r\n\r\nfunction assertValidCollection(name: string): void {\r\n if (!COLL_RE.test(name)) {\r\n throw new NeetruDbError(\r\n 'db_invalid_query',\r\n `Nome de coleção inválido: \"${name}\". Deve seguir o padrão ${COLL_RE}.`,\r\n );\r\n }\r\n}\r\n\r\nfunction assertValidId(id: string, label = 'id'): void {\r\n if (!id || typeof id !== 'string' || id.trim() === '') {\r\n throw new NeetruDbError(\r\n 'db_invalid_query',\r\n `${label} é obrigatório e deve ser uma string não-vazia.`,\r\n );\r\n }\r\n}\r\n\r\n// ─── Serialização de DbQuery → QueryDescriptor ────────────────────────────────\r\n\r\nfunction toQueryDescriptor(query?: DbQuery): QueryDescriptor {\r\n const desc: QueryDescriptor = {};\r\n\r\n if (query?.where) {\r\n desc.where = query.where.map((f) => ({\r\n field: f.field,\r\n op: f.op as import('./offline/types').WhereOp,\r\n value: f.value,\r\n }));\r\n }\r\n\r\n if (query?.orderBy) {\r\n desc.orderBy = {\r\n field: query.orderBy.field,\r\n direction: query.orderBy.direction,\r\n };\r\n }\r\n\r\n if (query?.limit !== undefined) {\r\n desc.limit = query.limit;\r\n }\r\n\r\n if (query?.cursor) {\r\n // O cursor é o docId serializado em base64\r\n try {\r\n const cursorObj = JSON.parse(atob(query.cursor)) as { docId: string; type: 'startAfter' };\r\n desc.cursor = { type: cursorObj.type ?? 'startAfter', docId: cursorObj.docId };\r\n } catch {\r\n // cursor inválido — ignora\r\n }\r\n }\r\n\r\n return desc;\r\n}\r\n\r\n/** Serializa o último doc de uma lista como cursor opaco. */\r\nfunction buildNextCursor(docs: Array<{ id: string }>, limit: number): string | null {\r\n if (docs.length < limit) return null;\r\n const lastDoc = docs[docs.length - 1];\r\n if (!lastDoc) return null;\r\n return btoa(JSON.stringify({ type: 'startAfter', docId: lastDoc.id }));\r\n}\r\n\r\n// ─── DbDocRef ─────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Referência a um documento específico.\r\n * Parte da superfície `DbCollectionRef.doc(id)`.\r\n *\r\n * Expõe as propriedades de identidade do documento de forma análoga ao\r\n * `DocumentReference` do Firestore SDK, evitando a necessidade de adaptadores\r\n * externos que reattachavam `collection` + `id` manualmente.\r\n *\r\n * @example\r\n * ```ts\r\n * const ref = orders.doc('order-123');\r\n * console.log(ref.id); // \"order-123\"\r\n * console.log(ref.collection); // \"orders\"\r\n * console.log(ref.path); // \"orders/order-123\"\r\n * ```\r\n */\r\nexport interface DbDocRef<T = Record<string, unknown>> {\r\n /** ID do documento dentro da coleção. */\r\n readonly id: string;\r\n /** Caminho completo no formato \"collection/docId\". */\r\n readonly path: string;\r\n /** Nome da coleção parent. */\r\n readonly collection: string;\r\n\r\n get(): Promise<DbGetResult<T> | null>;\r\n set(data: WithFieldSentinels<Omit<T, 'id'>>): Promise<{ ok: true }>;\r\n update(data: Partial<WithFieldSentinels<Omit<T, 'id'>>>): Promise<{ ok: true }>;\r\n remove(): Promise<{ ok: true }>;\r\n onSnapshot(cb: (snap: DbGetResult<T> | null) => void): Unsubscribe;\r\n}\r\n\r\n// ─── DbCollectionRef ──────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Referência a uma coleção — superfície dupla CRUD + realtime.\r\n *\r\n * Conforme 02-sdk.md §3.2 / I2 §3.2.\r\n */\r\nexport interface DbCollectionRef<T = Record<string, unknown>> {\r\n // ── CRUD (request/resposta offline-transparente) ──────────────────────────\r\n /** Retorna snapshot de um documento. `null` se não existir (nem no cache). */\r\n get(id: string): Promise<DbGetResult<T> | null>;\r\n /** Lista documentos com query opcional. */\r\n list(q?: DbQuery): Promise<DbListResult<T>>;\r\n /** Adiciona doc com id gerado pelo cliente (UUID v4). Durável localmente. */\r\n add(data: WithFieldSentinels<Omit<T, 'id'>>): Promise<{ ok: true; id: string }>;\r\n /** Cria ou sobrescreve um doc pelo id. Durável localmente. */\r\n set(id: string, data: WithFieldSentinels<Omit<T, 'id'>>): Promise<{ ok: true }>;\r\n /** Atualiza campos de um doc (merge). Durável localmente. */\r\n update(id: string, data: Partial<WithFieldSentinels<Omit<T, 'id'>>>): Promise<{ ok: true }>;\r\n /** Remove um doc (tombstone local). Durável localmente. */\r\n remove(id: string): Promise<{ ok: true }>;\r\n /** Aplica múltiplas operações atomicamente na fila. */\r\n batch(ops: DbBatchOp<T>[]): Promise<{ ok: true }>;\r\n\r\n // ── Realtime (listeners ao vivo) ──────────────────────────────────────────\r\n /** Escuta um documento específico. */\r\n onDoc(id: string, cb: (doc: T | null) => void): Unsubscribe;\r\n /** Escuta a coleção inteira (ou subconjunto via query). */\r\n onSnapshot(q: DbQuery | undefined, cb: (snap: DbListResult<T>) => void): Unsubscribe;\r\n\r\n // ── DbDocRef ──────────────────────────────────────────────────────────────\r\n /** Retorna uma referência ao documento `id`. */\r\n doc(id: string): DbDocRef<T>;\r\n}\r\n\r\n// ─── NeetruDbDocuments namespace ─────────────────────────────────────────────\r\n\r\n/**\r\n * Namespace `db.documents` — ponto de entrada para coleções de documentos.\r\n *\r\n * Analogia a `NeetruDb` de 02-sdk.md §3.1 mas escoped para o Mundo Documentos.\r\n */\r\nexport interface NeetruDbDocuments {\r\n collection<T = Record<string, unknown>>(name: string): DbCollectionRef<T>;\r\n /** Estado atual de sincronização (offline/online/syncing). */\r\n readonly syncState: SyncState;\r\n onSyncStateChanged(cb: (s: SyncState) => void): Unsubscribe;\r\n /** Força flush da fila de mutações pendentes. */\r\n flush(): Promise<void>;\r\n /** Limpa o cache local (IndexedDB) — operação destrutiva. */\r\n clearCache(): Promise<void>;\r\n /**\r\n * Retorna os registros do log de conflitos LWW gravados pelo SyncEngine.\r\n * Um conflito ocorre quando a mutação local é descartada porque o servidor\r\n * já avançou a versão do documento (Last-Write-Wins).\r\n */\r\n getConflicts(): Promise<ConflictRecord[]>;\r\n}\r\n\r\n// ─── Opções de criação do namespace ──────────────────────────────────────────\r\n\r\nexport interface CreateOfflineDocumentsOptions {\r\n /**\r\n * Nome do banco IndexedDB — deve ser único por produto × dbId × env.\r\n * Convenção: `neetru-db__{productSlug}__{dbId}__{env}`.\r\n */\r\n dbName: string;\r\n\r\n /**\r\n * Transporte de sync — implementa `SyncTransport` do SyncEngine.\r\n * Este é o **seam de injeção** do transporte real.\r\n *\r\n * Implementações possíveis:\r\n * - `RestSyncTransport` — REST → Core (padrão em staging/prod)\r\n * - `FirestoreRealtimeTransport` — Firestore Web SDK direto (engine=firestore)\r\n * - `WebSocketTransport` — WebSocket → gateway (engine=nosql-vm)\r\n * - `FakeRealtimeTransport` — in-memory (testes)\r\n */\r\n transport: RealtimeTransport;\r\n\r\n /**\r\n * Estado inicial de conectividade.\r\n * Default: `navigator.onLine` se disponível, senão `true`.\r\n */\r\n startOnline?: boolean;\r\n\r\n /**\r\n * `true` = sem contenção multi-aba (sempre líder).\r\n * Padrão em testes; em produção usa Web Locks.\r\n */\r\n singleTab?: boolean;\r\n\r\n /**\r\n * Intervalo do sync periódico em ms. `0` desativa.\r\n * Default: 5 * 60 * 1000 (5min).\r\n */\r\n periodicSyncIntervalMs?: number;\r\n}\r\n\r\n// ─── Implementação interna ────────────────────────────────────────────────────\r\n\r\n/**\r\n * Implementação de `DbCollectionRef` que usa a camada offline real.\r\n */\r\nclass DbCollectionRefImpl<T = Record<string, unknown>> implements DbCollectionRef<T> {\r\n constructor(\r\n private readonly _collection: string,\r\n private readonly _store: LocalStore,\r\n private readonly _queue: MutationQueue,\r\n private readonly _bus: ChangeBus,\r\n private readonly _engine: SyncEngine,\r\n private readonly _connectivity: ConnectivityMonitor,\r\n ) {}\r\n\r\n // ── helpers ────────────────────────────────────────────────────────────────\r\n\r\n /** Verifica se há mutações pendentes para esta coleção. */\r\n private async _hasPendingWrites(): Promise<boolean> {\r\n const pending = await this._queue.listPending();\r\n return pending.some((m) => m.collection === this._collection);\r\n }\r\n\r\n /** Verifica se há mutações pendentes para um doc específico. */\r\n private async _docHasPendingWrites(id: string): Promise<boolean> {\r\n const pending = await this._queue.listPending();\r\n return pending.some((m) => m.collection === this._collection && m.docId === id);\r\n }\r\n\r\n private _isOnline(): boolean {\r\n return this._connectivity.isOnline;\r\n }\r\n\r\n /** Constrói um DbGetResult para um doc específico, ou null se tombstoned/ausente. */\r\n private async _buildGetResult(id: string): Promise<DbGetResult<T> | null> {\r\n const doc = await this._store.getDoc<T>(this._collection, id);\r\n if (!doc || doc.meta.deleted) return null;\r\n\r\n const hasPending = await this._docHasPendingWrites(id);\r\n const isOnline = this._isOnline();\r\n const syncState = this._engine.getSyncState();\r\n\r\n const staleGet = !isOnline || syncState.status === 'offline';\r\n const fromCacheGet = hasPending || syncState.lastSyncedAt === null || staleGet;\r\n\r\n return {\r\n docs: [{ id: doc.id, data: doc.data }],\r\n fromCache: fromCacheGet,\r\n stale: staleGet,\r\n hasPendingWrites: hasPending,\r\n changes: [],\r\n };\r\n }\r\n\r\n /** Constrói um DbListResult para a coleção com query opcional. */\r\n private async _buildListResult(q?: DbQuery): Promise<DbListResult<T>> {\r\n const desc = toQueryDescriptor(q);\r\n const effectiveLimit = desc.limit ?? 20;\r\n const result = await this._store.listDocs<T>(this._collection, desc);\r\n\r\n const hasPending = await this._hasPendingWrites();\r\n const isOnline = this._isOnline();\r\n const syncState = this._engine.getSyncState();\r\n\r\n const nextCursor = buildNextCursor(result.docs, effectiveLimit);\r\n\r\n // fromCache: false quando há um lastSyncedAt confirmado e sem pending writes.\r\n // offline-first: antes do primeiro sync bem-sucedido é sempre fromCache:true.\r\n const stale = !isOnline || syncState.status === 'offline';\r\n const fromCache = hasPending || syncState.lastSyncedAt === null || stale;\r\n\r\n return {\r\n docs: result.docs.map((d) => ({ id: d.id, data: d.data })),\r\n nextCursor,\r\n fromCache,\r\n stale,\r\n hasPendingWrites: hasPending,\r\n changes: [],\r\n };\r\n }\r\n\r\n // ── CRUD ────────────────────────────────────────────────────────────────────\r\n\r\n async get(id: string): Promise<DbGetResult<T> | null> {\r\n assertValidId(id);\r\n return this._buildGetResult(id);\r\n }\r\n\r\n async list(q?: DbQuery): Promise<DbListResult<T>> {\r\n return this._buildListResult(q);\r\n }\r\n\r\n async add(data: WithFieldSentinels<Omit<T, 'id'>>): Promise<{ ok: true; id: string }> {\r\n // O payload da mutação carrega os sentinels CRUS (serverTimestamp/increment)\r\n // — o Core os resolve canonicamente na escrita. O cache local recebe uma\r\n // aproximação otimista (Date.now() / soma local) para a UI não piscar.\r\n const rawData = data as Record<string, unknown>;\r\n const localData = resolveSentinelsLocally(rawData, undefined);\r\n\r\n const mutation = await this._queue.enqueue({\r\n collection: this._collection,\r\n op: 'add',\r\n payload: rawData,\r\n baseVersion: null,\r\n batchId: null,\r\n });\r\n\r\n const docId = mutation.docId;\r\n\r\n // Aplica otimisticamente no LocalStore\r\n await this._store.putDoc({\r\n collection: this._collection,\r\n id: docId,\r\n data: localData,\r\n meta: {\r\n serverVersion: null,\r\n updatedAtServer: null,\r\n updatedAtLocal: Date.now(),\r\n state: 'pending',\r\n pendingMutationIds: [mutation.mutationId],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n });\r\n\r\n // Notifica listeners\r\n this._bus.emit([{\r\n type: 'added',\r\n collection: this._collection,\r\n doc: { id: docId, data: localData },\r\n }]);\r\n\r\n return { ok: true, id: docId };\r\n }\r\n\r\n async set(id: string, data: WithFieldSentinels<Omit<T, 'id'>>): Promise<{ ok: true }> {\r\n assertValidId(id);\r\n\r\n const existing = await this._store.getDoc(this._collection, id);\r\n const rawData = data as Record<string, unknown>;\r\n // set substitui o doc inteiro — increment usa base 0 (não o doc anterior),\r\n // espelhando a semântica do Core (`ref.set(...)` sem merge).\r\n const localData = resolveSentinelsLocally(rawData, undefined);\r\n\r\n const mutation = await this._queue.enqueue({\r\n collection: this._collection,\r\n docId: id,\r\n op: 'set',\r\n payload: rawData,\r\n baseVersion: existing?.meta.serverVersion ?? null,\r\n batchId: null,\r\n });\r\n\r\n // Aplica otimisticamente\r\n await this._store.putDoc({\r\n collection: this._collection,\r\n id,\r\n data: localData,\r\n meta: {\r\n serverVersion: existing?.meta.serverVersion ?? null,\r\n updatedAtServer: existing?.meta.updatedAtServer ?? null,\r\n updatedAtLocal: Date.now(),\r\n state: 'pending',\r\n pendingMutationIds: [mutation.mutationId],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n });\r\n\r\n this._bus.emit([{\r\n type: existing && !existing.meta.deleted ? 'modified' : 'added',\r\n collection: this._collection,\r\n doc: { id, data: localData },\r\n }]);\r\n\r\n return { ok: true };\r\n }\r\n\r\n async update(id: string, data: Partial<WithFieldSentinels<Omit<T, 'id'>>>): Promise<{ ok: true }> {\r\n assertValidId(id);\r\n\r\n const existing = await this._store.getDoc(this._collection, id);\r\n const rawData = data as Record<string, unknown>;\r\n // Resolve sentinels otimisticamente contra o doc atual (base de increment).\r\n // Em doc deletado, increment parte de 0 (não há valor anterior válido).\r\n const existingBase = existing?.meta.deleted ? undefined : existing?.data;\r\n const localData = resolveSentinelsLocally(rawData, existingBase);\r\n const mergedData = existing?.meta.deleted\r\n ? { ...localData }\r\n : { ...(existing?.data ?? {}), ...localData };\r\n\r\n const mutation = await this._queue.enqueue({\r\n collection: this._collection,\r\n docId: id,\r\n op: 'update',\r\n payload: rawData,\r\n baseVersion: existing?.meta.serverVersion ?? null,\r\n batchId: null,\r\n });\r\n\r\n await this._store.putDoc({\r\n collection: this._collection,\r\n id,\r\n data: mergedData,\r\n meta: {\r\n serverVersion: existing?.meta.serverVersion ?? null,\r\n updatedAtServer: existing?.meta.updatedAtServer ?? null,\r\n updatedAtLocal: Date.now(),\r\n state: 'pending',\r\n pendingMutationIds: [\r\n ...(existing?.meta.pendingMutationIds ?? []),\r\n mutation.mutationId,\r\n ],\r\n deleted: false,\r\n ownerId: existing?.meta.ownerId ?? null,\r\n },\r\n });\r\n\r\n this._bus.emit([{\r\n type: 'modified',\r\n collection: this._collection,\r\n doc: { id, data: mergedData },\r\n }]);\r\n\r\n return { ok: true };\r\n }\r\n\r\n async remove(id: string): Promise<{ ok: true }> {\r\n assertValidId(id);\r\n\r\n const existing = await this._store.getDoc(this._collection, id);\r\n if (!existing || existing.meta.deleted) {\r\n // Se era um doc add-only ainda na fila, o coalescing no MutationQueue vai lidar\r\n }\r\n\r\n await this._queue.enqueue({\r\n collection: this._collection,\r\n docId: id,\r\n op: 'remove',\r\n payload: null,\r\n baseVersion: existing?.meta.serverVersion ?? null,\r\n batchId: null,\r\n });\r\n\r\n // Tombstone otimístico\r\n await this._store.deleteDoc(this._collection, id);\r\n\r\n if (existing && !existing.meta.deleted) {\r\n this._bus.emit([{\r\n type: 'removed',\r\n collection: this._collection,\r\n doc: { id, data: existing.data },\r\n }]);\r\n }\r\n\r\n return { ok: true };\r\n }\r\n\r\n async batch(ops: DbBatchOp<T>[]): Promise<{ ok: true }> {\r\n const batchId = `batch-${Date.now()}-${Math.random().toString(36).slice(2)}`;\r\n const busChanges: Change[] = [];\r\n\r\n for (const op of ops) {\r\n const collection = this._collection;\r\n\r\n if (op.kind === 'add') {\r\n const data = op.data as Record<string, unknown>;\r\n const localData = resolveSentinelsLocally(data, undefined);\r\n const mutation = await this._queue.enqueue({\r\n collection,\r\n op: 'add',\r\n payload: data,\r\n baseVersion: null,\r\n batchId,\r\n });\r\n const docId = mutation.docId;\r\n await this._store.putDoc({\r\n collection,\r\n id: docId,\r\n data: localData,\r\n meta: {\r\n serverVersion: null,\r\n updatedAtServer: null,\r\n updatedAtLocal: Date.now(),\r\n state: 'pending',\r\n pendingMutationIds: [mutation.mutationId],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n });\r\n busChanges.push({ type: 'added', collection, doc: { id: docId, data: localData } });\r\n } else if (op.kind === 'set') {\r\n const id = op.id;\r\n const data = op.data as Record<string, unknown>;\r\n const existing = await this._store.getDoc(collection, id);\r\n const localData = resolveSentinelsLocally(data, undefined);\r\n const mutation = await this._queue.enqueue({\r\n collection,\r\n docId: id,\r\n op: 'set',\r\n payload: data,\r\n baseVersion: existing?.meta.serverVersion ?? null,\r\n batchId,\r\n });\r\n await this._store.putDoc({\r\n collection,\r\n id,\r\n data: localData,\r\n meta: {\r\n serverVersion: existing?.meta.serverVersion ?? null,\r\n updatedAtServer: existing?.meta.updatedAtServer ?? null,\r\n updatedAtLocal: Date.now(),\r\n state: 'pending',\r\n pendingMutationIds: [mutation.mutationId],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n });\r\n busChanges.push({\r\n type: existing && !existing.meta.deleted ? 'modified' : 'added',\r\n collection,\r\n doc: { id, data: localData },\r\n });\r\n } else if (op.kind === 'update') {\r\n const id = op.id;\r\n const data = op.data as Record<string, unknown>;\r\n const existing = await this._store.getDoc(collection, id);\r\n const existingBase = existing?.meta.deleted ? undefined : existing?.data;\r\n const localData = resolveSentinelsLocally(data, existingBase);\r\n const merged = { ...(existing?.data ?? {}), ...localData };\r\n const mutation = await this._queue.enqueue({\r\n collection,\r\n docId: id,\r\n op: 'update',\r\n payload: data,\r\n baseVersion: existing?.meta.serverVersion ?? null,\r\n batchId,\r\n });\r\n await this._store.putDoc({\r\n collection,\r\n id,\r\n data: merged,\r\n meta: {\r\n serverVersion: existing?.meta.serverVersion ?? null,\r\n updatedAtServer: existing?.meta.updatedAtServer ?? null,\r\n updatedAtLocal: Date.now(),\r\n state: 'pending',\r\n pendingMutationIds: [\r\n ...(existing?.meta.pendingMutationIds ?? []),\r\n mutation.mutationId,\r\n ],\r\n deleted: false,\r\n ownerId: existing?.meta.ownerId ?? null,\r\n },\r\n });\r\n busChanges.push({ type: 'modified', collection, doc: { id, data: merged } });\r\n } else if (op.kind === 'remove') {\r\n const id = op.id;\r\n const existing = await this._store.getDoc(collection, id);\r\n await this._queue.enqueue({\r\n collection,\r\n docId: id,\r\n op: 'remove',\r\n payload: null,\r\n baseVersion: existing?.meta.serverVersion ?? null,\r\n batchId,\r\n });\r\n await this._store.deleteDoc(collection, id);\r\n if (existing && !existing.meta.deleted) {\r\n busChanges.push({ type: 'removed', collection, doc: { id, data: existing.data } });\r\n }\r\n }\r\n }\r\n\r\n if (busChanges.length > 0) {\r\n this._bus.emit(busChanges);\r\n }\r\n\r\n return { ok: true };\r\n }\r\n\r\n // ── Realtime ─────────────────────────────────────────────────────────────────\r\n\r\n onDoc(id: string, cb: (doc: T | null) => void): Unsubscribe {\r\n assertValidId(id);\r\n\r\n // Entrega inicial imediata\r\n this._buildGetResult(id)\r\n .then((r) => {\r\n cb(r ? (r.docs[0]?.data ?? null) as T | null : null);\r\n })\r\n .catch(() => cb(null));\r\n\r\n // Subscreve ao bus da coleção para receber mudanças\r\n return this._bus.subscribe(this._collection, (changes) => {\r\n const relevant = changes.find((c) => c.doc.id === id);\r\n if (!relevant) return;\r\n\r\n if (relevant.type === 'removed') {\r\n cb(null);\r\n } else {\r\n cb(relevant.doc.data as T);\r\n }\r\n });\r\n }\r\n\r\n onSnapshot(q: DbQuery | undefined, cb: (snap: DbListResult<T>) => void): Unsubscribe {\r\n // Entrega inicial imediata (estado atual do cache)\r\n this._buildListResult(q).then((snap) => cb(snap)).catch(() => {});\r\n\r\n // Listener de mudanças do bus (local + server-pushed)\r\n const unsubBus = this._bus.subscribe(this._collection, async (_changes) => {\r\n try {\r\n // Reconstrói o snapshot completo com o estado atual + changes delta\r\n const snap = await this._buildListResult(q);\r\n\r\n // Injeta delta de changes (apenas os relevantes para a query)\r\n const delta = _changes.map((c) => ({\r\n type: c.type as DbChangeType,\r\n doc: { id: c.doc.id, data: c.doc.data as T },\r\n }));\r\n cb({ ...snap, changes: delta });\r\n } catch {\r\n // silencioso\r\n }\r\n });\r\n\r\n // Listener de mudanças de SyncState (para atualizar stale/fromCache)\r\n const unsubSync = this._engine.onSyncStateChange(async () => {\r\n try {\r\n const snap = await this._buildListResult(q);\r\n cb(snap);\r\n } catch {\r\n // silencioso\r\n }\r\n });\r\n\r\n // HIGH-1: se o transporte expõe subscribeCollection (nosql-vm/realtime),\r\n // registra a subscription e alimenta os deltas no ChangeBus local.\r\n let unsubRealtime: (() => void) | undefined;\r\n if (typeof (this._engine.transport as SyncTransport).subscribeCollection === 'function') {\r\n unsubRealtime = (this._engine.transport as SyncTransport).subscribeCollection!(\r\n this._collection,\r\n async (remoteChanges, needsResync) => {\r\n if (needsResync) {\r\n // Marca sincronização necessária via SyncState — o SyncEngine\r\n // disparará um fullResync no próximo ciclo.\r\n return;\r\n }\r\n // Converte as mudanças remotas para Change[] e aplica no LocalStore\r\n for (const rc of remoteChanges) {\r\n if (rc.type === 'removed' || rc.data === null) {\r\n await this._store.deleteDoc(this._collection, rc.docId);\r\n this._bus.emit([{\r\n type: 'removed',\r\n collection: this._collection,\r\n doc: { id: rc.docId, data: {} as Record<string, unknown> },\r\n }]);\r\n } else {\r\n await this._store.putDoc({\r\n collection: this._collection,\r\n id: rc.docId,\r\n data: rc.data,\r\n meta: {\r\n serverVersion: `rt_${Date.now()}`,\r\n updatedAtServer: Date.now(),\r\n updatedAtLocal: Date.now(),\r\n state: 'synced',\r\n pendingMutationIds: [],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n });\r\n this._bus.emit([{\r\n type: rc.type,\r\n collection: this._collection,\r\n doc: { id: rc.docId, data: rc.data },\r\n }]);\r\n }\r\n }\r\n },\r\n );\r\n }\r\n\r\n return () => {\r\n unsubBus();\r\n unsubSync();\r\n unsubRealtime?.();\r\n };\r\n }\r\n\r\n doc(id: string): DbDocRef<T> {\r\n assertValidId(id);\r\n const self = this;\r\n\r\n return {\r\n get id(): string { return id; },\r\n get path(): string { return `${self._collection}/${id}`; },\r\n get collection(): string { return self._collection; },\r\n\r\n async get(): Promise<DbGetResult<T> | null> {\r\n return self._buildGetResult(id);\r\n },\r\n async set(data: WithFieldSentinels<Omit<T, 'id'>>): Promise<{ ok: true }> {\r\n return self.set(id, data);\r\n },\r\n async update(data: Partial<WithFieldSentinels<Omit<T, 'id'>>>): Promise<{ ok: true }> {\r\n return self.update(id, data);\r\n },\r\n async remove(): Promise<{ ok: true }> {\r\n return self.remove(id);\r\n },\r\n onSnapshot(cb: (snap: DbGetResult<T> | null) => void): Unsubscribe {\r\n // Entrega inicial\r\n self._buildGetResult(id).then((r) => cb(r)).catch(() => cb(null));\r\n\r\n const unsubBus = self._bus.subscribe(self._collection, async (changes) => {\r\n const relevant = changes.find((c) => c.doc.id === id);\r\n if (!relevant) return;\r\n try {\r\n if (relevant.type === 'removed') {\r\n cb(null);\r\n } else {\r\n const result = await self._buildGetResult(id);\r\n cb(result);\r\n }\r\n } catch {\r\n cb(null);\r\n }\r\n });\r\n\r\n const unsubSync = self._engine.onSyncStateChange(async () => {\r\n try {\r\n const result = await self._buildGetResult(id);\r\n cb(result);\r\n } catch {\r\n cb(null);\r\n }\r\n });\r\n\r\n return () => {\r\n unsubBus();\r\n unsubSync();\r\n };\r\n },\r\n };\r\n }\r\n}\r\n\r\n// ─── Implementação de NeetruDbDocuments ──────────────────────────────────────\r\n\r\nclass NeetruDbDocumentsImpl implements NeetruDbDocuments {\r\n private readonly _store: LocalStore;\r\n private readonly _queue: MutationQueue;\r\n private readonly _bus: ChangeBus;\r\n private readonly _engine: SyncEngine;\r\n private readonly _connectivity: ConnectivityMonitor;\r\n\r\n constructor(opts: {\r\n store: LocalStore;\r\n queue: MutationQueue;\r\n bus: ChangeBus;\r\n engine: SyncEngine;\r\n connectivity: ConnectivityMonitor;\r\n }) {\r\n this._store = opts.store;\r\n this._queue = opts.queue;\r\n this._bus = opts.bus;\r\n this._engine = opts.engine;\r\n this._connectivity = opts.connectivity;\r\n }\r\n\r\n collection<T = Record<string, unknown>>(name: string): DbCollectionRef<T> {\r\n assertValidCollection(name);\r\n return new DbCollectionRefImpl<T>(\r\n name,\r\n this._store,\r\n this._queue,\r\n this._bus,\r\n this._engine,\r\n this._connectivity,\r\n );\r\n }\r\n\r\n get syncState(): SyncState {\r\n return this._engine.getSyncState();\r\n }\r\n\r\n onSyncStateChanged(cb: (s: SyncState) => void): Unsubscribe {\r\n return this._engine.onSyncStateChange(cb);\r\n }\r\n\r\n async flush(): Promise<void> {\r\n return this._engine.flush();\r\n }\r\n\r\n async clearCache(): Promise<void> {\r\n // BUG fix: `close()` + `open()` apenas reabre o mesmo banco IndexedDB sem\r\n // apagar os dados. `clearAll()` chama `indexedDB.deleteDatabase()` (LocalStore)\r\n // ou limpa os Maps internos (MemoryStore) antes de reabrir — dados realmente\r\n // descartados. Cast necessário porque `store` é tipado como `LocalStore` mas\r\n // em runtime pode ser `MemoryStore` (fallback para Node/Edge sem IndexedDB).\r\n const storeWithClear = this._store as unknown as { clearAll?: () => Promise<void> };\r\n if (typeof storeWithClear.clearAll === 'function') {\r\n await storeWithClear.clearAll();\r\n } else {\r\n // Fallback defensivo para stores customizadas sem clearAll.\r\n await this._store.close();\r\n await this._store.open();\r\n }\r\n }\r\n\r\n async getConflicts(): Promise<ConflictRecord[]> {\r\n return this._store.listConflicts();\r\n }\r\n}\r\n\r\n// ─── Factory pública ─────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Cria e inicializa o namespace de documentos offline-first.\r\n *\r\n * Configura todos os 8 componentes da camada offline (LocalStore, MutationQueue,\r\n * QueryEngine, SyncEngine, ConflictResolver, ConnectivityMonitor, TabCoordinator,\r\n * ChangeBus) e os liga ao `RealtimeTransport` injetado.\r\n *\r\n * @example\r\n * ```ts\r\n * // Em produção (transport real injetado pelo resolver do Core):\r\n * const ns = await createOfflineDocumentsNamespace({\r\n * dbName: 'neetru-db__my-product__db1__production',\r\n * transport: new RestSyncTransport(config),\r\n * });\r\n * const orders = ns.collection<Order>('orders');\r\n *\r\n * // Realtime:\r\n * const unsub = orders.onSnapshot({ where: [{ field: 'status', op: '==', value: 'open' }] }, snap => {\r\n * renderOrders(snap.docs);\r\n * });\r\n * ```\r\n */\r\nexport async function createOfflineDocumentsNamespace(\r\n opts: CreateOfflineDocumentsOptions,\r\n): Promise<NeetruDbDocuments> {\r\n // bug_ba287a — fallback para MemoryStore quando IndexedDB não está disponível\r\n // (Node.js, Bun, Edge Workers sem IDB). Sem necessidade de flag explícita:\r\n // a detecção é automática via presença de `indexedDB` e `window` no runtime.\r\n //\r\n // MemoryStore implementa exatamente o mesmo contrato público de LocalStore —\r\n // o cast é seguro e evita modificar os tipos de SyncEngine/MutationQueue.\r\n const store = (\r\n isIndexedDBUnavailable()\r\n ? new MemoryStore()\r\n : new LocalStore(opts.dbName)\r\n ) as unknown as LocalStore;\r\n await store.open();\r\n\r\n const queue = new MutationQueue(store);\r\n const resolver = new ConflictResolver();\r\n const bus = new ChangeBus();\r\n\r\n const connectivity = new ConnectivityMonitor({\r\n // Se startOnline=false, injeta um navigator falso\r\n navigator: opts.startOnline === false\r\n ? { onLine: false }\r\n : (typeof navigator !== 'undefined' ? navigator : undefined),\r\n });\r\n\r\n // TabCoordinator — singleTab = sem eleição (sempre líder)\r\n const tabCoordinatorLike = opts.singleTab\r\n ? // Fake tab coordinator para single-tab mode (sempre líder)\r\n {\r\n isLeader: () => true,\r\n onRoleChange: (_cb: (role: 'leader' | 'follower') => void): Unsubscribe => {\r\n return () => {};\r\n },\r\n }\r\n : new TabCoordinator({\r\n lockName: `neetru-offline:${opts.dbName}`,\r\n channelName: `neetru-offline:${opts.dbName}`,\r\n });\r\n\r\n const engine = new SyncEngine({\r\n store,\r\n queue,\r\n resolver,\r\n bus,\r\n transport: opts.transport,\r\n tabCoordinator: tabCoordinatorLike,\r\n connectivity,\r\n periodicSyncIntervalMs: opts.periodicSyncIntervalMs ?? 5 * 60 * 1000,\r\n });\r\n\r\n return new NeetruDbDocumentsImpl({\r\n store,\r\n queue,\r\n bus,\r\n engine,\r\n connectivity,\r\n });\r\n}\r\n","/**\r\n * NeetruRealtimeClient — cliente WebSocket multiplexado do gateway (M3).\r\n *\r\n * Componente #18 do relatório central do Conselho Neetru Core DB.\r\n * Par cliente do serviço `neetru-realtime` (componente #19,\r\n * `@neetru/realtime-transport`).\r\n *\r\n * Responsabilidades:\r\n * - Manter EXATAMENTE UMA conexão WebSocket ao gateway.\r\n * - Multiplexar N subscriptions independentes sobre ela.\r\n * - Reconectar com backoff exponencial + jitter em caso de queda.\r\n * - Em reconexão, reenviar todos os frames `subscribe` ativos.\r\n * - Responder / enviar heartbeat ping/pong por protocolo.\r\n * - Rotear frames inbound para o callback correto por `subscriptionId`.\r\n * - Emitir mudanças de `ConnectionState` para observadores externos.\r\n *\r\n * Protocolo de frames (contrato inlined em `./types.ts` — MASTER-CRIT-038):\r\n * ENVIA → `subscribe` | `unsubscribe` | `ping`\r\n * RECEBE ← `delta` | `resync` | `stale` | `error` | `pong` | `drain`\r\n *\r\n * Deps: ZERO externas. Apenas WebSocket nativo (injetável).\r\n *\r\n * Nota: a integração de `NeetruRealtimeClient` na superfície pública\r\n * `client.db` é um follow-up deliberado — ver seção de pendências no\r\n * relatório de entrega.\r\n */\r\n\r\nimport type {\r\n RealtimeClientOptions,\r\n WebSocketLike,\r\n WebSocketFactory,\r\n OutboundFrame,\r\n InboundFrame,\r\n ConnectionState,\r\n ConnectionStateListener,\r\n SubscriptionCallback,\r\n SubscriptionEntry,\r\n RealtimeQuery,\r\n TicketProvider,\r\n RealtimeTicket,\r\n} from './types';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constantes\r\n// ---------------------------------------------------------------------------\r\n\r\n/** readyState WebSocket conforme especificação WHATWG. */\r\nconst WS_OPEN = 1;\r\n// const WS_CLOSING = 2; // não usado diretamente\r\nconst WS_CLOSED = 3;\r\n\r\n/** Fator multiplicador do jitter. O delay efetivo = base * jitter, onde\r\n * jitter ∈ [0.5, 1.5] (±50%). */\r\nconst JITTER_MIN = 0.5;\r\nconst JITTER_MAX = 1.5;\r\n\r\n/** Defaults */\r\nconst DEFAULT_BACKOFF_BASE_MS = 1_000;\r\nconst DEFAULT_BACKOFF_MAX_MS = 30_000;\r\nconst DEFAULT_HEARTBEAT_INTERVAL_MS = 25_000;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Geração de IDs\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Gera um ID de subscription único por instância.\r\n * Usa `crypto.randomUUID()` quando disponível (browser/Node 20+);\r\n * fallback para contador + Math.random() em ambientes sem crypto.\r\n */\r\nlet _idCounter = 0;\r\nfunction generateId(): string {\r\n if (typeof globalThis.crypto?.randomUUID === 'function') {\r\n return globalThis.crypto.randomUUID();\r\n }\r\n return `nrt-sub-${Date.now()}-${++_idCounter}-${Math.random().toString(36).slice(2)}`;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// NeetruRealtimeClient\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Cliente WebSocket multiplexado do gateway `neetru-realtime`.\r\n *\r\n * @example\r\n * ```ts\r\n * const rt = new NeetruRealtimeClient({\r\n * gatewayUrl: 'wss://realtime.neetru.com/ws',\r\n * });\r\n *\r\n * const subId = rt.subscribe('orders', { filter: { status: 'open' } }, (frame) => {\r\n * if (frame.op === 'delta') applyChanges(frame.changes);\r\n * if (frame.op === 'resync') fullReload();\r\n * });\r\n *\r\n * rt.onConnectionState((state) => console.log('connection:', state));\r\n *\r\n * // Para parar:\r\n * rt.unsubscribe(subId);\r\n * rt.close();\r\n * ```\r\n */\r\nexport class NeetruRealtimeClient {\r\n // ── configuração ──────────────────────────────────────────────────────────\r\n private readonly _gatewayUrl: string;\r\n private readonly _wsFactory: WebSocketFactory;\r\n private readonly _setTimeout: typeof setTimeout;\r\n private readonly _clearTimeout: typeof clearTimeout;\r\n private readonly _backoffBaseMs: number;\r\n private readonly _backoffMaxMs: number;\r\n private readonly _heartbeatIntervalMs: number;\r\n private readonly _ticketProvider: TicketProvider;\r\n /** ID do banco lógico (BL-8) — embutido em query.filter._dbId de cada subscribe. */\r\n private readonly _dbId: string | undefined;\r\n\r\n /** Ticket atual — obtido antes de cada abertura de WS e embutido nos frames. */\r\n private _currentTicket: RealtimeTicket | null = null;\r\n\r\n // ── estado interno ────────────────────────────────────────────────────────\r\n\r\n /** Subscriptions ativas: id → entry */\r\n private _subscriptions = new Map<string, SubscriptionEntry>();\r\n\r\n /** Listeners do estado da conexão. */\r\n private _stateListeners: Array<ConnectionStateListener> = [];\r\n\r\n /** Estado atual da conexão. */\r\n private _connectionState: ConnectionState = 'connecting';\r\n\r\n /** Socket atual (pode ser null entre tentativas). */\r\n private _ws: WebSocketLike | null = null;\r\n\r\n /** Número da tentativa de reconexão corrente (reseta após conexão bem-sucedida). */\r\n private _reconnectAttempt = 0;\r\n\r\n /** Handle do timer de backoff pendente. */\r\n private _reconnectTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n /** Handle do timer de heartbeat. */\r\n private _heartbeatTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n /** Indica que o cliente foi encerrado via `close()`. Não reconecta mais. */\r\n private _closed = false;\r\n\r\n /**\r\n * Frames de subscribe que precisam ser enviados mas a socket ainda não\r\n * está aberta (estado CONNECTING). Drenados no onopen.\r\n */\r\n private _pendingFrames: OutboundFrame[] = [];\r\n\r\n // ── construtor ────────────────────────────────────────────────────────────\r\n\r\n constructor(options: RealtimeClientOptions) {\r\n this._gatewayUrl = options.gatewayUrl;\r\n\r\n this._wsFactory = options.webSocketFactory ?? defaultWebSocketFactory;\r\n\r\n this._setTimeout = options.setTimeoutFn ?? globalThis.setTimeout.bind(globalThis);\r\n this._clearTimeout = options.clearTimeoutFn ?? globalThis.clearTimeout.bind(globalThis);\r\n\r\n this._backoffBaseMs = options.backoffBaseMs ?? DEFAULT_BACKOFF_BASE_MS;\r\n this._backoffMaxMs = options.backoffMaxMs ?? DEFAULT_BACKOFF_MAX_MS;\r\n this._heartbeatIntervalMs =\r\n options.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;\r\n\r\n this._ticketProvider = options.ticketProvider;\r\n this._dbId = options.dbId;\r\n\r\n // Inicia a conexão imediatamente (busca ticket antes de abrir o WS).\r\n this._connect();\r\n }\r\n\r\n // ── API pública ───────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Registra uma subscription em `collection` com `query` opcional.\r\n *\r\n * Envia um frame `subscribe` ao gateway (ou enfileira se o socket ainda\r\n * não está aberto). O `callback` é invocado com cada frame `delta`,\r\n * `resync`, `stale` ou `error` roteado para esta subscription.\r\n *\r\n * @returns O `subscriptionId` opaco — usar para cancelar via `unsubscribe()`.\r\n */\r\n subscribe(\r\n collection: string,\r\n query: RealtimeQuery,\r\n callback: SubscriptionCallback,\r\n ): string {\r\n if (this._closed) {\r\n // Cliente encerrado — retorna um id fictício sem efeito.\r\n return generateId();\r\n }\r\n\r\n const subscriptionId = generateId();\r\n this._subscriptions.set(subscriptionId, {\r\n subscriptionId,\r\n collection,\r\n query: Object.keys(query).length > 0 ? query : undefined,\r\n callback,\r\n });\r\n\r\n const frame: OutboundFrame = {\r\n op: 'subscribe',\r\n subscriptionId,\r\n collection,\r\n query: this._buildSubscribeQuery(query),\r\n };\r\n\r\n this._sendOrBuffer(frame);\r\n return subscriptionId;\r\n }\r\n\r\n /**\r\n * Cancela uma subscription.\r\n *\r\n * Envia um frame `unsubscribe` ao gateway e remove o listener local.\r\n * Frames subsequentes com este `subscriptionId` são silenciosamente descartados.\r\n */\r\n unsubscribe(subscriptionId: string): void {\r\n if (!this._subscriptions.has(subscriptionId)) {\r\n // id desconhecido — sem efeito (não lança erro).\r\n return;\r\n }\r\n\r\n this._subscriptions.delete(subscriptionId);\r\n\r\n const frame: OutboundFrame = { op: 'unsubscribe', subscriptionId };\r\n this._sendOrBuffer(frame);\r\n }\r\n\r\n /**\r\n * Registra um listener de mudanças no estado da conexão.\r\n *\r\n * O listener é invocado imediatamente com o estado atual e depois a cada\r\n * transição. Retorna uma função `unsubscribe`.\r\n */\r\n onConnectionState(listener: ConnectionStateListener): () => void {\r\n this._stateListeners.push(listener);\r\n // entrega o estado atual imediatamente\r\n listener(this._connectionState);\r\n return () => {\r\n this._stateListeners = this._stateListeners.filter(l => l !== listener);\r\n };\r\n }\r\n\r\n /**\r\n * Encerra o cliente definitivamente.\r\n *\r\n * Fecha o socket ativo, cancela timers pendentes e marca o cliente como\r\n * encerrado (sem mais reconexões).\r\n */\r\n close(): void {\r\n this._closed = true;\r\n this._cancelReconnectTimer();\r\n this._cancelHeartbeatTimer();\r\n if (this._ws) {\r\n // desvincula handlers para não disparar onclose→reconnect\r\n this._detachHandlers(this._ws);\r\n if (this._ws.readyState !== WS_CLOSED) {\r\n this._ws.close(1000, 'client closed');\r\n }\r\n this._ws = null;\r\n }\r\n this._setState('disconnected');\r\n }\r\n\r\n // ── Conexão ───────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Busca um ticket de autenticação e, em seguida, cria um novo WebSocket e\r\n * instala os handlers de evento.\r\n *\r\n * A busca de ticket é obrigatória antes de abrir qualquer WS (primeira\r\n * conexão e reconexões). Se a busca falhar, a conexão é abortada com\r\n * estado `'connecting'` e o backoff reconectará em seguida.\r\n *\r\n * Fail-closed: o WebSocket NUNCA é aberto sem um ticket válido.\r\n */\r\n private _connect(): void {\r\n if (this._closed) return;\r\n this._setState('connecting');\r\n\r\n // Fire-and-forget: a promise é gerenciada internamente.\r\n void this._connectWithTicket();\r\n }\r\n\r\n /** Implementação assíncrona de _connect — busca ticket e abre WS. */\r\n private async _connectWithTicket(): Promise<void> {\r\n if (this._closed) return;\r\n\r\n // ── 1. Busca o ticket ────────────────────────────────────────────────────\r\n let ticket: RealtimeTicket;\r\n try {\r\n ticket = await this._ticketProvider();\r\n } catch (err) {\r\n // Ticket fetch falhou — permanece em 'connecting' e agenda reconexão.\r\n // O WS não é aberto (fail-closed).\r\n if (this._closed) return;\r\n const delay = this._computeBackoffDelay(this._reconnectAttempt);\r\n this._reconnectAttempt++;\r\n this._reconnectTimer = this._setTimeout(() => {\r\n this._reconnectTimer = null;\r\n if (!this._closed) this._connect();\r\n }, delay);\r\n // Permanece em 'connecting' — não altera estado (já está lá).\r\n void err; // silencia \"unused variable\" lint\r\n return;\r\n }\r\n\r\n if (this._closed) return;\r\n\r\n // ── 2. Armazena o ticket para embedding nos frames subscribe ─────────────\r\n this._currentTicket = ticket;\r\n\r\n // ── 3. Abre o WebSocket ──────────────────────────────────────────────────\r\n const ws = this._wsFactory(this._gatewayUrl);\r\n this._ws = ws;\r\n\r\n ws.onopen = this._handleOpen.bind(this);\r\n ws.onmessage = this._handleMessage.bind(this);\r\n ws.onclose = this._handleClose.bind(this);\r\n ws.onerror = this._handleError.bind(this);\r\n }\r\n\r\n // ── Handlers de WebSocket ─────────────────────────────────────────────────\r\n\r\n private _handleOpen(_event: Event): void {\r\n if (this._closed) return;\r\n\r\n this._reconnectAttempt = 0; // reconexão bem-sucedida — reseta counter\r\n this._setState('connected');\r\n\r\n // Drena frames que foram enfileirados enquanto o socket estava CONNECTING.\r\n for (const frame of this._pendingFrames) {\r\n this._sendNow(frame);\r\n }\r\n this._pendingFrames = [];\r\n\r\n // Resubscreve todas as subscriptions ativas (relevante em reconexões\r\n // onde _pendingFrames estava vazio mas as subs já existiam).\r\n // No open inicial, _subscriptions está vazio ou populado (se subscribe\r\n // foi chamado antes do open). Os frames foram para _pendingFrames.\r\n // Em reconexão: _pendingFrames foi drenado acima — mas as subscriptions\r\n // ativas precisam ser re-registradas no NOVO socket.\r\n // Porém, os frames que foram para _pendingFrames já incluem os subscribes\r\n // iniciais. Precisamos distinguir: reconexão vs. primeira conexão.\r\n // Para simplificar e ser correto nos dois casos, resubscreve SEMPRE\r\n // subscriptions que não estavam no _pendingFrames que acabamos de drenar.\r\n this._resubscribeAll();\r\n\r\n // Inicia heartbeat se habilitado.\r\n this._scheduleHeartbeat();\r\n }\r\n\r\n private _handleMessage(event: MessageEvent): void {\r\n if (this._closed) return;\r\n\r\n let frame: InboundFrame;\r\n try {\r\n frame = JSON.parse(event.data as string) as InboundFrame;\r\n } catch {\r\n // frame malformado — ignora\r\n return;\r\n }\r\n\r\n switch (frame.op) {\r\n case 'delta':\r\n case 'resync':\r\n case 'stale':\r\n case 'error':\r\n this._routeToSubscription(frame);\r\n break;\r\n\r\n case 'pong':\r\n // heartbeat respondido — nada a fazer (timer já foi limpo)\r\n break;\r\n\r\n case 'drain':\r\n this._handleDrain();\r\n break;\r\n\r\n default:\r\n // op desconhecido — ignora silenciosamente\r\n break;\r\n }\r\n }\r\n\r\n private _handleClose(_event: CloseEvent): void {\r\n if (this._closed) return;\r\n\r\n this._cancelHeartbeatTimer();\r\n this._ws = null;\r\n this._scheduleReconnect();\r\n }\r\n\r\n private _handleError(_event: Event): void {\r\n // O error é sempre seguido de onclose — não precisamos fazer nada aqui;\r\n // o onclose cuidará da reconexão.\r\n // Marcamos connecting para sinalizar que algo deu errado enquanto aguardamos.\r\n if (this._closed) return;\r\n this._setState('connecting');\r\n }\r\n\r\n // ── Drain (graceful shutdown do gateway) ─────────────────────────────────\r\n\r\n private _handleDrain(): void {\r\n if (this._closed) return;\r\n\r\n this._setState('draining');\r\n this._cancelHeartbeatTimer();\r\n\r\n // Fecha o socket atual sem esperar o close natural do gateway.\r\n if (this._ws) {\r\n this._detachHandlers(this._ws);\r\n if (this._ws.readyState !== WS_CLOSED) {\r\n this._ws.close(1001, 'drain');\r\n }\r\n this._ws = null;\r\n }\r\n\r\n // Reconecta com backoff — o gateway vai subir em seguida.\r\n this._scheduleReconnect();\r\n }\r\n\r\n // ── Roteamento de frames ──────────────────────────────────────────────────\r\n\r\n private _routeToSubscription(frame: InboundFrame): void {\r\n const entry = this._subscriptions.get(frame.subscriptionId);\r\n if (!entry) {\r\n // subscriptionId desconhecido — ignora silenciosamente\r\n return;\r\n }\r\n try {\r\n entry.callback(frame);\r\n } catch {\r\n // erro no callback do produto não deve derrubar o cliente\r\n }\r\n }\r\n\r\n // ── Resubscrição ──────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Reenvía frames `subscribe` para todas as subscriptions ativas.\r\n * Chamado no `onopen` de reconexões para restaurar o estado remoto.\r\n *\r\n * Durante a PRIMEIRA conexão: _pendingFrames já foi drenado com os\r\n * subscribes iniciais acima. ResubscribeAll envia novamente — como a\r\n * lista de subscriptions foi populada pelos `subscribe()` calls anteriores\r\n * ao open, e os frames drenados também os incluem, teríamos duplicatas.\r\n *\r\n * Solução: resubscribeAll só é invocado após drenar _pendingFrames, e\r\n * como o gateway é idempotente para o mesmo subscriptionId (segundo o\r\n * design do componente #19), a duplicata é inócua. Em reconexões, onde\r\n * _pendingFrames está vazio, os frames são os únicos enviados.\r\n *\r\n * Para o caso do primeiro open com subscribes anteriores ao open, os\r\n * frames já foram drenados de _pendingFrames — não chamamos resubscribeAll\r\n * se era a primeira conexão (_reconnectAttempt era 0 antes de resetar).\r\n * Rastreamos isso com _hasConnectedOnce.\r\n */\r\n private _hasConnectedOnce = false;\r\n\r\n private _resubscribeAll(): void {\r\n if (!this._hasConnectedOnce) {\r\n // Primeiro open: os subscribes foram drenados de _pendingFrames.\r\n // Não resubscreve para evitar duplicata.\r\n this._hasConnectedOnce = true;\r\n return;\r\n }\r\n\r\n // Reconexão: envia subscribe frames para todas as subs ativas.\r\n // O ticket corrente (obtido antes de abrir este WS) é embutido em\r\n // cada frame — assim o gateway pode validar a autenticidade.\r\n for (const entry of this._subscriptions.values()) {\r\n const frame: OutboundFrame = {\r\n op: 'subscribe',\r\n subscriptionId: entry.subscriptionId,\r\n collection: entry.collection,\r\n query: this._buildSubscribeQuery(entry.query ?? {}),\r\n };\r\n this._sendNow(frame);\r\n }\r\n }\r\n\r\n // ── Ticket embedding ──────────────────────────────────────────────────────\r\n\r\n /**\r\n * Constrói o descriptor `query` para um frame `subscribe`, embutindo o\r\n * `token` do ticket corrente em `query.filter._ticket` e o `_dbId` do\r\n * banco lógico em `query.filter._dbId` (BL-8 fix).\r\n *\r\n * O gateway extrai `filter._ticket` do primeiro frame `subscribe` e valida\r\n * contra `POST /api/sdk/v1/db/realtime/validate`. `filter._dbId` é exigido\r\n * pelo `@neetru/realtime-changestream._extractDbId` para rotear a\r\n * subscription ao banco correto — sem ele a subscription é rejeitada.\r\n *\r\n * Retorna `undefined` se a query seria vazia E não há ticket (estado\r\n * transitório antes do primeiro ticket — não deve ocorrer normalmente pois\r\n * `_connect` só abre o WS após obter o ticket).\r\n */\r\n private _buildSubscribeQuery(\r\n query: RealtimeQuery,\r\n ): RealtimeQuery | undefined {\r\n const ticket = this._currentTicket;\r\n const hasUserQuery = Object.keys(query).length > 0;\r\n\r\n if (!ticket) {\r\n // Sem ticket — retorna a query original sem embedding (defensivo;\r\n // na prática nunca chega aqui pois _connect não abre WS sem ticket).\r\n return hasUserQuery ? query : undefined;\r\n }\r\n\r\n // BL-8: mescla _ticket + _dbId no filter, preservando filtros do caller.\r\n const mergedFilter: Record<string, unknown> = {\r\n ...(query.filter ?? {}),\r\n _ticket: ticket.token,\r\n };\r\n\r\n // Embute _dbId apenas quando configurado (compatibilidade reversa).\r\n if (this._dbId !== undefined) {\r\n mergedFilter['_dbId'] = this._dbId;\r\n }\r\n\r\n return {\r\n ...query,\r\n filter: mergedFilter,\r\n };\r\n }\r\n\r\n // ── Backoff e reconexão ───────────────────────────────────────────────────\r\n\r\n /** Agenda uma tentativa de reconexão com backoff exponencial + jitter. */\r\n private _scheduleReconnect(): void {\r\n if (this._closed) return;\r\n\r\n this._cancelReconnectTimer();\r\n this._setState('connecting');\r\n\r\n // Invalida o ticket corrente — a reconexão deve buscar um novo.\r\n this._currentTicket = null;\r\n\r\n const delayMs = this._computeBackoffDelay(this._reconnectAttempt);\r\n this._reconnectAttempt++;\r\n\r\n this._reconnectTimer = this._setTimeout(() => {\r\n this._reconnectTimer = null;\r\n if (!this._closed) {\r\n this._connect();\r\n }\r\n }, delayMs);\r\n }\r\n\r\n /**\r\n * Calcula o delay de backoff para o attempt N.\r\n *\r\n * Fórmula: `min(baseMs * 2^N, maxMs) * jitter`\r\n * onde `jitter ∈ [JITTER_MIN, JITTER_MAX]` (±50%).\r\n */\r\n private _computeBackoffDelay(attempt: number): number {\r\n const exponential = this._backoffBaseMs * Math.pow(2, attempt);\r\n const capped = Math.min(exponential, this._backoffMaxMs);\r\n const jitter = JITTER_MIN + Math.random() * (JITTER_MAX - JITTER_MIN);\r\n return Math.round(capped * jitter);\r\n }\r\n\r\n private _cancelReconnectTimer(): void {\r\n if (this._reconnectTimer !== null) {\r\n this._clearTimeout(this._reconnectTimer);\r\n this._reconnectTimer = null;\r\n }\r\n }\r\n\r\n // ── Heartbeat ─────────────────────────────────────────────────────────────\r\n\r\n /** Agenda o próximo ping. Não-operacional se heartbeatIntervalMs === 0. */\r\n private _scheduleHeartbeat(): void {\r\n if (this._heartbeatIntervalMs === 0) return;\r\n this._cancelHeartbeatTimer();\r\n\r\n this._heartbeatTimer = this._setTimeout(() => {\r\n this._heartbeatTimer = null;\r\n this._sendPing();\r\n // agenda o próximo ciclo\r\n this._scheduleHeartbeat();\r\n }, this._heartbeatIntervalMs);\r\n }\r\n\r\n private _cancelHeartbeatTimer(): void {\r\n if (this._heartbeatTimer !== null) {\r\n this._clearTimeout(this._heartbeatTimer);\r\n this._heartbeatTimer = null;\r\n }\r\n }\r\n\r\n private _sendPing(): void {\r\n // O ping usa um subscriptionId especial vazio ('') para o heartbeat\r\n // de aplicação (distinto do ping/pong do protocolo WebSocket).\r\n const frame: OutboundFrame = { op: 'ping', subscriptionId: '' };\r\n this._sendOrBuffer(frame);\r\n }\r\n\r\n // ── Envio de frames ───────────────────────────────────────────────────────\r\n\r\n /**\r\n * Envia o frame imediatamente se o socket está aberto; caso contrário,\r\n * enfileira em `_pendingFrames` para envio no próximo `onopen`.\r\n */\r\n private _sendOrBuffer(frame: OutboundFrame): void {\r\n if (\r\n this._ws !== null &&\r\n this._ws.readyState === WS_OPEN\r\n ) {\r\n this._sendNow(frame);\r\n } else {\r\n // Socket ainda está CONNECTING ou foi perdido — enfileira.\r\n // Frames de unsubscribe não precisam ser bufferizados pois não há\r\n // estado remoto a limpar (o remote não tem a sub se o socket não abriu).\r\n if (frame.op !== 'unsubscribe') {\r\n this._pendingFrames.push(frame);\r\n }\r\n }\r\n }\r\n\r\n /** Serializa e envia o frame imediatamente via WebSocket. */\r\n private _sendNow(frame: OutboundFrame): void {\r\n if (!this._ws || this._ws.readyState !== WS_OPEN) return;\r\n try {\r\n this._ws.send(JSON.stringify(frame));\r\n } catch {\r\n // Falha de send (ex: buffer cheio) — ignora; o onclose cuidará da reconexão.\r\n }\r\n }\r\n\r\n // ── Estado da conexão ─────────────────────────────────────────────────────\r\n\r\n private _setState(state: ConnectionState): void {\r\n if (this._connectionState === state) return;\r\n this._connectionState = state;\r\n for (const listener of this._stateListeners) {\r\n try {\r\n listener(state);\r\n } catch {\r\n // erro no listener do produto não deve derrubar o cliente\r\n }\r\n }\r\n }\r\n\r\n // ── Desvinculação de handlers ─────────────────────────────────────────────\r\n\r\n /** Remove todos os handlers de um WebSocket (evita disparo após close()). */\r\n private _detachHandlers(ws: WebSocketLike): void {\r\n ws.onopen = null;\r\n ws.onmessage = null;\r\n ws.onclose = null;\r\n ws.onerror = null;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Factory de WebSocket padrão\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Factory padrão: cria um `WebSocket` nativo do browser/runtime.\r\n * Substituída por FakeWebSocket em testes.\r\n */\r\nconst defaultWebSocketFactory: WebSocketFactory = (url: string): WebSocketLike => {\r\n // `WebSocket` é global no browser e no Node 22+ (sem import).\r\n // Em ambientes sem WebSocket global, o produto deve injetar a factory.\r\n if (typeof WebSocket === 'undefined') {\r\n throw new Error(\r\n '[NeetruRealtimeClient] WebSocket não disponível neste ambiente. ' +\r\n 'Injete uma implementação via `webSocketFactory` nas opções.',\r\n );\r\n }\r\n return new WebSocket(url);\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Re-exports de tipos para conveniência do consumidor\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type {\r\n RealtimeClientOptions,\r\n RealtimeQuery,\r\n RealtimeTicket,\r\n TicketProvider,\r\n ConnectionState,\r\n ConnectionStateListener,\r\n SubscriptionCallback,\r\n InboundFrame,\r\n OutboundFrame,\r\n} from './types';\r\n","/**\r\n * Checkout namespace (v1.1) — `client.checkout.*`\r\n *\r\n * Fluxo canônico (vide `docs/FLUXO_SIGNUP_BILLING_CHECKOUT.md` §6):\r\n * 1. SaaS produto chama `client.checkout.start({productId, planId, callbackUrl})`.\r\n * 2. SDK posta em `POST /api/v1/checkout/intents` (Bearer access_token OIDC).\r\n * 3. Core cria `checkout_intents/{intentId}` (TTL 15min) + retorna `redirectUrl`.\r\n * 4. Em browser, SDK redireciona automaticamente pra `redirectUrl`. Em\r\n * Node/SSR, retorna o objeto `{intentId, redirectUrl}` sem redirect.\r\n * 5. Portal (`minhaconta.neetru.com/portal/kyc/{intentId}`) coleta KYC + cartão.\r\n * 6. Usuário volta pra `callbackUrl?status=success&intentId=...` quando completo.\r\n *\r\n * **Dev mode** (`NEETRU_ENV=dev`): `start()` retorna URL fake sem network call.\r\n * Útil pra dev externo SaaS testar UI sem provisionar conta Neetru.\r\n *\r\n * **Estabilidade**: minor bump v1.0 → v1.1 (feature add, sem breaking).\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n// ─── Types públicos ─────────────────────────────────────────────────────────\r\n\r\n/** Tipo do tenant alvo da subscription (PF=uid, PJ=orgId). */\r\nexport type CheckoutTenantType = 'pf' | 'pj';\r\n\r\n/** Status do `checkout_intents/{intentId}` no Core. */\r\nexport type CheckoutIntentStatus =\r\n | 'pending'\r\n | 'kyc_in_progress'\r\n | 'stripe_redirected'\r\n | 'completed'\r\n | 'expired'\r\n | 'cancelled';\r\n\r\nexport interface CheckoutStartInput {\r\n /** Slug do produto no catálogo (ex: `neetru-pulse`). */\r\n productId: string;\r\n /** Slug do plano no catálogo do produto (ex: `pro_monthly`). */\r\n planId: string;\r\n /** Pra onde o produto SaaS quer voltar pós-checkout. https obrigatório (ou http://localhost em dev). */\r\n callbackUrl: string;\r\n /** Override pra checkout em nome de uma org. Default: PF do uid logado. */\r\n tenantType?: CheckoutTenantType;\r\n /** Quando `tenantType='pj'`, id da org. Ignorado quando PF. */\r\n tenantId?: string;\r\n /**\r\n * Em browsers, default `true` — SDK faz `window.location.href = redirectUrl`.\r\n * Passe `false` se quiser controlar o redirect manualmente.\r\n */\r\n autoRedirect?: boolean;\r\n /**\r\n * **C2 (auditoria 2026-06-10):** access_token OIDC do **usuário final** que\r\n * está assinando. OBRIGATÓRIO no modo HTTP real — o endpoint de checkout do\r\n * Core (`/api/v1/checkout/intents`) autentica a identidade do cliente (Bearer\r\n * access_token OIDC ou cookie de sessão), NÃO a chave de API do SDK (`nrt_*`).\r\n * Enviar a chave `nrt_*` resultava em 401 sempre. O SDK é BFF-pattern: o app\r\n * consumidor gerencia o ciclo OIDC e passa o access_token aqui.\r\n */\r\n accessToken?: string;\r\n}\r\n\r\n/** Auth por chamada do checkout — access_token OIDC do usuário final. */\r\nexport interface CheckoutAuthOpts {\r\n /** access_token OIDC do usuário final (vide CheckoutStartInput.accessToken). */\r\n accessToken?: string;\r\n}\r\n\r\nexport interface CheckoutStartResult {\r\n intentId: string;\r\n redirectUrl: string;\r\n status: CheckoutIntentStatus;\r\n expiresAt: string;\r\n /** True se KYC ainda precisa ser coletado no portal. UI pode mostrar hint. */\r\n requiresKyc: boolean;\r\n}\r\n\r\nexport interface CheckoutIntentInfo {\r\n intentId: string;\r\n uid: string;\r\n targetTenantId: string;\r\n targetTenantType: CheckoutTenantType;\r\n productId: string;\r\n planId: string;\r\n callbackUrl: string;\r\n status: CheckoutIntentStatus;\r\n /** Stripe Checkout Session id quando avançou pra `stripe_redirected`. */\r\n stripeSessionId?: string | null;\r\n expiresAt: string;\r\n /** True se já passou `expiresAt` mas Core ainda não marcou expired. */\r\n isStale?: boolean;\r\n}\r\n\r\nexport interface CheckoutNamespace {\r\n /**\r\n * Inicia checkout. Em browser, redireciona automaticamente pro portal.\r\n * Em Node/SSR, retorna o resultado sem efeitos colaterais — caller decide\r\n * o que fazer com `redirectUrl`.\r\n *\r\n * Dev mode (`NEETRU_ENV=dev`): retorna URL fake `https://localhost:9003/portal/checkout/mock-XXXX`.\r\n */\r\n start(input: CheckoutStartInput): Promise<CheckoutStartResult>;\r\n /** Lê estado atual do intent (Core). Requer `opts.accessToken` no HTTP real. */\r\n get(intentId: string, opts?: CheckoutAuthOpts): Promise<CheckoutIntentInfo>;\r\n /** Cancela um intent que ainda não virou `stripe_redirected`. Requer `opts.accessToken` no HTTP real. */\r\n cancel(intentId: string, opts?: CheckoutAuthOpts): Promise<{ ok: true; alreadyCancelled: boolean }>;\r\n}\r\n\r\n/**\r\n * C2: monta a auth do checkout a partir do access_token OIDC do usuário final.\r\n * Fail-closed: sem token, lança erro claro em vez de mandar a chave `nrt_*`\r\n * (que o endpoint rejeita com 401). Retorna requireAuth:false + header Bearer\r\n * manual — httpRequest preserva `headers.authorization` quando requireAuth=false.\r\n */\r\nfunction checkoutAuth(\r\n accessToken: string | undefined,\r\n method: string,\r\n): { requireAuth: false; headers: Record<string, string> } {\r\n if (!accessToken || typeof accessToken !== 'string') {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n `checkout.${method} requer o access_token OIDC do usuário final (passe \\`accessToken\\`). ` +\r\n `A chave de API do SDK (nrt_*) NÃO é aceita pelo endpoint de checkout — ele autentica a ` +\r\n `identidade do cliente que está assinando (Bearer access_token OIDC ou cookie de sessão).`,\r\n );\r\n }\r\n return { requireAuth: false, headers: { authorization: `Bearer ${accessToken}` } };\r\n}\r\n\r\n// ─── Implementação real (HTTP) ─────────────────────────────────────────────\r\n\r\ninterface RawStartCheckoutResponse {\r\n ok?: boolean;\r\n intentId?: string;\r\n redirectUrl?: string;\r\n status?: string;\r\n expiresAt?: string;\r\n requiresKyc?: boolean;\r\n}\r\n\r\ninterface RawGetCheckoutResponse {\r\n ok?: boolean;\r\n intent?: {\r\n intentId?: string;\r\n uid?: string;\r\n targetTenantId?: string;\r\n targetTenantType?: string;\r\n productId?: string;\r\n planId?: string;\r\n callbackUrl?: string;\r\n status?: string;\r\n stripeSessionId?: string | null;\r\n expiresAt?: string;\r\n };\r\n isStale?: boolean;\r\n}\r\n\r\nfunction parseStartResponse(raw: unknown): CheckoutStartResult {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'checkout.start response is not an object');\r\n }\r\n const r = raw as RawStartCheckoutResponse;\r\n if (typeof r.intentId !== 'string' || !r.intentId) {\r\n throw new NeetruError('invalid_response', 'checkout.start response missing intentId');\r\n }\r\n if (typeof r.redirectUrl !== 'string' || !r.redirectUrl) {\r\n throw new NeetruError('invalid_response', 'checkout.start response missing redirectUrl');\r\n }\r\n return {\r\n intentId: r.intentId,\r\n redirectUrl: r.redirectUrl,\r\n status: (r.status as CheckoutIntentStatus | undefined) ?? 'pending',\r\n expiresAt: typeof r.expiresAt === 'string' ? r.expiresAt : new Date().toISOString(),\r\n requiresKyc: r.requiresKyc === true,\r\n };\r\n}\r\n\r\nfunction parseGetResponse(raw: unknown): CheckoutIntentInfo {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'checkout.get response is not an object');\r\n }\r\n const r = raw as RawGetCheckoutResponse;\r\n const intent = r.intent;\r\n if (!intent || typeof intent !== 'object') {\r\n throw new NeetruError('invalid_response', 'checkout.get response missing intent');\r\n }\r\n if (typeof intent.intentId !== 'string') {\r\n throw new NeetruError('invalid_response', 'checkout.get response missing intentId');\r\n }\r\n return {\r\n intentId: intent.intentId,\r\n uid: intent.uid ?? '',\r\n targetTenantId: intent.targetTenantId ?? '',\r\n targetTenantType: (intent.targetTenantType as CheckoutTenantType | undefined) ?? 'pf',\r\n productId: intent.productId ?? '',\r\n planId: intent.planId ?? '',\r\n callbackUrl: intent.callbackUrl ?? '',\r\n status: (intent.status as CheckoutIntentStatus | undefined) ?? 'pending',\r\n stripeSessionId: intent.stripeSessionId ?? null,\r\n expiresAt: intent.expiresAt ?? new Date().toISOString(),\r\n isStale: r.isStale === true,\r\n };\r\n}\r\n\r\n/**\r\n * Detecta se estamos em browser context. Em SSR / Node / Edge, `window`\r\n * pode não existir — fazemos check defensivo.\r\n */\r\nfunction inBrowser(): boolean {\r\n try {\r\n return (\r\n typeof globalThis !== 'undefined' &&\r\n typeof (globalThis as { window?: { location?: { href?: string } } }).window !== 'undefined' &&\r\n typeof globalThis.location !== 'undefined' &&\r\n typeof globalThis.location.assign === 'function'\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nfunction performRedirect(url: string): void {\r\n try {\r\n globalThis.location.assign(url);\r\n } catch {\r\n /* noop em runtimes sem location.assign — caller decide */\r\n }\r\n}\r\n\r\n/**\r\n * Implementação HTTP real. Posta no Core, parse response, redireciona se browser.\r\n */\r\nfunction createHttpCheckoutNamespace(config: ResolvedConfig): CheckoutNamespace {\r\n return {\r\n async start(input: CheckoutStartInput): Promise<CheckoutStartResult> {\r\n if (!input?.productId) {\r\n throw new NeetruError('validation_failed', 'checkout.start: productId is required');\r\n }\r\n if (!input?.planId) {\r\n throw new NeetruError('validation_failed', 'checkout.start: planId is required');\r\n }\r\n if (!input?.callbackUrl) {\r\n throw new NeetruError('validation_failed', 'checkout.start: callbackUrl is required');\r\n }\r\n\r\n const body: Record<string, unknown> = {\r\n productId: input.productId,\r\n planId: input.planId,\r\n callbackUrl: input.callbackUrl,\r\n };\r\n if (input.tenantType) body.targetTenantType = input.tenantType;\r\n if (input.tenantId) body.targetTenantId = input.tenantId;\r\n\r\n // bug: sem idempotencyKey → retry criava intents duplicados (fix: alinhar com usage.report/support.createTicket)\r\n const { requireAuth, headers } = checkoutAuth(input.accessToken, 'start');\r\n const raw = await httpRequest<RawStartCheckoutResponse>(config, {\r\n method: 'POST',\r\n path: '/api/v1/checkout/intents',\r\n body,\r\n requireAuth,\r\n headers,\r\n idempotencyKey: true,\r\n });\r\n const result = parseStartResponse(raw);\r\n\r\n const shouldRedirect = input.autoRedirect !== false;\r\n if (shouldRedirect && inBrowser()) {\r\n performRedirect(result.redirectUrl);\r\n }\r\n return result;\r\n },\r\n\r\n async get(intentId: string, opts?: CheckoutAuthOpts): Promise<CheckoutIntentInfo> {\r\n if (!intentId || typeof intentId !== 'string') {\r\n throw new NeetruError('validation_failed', 'checkout.get: intentId is required');\r\n }\r\n const { requireAuth, headers } = checkoutAuth(opts?.accessToken, 'get');\r\n const raw = await httpRequest<RawGetCheckoutResponse>(config, {\r\n method: 'GET',\r\n path: `/api/v1/checkout/intents/${encodeURIComponent(intentId)}`,\r\n requireAuth,\r\n headers,\r\n });\r\n return parseGetResponse(raw);\r\n },\r\n\r\n async cancel(intentId: string, opts?: CheckoutAuthOpts): Promise<{ ok: true; alreadyCancelled: boolean }> {\r\n if (!intentId || typeof intentId !== 'string') {\r\n throw new NeetruError('validation_failed', 'checkout.cancel: intentId is required');\r\n }\r\n const { requireAuth, headers } = checkoutAuth(opts?.accessToken, 'cancel');\r\n const raw = await httpRequest<{ ok?: boolean; alreadyCancelled?: boolean }>(config, {\r\n method: 'DELETE',\r\n path: `/api/v1/checkout/intents/${encodeURIComponent(intentId)}`,\r\n requireAuth,\r\n headers,\r\n });\r\n return {\r\n ok: true,\r\n alreadyCancelled: (raw as { alreadyCancelled?: boolean })?.alreadyCancelled === true,\r\n };\r\n },\r\n };\r\n}\r\n\r\n// ─── Mock dev (sem network) ─────────────────────────────────────────────────\r\n\r\n/**\r\n * Mock dev — retorna URL fake `https://localhost:9003/portal/checkout/mock-XXXX`\r\n * sem tocar no Core. Útil pra dev externo SaaS testar UI/redirect sem precisar\r\n * de Bearer token Neetru.\r\n *\r\n * Dev mode persiste intents em mapa in-memory pro `get`/`cancel` retornarem\r\n * resultado consistente.\r\n */\r\nexport class MockCheckout implements CheckoutNamespace {\r\n private readonly intents = new Map<string, CheckoutIntentInfo>();\r\n\r\n async start(input: CheckoutStartInput): Promise<CheckoutStartResult> {\r\n if (!input?.productId) {\r\n throw new NeetruError('validation_failed', 'checkout.start: productId is required');\r\n }\r\n if (!input?.planId) {\r\n throw new NeetruError('validation_failed', 'checkout.start: planId is required');\r\n }\r\n if (!input?.callbackUrl) {\r\n throw new NeetruError('validation_failed', 'checkout.start: callbackUrl is required');\r\n }\r\n\r\n const intentId = `chk_mock_${Math.random().toString(36).slice(2, 10)}`;\r\n const expiresAt = new Date(Date.now() + 15 * 60 * 1000).toISOString();\r\n const redirectUrl = `https://localhost:9003/portal/checkout/${intentId}`;\r\n\r\n this.intents.set(intentId, {\r\n intentId,\r\n uid: 'dev-fixture-uid',\r\n targetTenantId: input.tenantId ?? 'dev-fixture-uid',\r\n targetTenantType: input.tenantType ?? 'pf',\r\n productId: input.productId,\r\n planId: input.planId,\r\n callbackUrl: input.callbackUrl,\r\n status: 'pending',\r\n stripeSessionId: null,\r\n expiresAt,\r\n });\r\n\r\n return {\r\n intentId,\r\n redirectUrl,\r\n status: 'pending',\r\n expiresAt,\r\n requiresKyc: false,\r\n };\r\n }\r\n\r\n async get(intentId: string, _opts?: CheckoutAuthOpts): Promise<CheckoutIntentInfo> {\r\n const found = this.intents.get(intentId);\r\n if (!found) {\r\n throw new NeetruError('not_found', `Mock intent ${intentId} not found`);\r\n }\r\n return { ...found };\r\n }\r\n\r\n async cancel(intentId: string, _opts?: CheckoutAuthOpts): Promise<{ ok: true; alreadyCancelled: boolean }> {\r\n const found = this.intents.get(intentId);\r\n if (!found) {\r\n throw new NeetruError('not_found', `Mock intent ${intentId} not found`);\r\n }\r\n const alreadyCancelled = found.status === 'cancelled';\r\n this.intents.set(intentId, { ...found, status: 'cancelled' });\r\n return { ok: true, alreadyCancelled };\r\n }\r\n}\r\n\r\n// ─── Factory ────────────────────────────────────────────────────────────────\r\n\r\nexport function createCheckoutNamespace(config: ResolvedConfig): CheckoutNamespace {\r\n if (config.env === 'dev') return new MockCheckout();\r\n return createHttpCheckoutNamespace(config);\r\n}\r\n","/**\r\n * Webhooks namespace (v1.2) — produtos SaaS registram endpoints HTTP no Core\r\n * pra receber notificações de eventos.\r\n *\r\n * Casos típicos:\r\n * - `subscription.activated` quando cliente conclui checkout\r\n * - `subscription.cancelled` / `subscription.payment_failed`\r\n * - `usage.quota_exceeded` quando produto bate teto mensal\r\n * - `account.suspended` quando staff Neetru suspende uma conta\r\n *\r\n * Pull-vs-push: o SDK existente é pull-only (`getQuota`, etc). Webhooks\r\n * fecham o gap pra eventos assíncronos sem o produto precisar fazer polling.\r\n *\r\n * Segurança:\r\n * - Endpoint do produto recebe HMAC SHA-256 em header `X-Neetru-Signature`\r\n * usando `secret` opcional do registro. Sem `secret`, header ausente —\r\n * produto deve usar HTTPS + IP allowlist.\r\n * - Replay protection: header `X-Neetru-Timestamp` (ms) — produto deve\r\n * rejeitar > 5min de skew.\r\n * - Retry: Core retenta 3x com backoff exponencial (1s, 5s, 25s) se 5xx\r\n * ou timeout. Após 3 falhas → marca endpoint `degraded` por 1h.\r\n *\r\n * Endpoints REST (em prod):\r\n * - `POST /api/sdk/v1/webhooks` — registra novo endpoint\r\n * - `GET /api/sdk/v1/webhooks` — lista endpoints do produto\r\n * - `DELETE /api/sdk/v1/webhooks/{id}` — remove endpoint\r\n * - `POST /api/sdk/v1/webhooks/{id}/test` — dispara evento de teste\r\n *\r\n * Mock em `NEETRU_ENV=dev`: tudo in-memory, sem rede.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport { assertValidSdkId } from './validators';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n/** Eventos Neetru que produtos podem assinar. Lista expansível por minor bump. */\r\nexport type WebhookEvent =\r\n | 'subscription.activated'\r\n | 'subscription.cancelled'\r\n | 'subscription.payment_failed'\r\n | 'subscription.trial_ending'\r\n | 'usage.quota_exceeded'\r\n | 'account.suspended'\r\n | 'account.reactivated'\r\n | 'support.ticket_replied';\r\n\r\nexport interface WebhookEndpoint {\r\n id: string;\r\n url: string;\r\n events: WebhookEvent[];\r\n /** Quando true, `X-Neetru-Signature` é enviado em cada dispatch. */\r\n hasSecret: boolean;\r\n status: 'active' | 'degraded' | 'disabled';\r\n /** ISO timestamp do último dispatch bem-sucedido. */\r\n lastDeliveryAt?: string;\r\n /** Quantos dispatches falharam consecutivos (resetado em sucesso). */\r\n consecutiveFailures?: number;\r\n createdAt: string;\r\n}\r\n\r\nexport interface RegisterWebhookInput {\r\n /**\r\n * **3.0 (breaking):** `productId` é obrigatório no body. Se ausente,\r\n * SDK tenta resolver do `config.productId` (default no `createNeetruClient`);\r\n * lança `validation_failed` se ambos faltarem.\r\n */\r\n productId?: string;\r\n url: string;\r\n events: WebhookEvent[];\r\n /**\r\n * Secret pra HMAC SHA-256 (mín 16 chars). Recomendado.\r\n * Quando ausente, dispatches vão sem assinatura — produto deve ter\r\n * IP allowlist ou outra defesa.\r\n */\r\n secret?: string;\r\n}\r\n\r\nexport interface WebhookTestResult {\r\n ok: boolean;\r\n statusCode?: number;\r\n durationMs?: number;\r\n error?: string;\r\n}\r\n\r\n/**\r\n * 3.0: opções de scoping — todos os verbos exigem `productId` (default do\r\n * `config.productId` se ausente).\r\n */\r\nexport interface WebhookScopeOptions {\r\n productId?: string;\r\n}\r\n\r\nexport interface WebhooksNamespace {\r\n /** Registra um novo endpoint. */\r\n register(input: RegisterWebhookInput): Promise<WebhookEndpoint>;\r\n /** Lista endpoints registrados pelo produto. */\r\n list(options?: WebhookScopeOptions): Promise<WebhookEndpoint[]>;\r\n /** Remove um endpoint. */\r\n unregister(id: string, options?: WebhookScopeOptions): Promise<{ ok: true }>;\r\n /** Dispara evento de teste pra validar conectividade. */\r\n test(id: string, options?: WebhookScopeOptions): Promise<WebhookTestResult>;\r\n}\r\n\r\n/**\r\n * Verifica assinatura HMAC SHA-256 de payload de webhook recebido pelo\r\n * produto consumer. **3.0**: Universal (browser/Node/Edge) via WebCrypto.subtle.\r\n *\r\n * Constant-time compare via byte-level XOR accumulator (não usa\r\n * `timingSafeEqual` do Node porque WebCrypto não tem equivalente direto).\r\n *\r\n * **3.1.3 (auditoria 2026-06-10)**: o Core assina HMAC sobre\r\n * `` `${timestamp}.${rawBody}` `` (vide `computeWebhookSignature` em\r\n * `functions/src/lib/webhook-delivery-core.ts`) — o `timestamp` é o valor do\r\n * header `X-Neetru-Timestamp`. Passe-o no 4º parâmetro; sem ele o HMAC é\r\n * computado só sobre o body e NUNCA confere com entregas reais do Core.\r\n * Prefira `verifyWebhookRequest`, que lê os headers e já faz tudo.\r\n *\r\n * @param payload Corpo cru da request (string ou Uint8Array). NÃO use o objeto\r\n * parseado — JSON.stringify pode diferir do que foi assinado.\r\n * @param signature Header `X-Neetru-Signature` recebido (formato `sha256=<hex>`).\r\n * @param secret Secret registrado em `webhooks.register({ secret })`.\r\n * @param timestamp Valor do header `X-Neetru-Timestamp` (ms epoch). Quando\r\n * presente, o HMAC cobre `` `${timestamp}.${payload}` ``\r\n * (esquema canônico do Core — replay protection embutida).\r\n * @returns Promise<boolean> — true se assinatura confere, false caso contrário.\r\n *\r\n * @example\r\n * ```ts\r\n * // Next.js Route Handler (Edge ou Node runtime — funciona em ambos)\r\n * export async function POST(req: Request) {\r\n * const raw = await req.text();\r\n * const sig = req.headers.get('X-Neetru-Signature');\r\n * const ts = req.headers.get('X-Neetru-Timestamp');\r\n * const ok = await verifyWebhookSignature(raw, sig, process.env.NEETRU_WEBHOOK_SECRET!, ts ?? undefined);\r\n * if (!ok) return new Response('unauthorized', { status: 401 });\r\n * const event = JSON.parse(raw);\r\n * // ... handle event\r\n * return Response.json({ ok: true });\r\n * }\r\n * ```\r\n *\r\n * @throws NeetruError('runtime_unsupported') se runtime não expõe WebCrypto.\r\n * Não retorna `false` silencioso — caller precisa distinguir \"assinatura\r\n * inválida\" (return false) de \"ambiente não suporta\" (throw).\r\n */\r\nexport async function verifyWebhookSignature(\r\n payload: string | Uint8Array,\r\n signature: string | null | undefined,\r\n secret: string,\r\n timestamp?: string | number,\r\n): Promise<boolean> {\r\n if (!signature || !secret) return false;\r\n // Aceita \"sha256=<hex>\" ou \"<hex>\" cru.\r\n const sigHex = signature.startsWith('sha256=') ? signature.slice(7) : signature;\r\n if (!/^[0-9a-f]+$/i.test(sigHex)) return false;\r\n\r\n // WebCrypto disponível em Node ≥20, browsers modernos, Edge runtimes.\r\n const subtle: SubtleCrypto | undefined =\r\n typeof globalThis !== 'undefined' && 'crypto' in globalThis\r\n ? (globalThis as { crypto?: { subtle?: SubtleCrypto } }).crypto?.subtle\r\n : undefined;\r\n if (!subtle) {\r\n throw new NeetruError(\r\n 'runtime_unsupported',\r\n 'verifyWebhookSignature requires globalThis.crypto.subtle (Node ≥20, modern browser, or Edge runtime).',\r\n );\r\n }\r\n\r\n const encoder = new TextEncoder();\r\n const keyBytes = encoder.encode(secret);\r\n // TextEncoder.encode retorna Uint8Array<ArrayBuffer>; payload Uint8Array\r\n // pode vir como Uint8Array<ArrayBufferLike> (SharedArrayBuffer compat). Cast\r\n // explicit pra ArrayBuffer view — Web Crypto aceita ambos em runtime.\r\n const rawBytes: Uint8Array =\r\n typeof payload === 'string' ? encoder.encode(payload) : payload;\r\n // Esquema canônico do Core: HMAC(`${timestamp}.${rawBody}`). Sem timestamp,\r\n // assina só o body (compat com verificações custom fora do fluxo Core).\r\n let payloadBytes: Uint8Array = rawBytes;\r\n if (timestamp !== undefined) {\r\n const prefix = encoder.encode(`${timestamp}.`);\r\n const merged = new Uint8Array(prefix.length + rawBytes.length);\r\n merged.set(prefix, 0);\r\n merged.set(rawBytes, prefix.length);\r\n payloadBytes = merged;\r\n }\r\n\r\n const key = await subtle.importKey(\r\n 'raw',\r\n keyBytes as BufferSource,\r\n { name: 'HMAC', hash: 'SHA-256' },\r\n false,\r\n ['sign'],\r\n );\r\n const macBuffer = await subtle.sign(\r\n 'HMAC',\r\n key,\r\n payloadBytes as BufferSource,\r\n );\r\n const macBytes = new Uint8Array(macBuffer);\r\n\r\n // Decode hex signature em bytes.\r\n const sigBytes = hexToBytes(sigHex.toLowerCase());\r\n if (!sigBytes || sigBytes.length !== macBytes.length) return false;\r\n\r\n // Constant-time compare via XOR accumulator.\r\n let diff = 0;\r\n for (let i = 0; i < macBytes.length; i++) {\r\n diff |= macBytes[i] ^ sigBytes[i];\r\n }\r\n return diff === 0;\r\n}\r\n\r\n// ─── verifyWebhookRequest — assinatura + replay protection ─────────────────\r\n\r\n/**\r\n * Opções de `verifyWebhookRequest`.\r\n */\r\nexport interface VerifyWebhookRequestOptions {\r\n /**\r\n * Janela de tolerância em milliseconds para o skew de timestamp.\r\n * Default: 300_000 (5 minutos), conforme documentado na spec de webhooks.\r\n * Valores menores aumentam a proteção contra replay; valores maiores acomodam\r\n * clocks com drift. Não use valores acima de 600_000 (10 min).\r\n */\r\n toleranceMs?: number;\r\n}\r\n\r\n/**\r\n * Resultado de `verifyWebhookRequest`.\r\n */\r\nexport type VerifyWebhookRequestResult =\r\n | { ok: true }\r\n | { ok: false; reason: 'invalid_signature' | 'timestamp_missing' | 'timestamp_expired' | 'runtime_unsupported' };\r\n\r\n/**\r\n * Helper server-only que combina:\r\n * 1. Verificação de assinatura HMAC-SHA256 (`X-Neetru-Signature`)\r\n * 2. **Replay-protection** via skew de timestamp (`X-Neetru-Timestamp`)\r\n *\r\n * Rejeita o request se o timestamp estiver fora da janela `toleranceMs`\r\n * (default ±5 min). Isso fecha a janela de replay onde um atacante captura\r\n * um request válido e o re-envia mais tarde.\r\n *\r\n * **Use este helper em vez de `verifyWebhookSignature` diretamente** — ele\r\n * é a forma correta de validar um webhook Neetru em produção.\r\n *\r\n * @param payload Corpo cru da request (string ou Uint8Array).\r\n * @param headers Headers do request (pode ser um `Headers` Web API ou\r\n * `Record<string, string | undefined>`). Lidos: `X-Neetru-Signature` e\r\n * `X-Neetru-Timestamp`.\r\n * @param secret Secret registrado em `webhooks.register({ secret })`.\r\n * @param options Opções adicionais (ex: `toleranceMs`).\r\n * @returns `{ ok: true }` ou `{ ok: false, reason }` — nunca lança, a menos\r\n * que o runtime não suporte WebCrypto (então propaga `NeetruError('runtime_unsupported')`).\r\n *\r\n * @example\r\n * ```ts\r\n * // Next.js Route Handler\r\n * export async function POST(req: Request) {\r\n * const raw = await req.text();\r\n * const result = await verifyWebhookRequest(raw, req.headers, process.env.NEETRU_WEBHOOK_SECRET!);\r\n * if (!result.ok) {\r\n * console.warn('Webhook rejeitado:', result.reason);\r\n * return new Response('unauthorized', { status: 401 });\r\n * }\r\n * const event = JSON.parse(raw);\r\n * // ... handle event\r\n * return Response.json({ ok: true });\r\n * }\r\n * ```\r\n */\r\nexport async function verifyWebhookRequest(\r\n payload: string | Uint8Array,\r\n headers: Headers | Record<string, string | undefined>,\r\n secret: string,\r\n options: VerifyWebhookRequestOptions = {},\r\n): Promise<VerifyWebhookRequestResult> {\r\n const toleranceMs = options.toleranceMs ?? 300_000; // 5 minutos\r\n\r\n // Lê os headers de forma compatível com Web API Headers e Record<string, string>\r\n const getHeader = (name: string): string | null | undefined => {\r\n if (typeof (headers as Headers).get === 'function') {\r\n return (headers as Headers).get(name);\r\n }\r\n const rec = headers as Record<string, string | undefined>;\r\n // Normaliza pra lowercase pra lidar com variações de casing\r\n const lower = name.toLowerCase();\r\n for (const key of Object.keys(rec)) {\r\n if (key.toLowerCase() === lower) return rec[key] ?? null;\r\n }\r\n return null;\r\n };\r\n\r\n // 1. Verifica skew de timestamp ANTES da criptografia (fail-fast barato)\r\n // getHeader já normaliza lowercase (Record) e Headers.get é case-insensitive — redundância removida\r\n const tsHeader = getHeader('x-neetru-timestamp');\r\n if (!tsHeader) {\r\n return { ok: false, reason: 'timestamp_missing' };\r\n }\r\n const tsMs = Number(tsHeader);\r\n if (!Number.isFinite(tsMs)) {\r\n return { ok: false, reason: 'timestamp_missing' };\r\n }\r\n const skewMs = Math.abs(Date.now() - tsMs);\r\n if (skewMs > toleranceMs) {\r\n return { ok: false, reason: 'timestamp_expired' };\r\n }\r\n\r\n // 2. Verifica assinatura HMAC-SHA256 (WebCrypto — pode lançar runtime_unsupported).\r\n // 3.1.3 fix (auditoria 2026-06-10): o HMAC do Core cobre `${timestamp}.${rawBody}`\r\n // — antes verificávamos só o body, então TODA entrega legítima falhava aqui.\r\n const sig = getHeader('x-neetru-signature');\r\n const valid = await verifyWebhookSignature(payload, sig, secret, tsHeader);\r\n if (!valid) {\r\n return { ok: false, reason: 'invalid_signature' };\r\n }\r\n\r\n return { ok: true };\r\n}\r\n\r\n/** Hex → bytes. Retorna null em input com tamanho ímpar/inválido. */\r\nfunction hexToBytes(hex: string): Uint8Array | null {\r\n if (hex.length % 2 !== 0) return null;\r\n const bytes = new Uint8Array(hex.length / 2);\r\n for (let i = 0; i < bytes.length; i++) {\r\n const high = parseInt(hex[i * 2], 16);\r\n const low = parseInt(hex[i * 2 + 1], 16);\r\n if (Number.isNaN(high) || Number.isNaN(low)) return null;\r\n bytes[i] = (high << 4) | low;\r\n }\r\n return bytes;\r\n}\r\n\r\n// ─── HTTP impl ──────────────────────────────────────────────────────────────\r\n\r\nconst VALID_EVENTS: readonly WebhookEvent[] = [\r\n 'subscription.activated',\r\n 'subscription.cancelled',\r\n 'subscription.payment_failed',\r\n 'subscription.trial_ending',\r\n 'usage.quota_exceeded',\r\n 'account.suspended',\r\n 'account.reactivated',\r\n 'support.ticket_replied',\r\n];\r\n\r\nfunction toEndpoint(raw: unknown): WebhookEndpoint {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Webhook response is not an object');\r\n }\r\n const r = raw as Record<string, unknown>;\r\n if (typeof r.id !== 'string') {\r\n throw new NeetruError('invalid_response', 'Webhook missing id');\r\n }\r\n return {\r\n id: r.id,\r\n url: typeof r.url === 'string' ? r.url : '',\r\n events: Array.isArray(r.events)\r\n ? (r.events as unknown[]).filter((e): e is WebhookEvent =>\r\n VALID_EVENTS.includes(e as WebhookEvent),\r\n )\r\n : [],\r\n hasSecret: r.hasSecret === true,\r\n status:\r\n r.status === 'active' || r.status === 'degraded' || r.status === 'disabled'\r\n ? r.status\r\n : 'active',\r\n lastDeliveryAt: typeof r.lastDeliveryAt === 'string' ? r.lastDeliveryAt : undefined,\r\n consecutiveFailures:\r\n typeof r.consecutiveFailures === 'number' ? r.consecutiveFailures : undefined,\r\n createdAt: typeof r.createdAt === 'string' ? r.createdAt : new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction validateInput(input: RegisterWebhookInput): void {\r\n if (!input.url || typeof input.url !== 'string') {\r\n throw new NeetruError('validation_failed', 'url é obrigatória');\r\n }\r\n try {\r\n const parsed = new URL(input.url);\r\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\r\n throw new Error('invalid protocol');\r\n }\r\n // Em prod, http: é warning (não bloqueia) — testes locais podem usar\r\n } catch {\r\n throw new NeetruError('validation_failed', `url inválida: ${input.url}`);\r\n }\r\n if (!Array.isArray(input.events) || input.events.length === 0) {\r\n throw new NeetruError('validation_failed', 'events deve ter pelo menos 1 evento');\r\n }\r\n for (const ev of input.events) {\r\n if (!VALID_EVENTS.includes(ev)) {\r\n throw new NeetruError('validation_failed', `evento desconhecido: ${ev}`);\r\n }\r\n }\r\n if (input.secret !== undefined && input.secret.length < 16) {\r\n throw new NeetruError('validation_failed', 'secret deve ter ≥16 chars (recomendado 32+)');\r\n }\r\n}\r\n\r\n/** Resolve productId: option explícito > input.productId > config.productId.\r\n *\r\n * **M-03 fix (Opus review 2026-05-27):** valida client-side contra `SDK_ID_RE`\r\n * antes de mandar pro Core — evita 400 silencioso em produção. */\r\nfunction resolveProductId(\r\n config: ResolvedConfig,\r\n ...candidates: Array<string | undefined>\r\n): string {\r\n for (const c of candidates) {\r\n if (typeof c === 'string' && c.length > 0) {\r\n assertValidSdkId('productId', c);\r\n return c;\r\n }\r\n }\r\n if (config.productId) {\r\n assertValidSdkId('productId', config.productId);\r\n return config.productId;\r\n }\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productId required (pass to options/input or set on createNeetruClient)',\r\n );\r\n}\r\n\r\nexport function createWebhooksNamespace(config: ResolvedConfig): WebhooksNamespace {\r\n return {\r\n async register(input) {\r\n validateInput(input);\r\n const productId = resolveProductId(config, input.productId);\r\n const raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/webhooks',\r\n body: {\r\n productId,\r\n url: input.url,\r\n events: input.events,\r\n ...(input.secret ? { secret: input.secret } : {}),\r\n },\r\n requireAuth: true,\r\n });\r\n return toEndpoint(raw);\r\n },\r\n async list(options) {\r\n const productId = resolveProductId(config, options?.productId);\r\n const raw = await httpRequest<{ endpoints?: unknown[] }>(config, {\r\n method: 'GET',\r\n path: '/api/sdk/v1/webhooks',\r\n query: { productId },\r\n requireAuth: true,\r\n });\r\n const list = Array.isArray(raw?.endpoints) ? raw.endpoints : [];\r\n return list.map(toEndpoint);\r\n },\r\n async unregister(id, options) {\r\n if (!id) throw new NeetruError('validation_failed', 'id obrigatório');\r\n const productId = resolveProductId(config, options?.productId);\r\n await httpRequest<unknown>(config, {\r\n method: 'DELETE',\r\n path: `/api/sdk/v1/webhooks/${encodeURIComponent(id)}`,\r\n query: { productId },\r\n requireAuth: true,\r\n });\r\n return { ok: true };\r\n },\r\n async test(id, options) {\r\n if (!id) throw new NeetruError('validation_failed', 'id obrigatório');\r\n const productId = resolveProductId(config, options?.productId);\r\n const raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: `/api/sdk/v1/webhooks/${encodeURIComponent(id)}/test`,\r\n query: { productId },\r\n requireAuth: true,\r\n idempotencyKey: true,\r\n });\r\n if (!raw || typeof raw !== 'object') {\r\n return { ok: false, error: 'invalid response' };\r\n }\r\n const r = raw as Record<string, unknown>;\r\n return {\r\n ok: r.ok === true,\r\n statusCode: typeof r.statusCode === 'number' ? r.statusCode : undefined,\r\n durationMs: typeof r.durationMs === 'number' ? r.durationMs : undefined,\r\n error: typeof r.error === 'string' ? r.error : undefined,\r\n };\r\n },\r\n };\r\n}\r\n\r\n// ─── Mock impl (dev / tests) ────────────────────────────────────────────────\r\n\r\nexport class MockWebhooks implements WebhooksNamespace {\r\n private endpoints = new Map<string, WebhookEndpoint>();\r\n private nextId = 1;\r\n\r\n async register(input: RegisterWebhookInput): Promise<WebhookEndpoint> {\r\n validateInput(input);\r\n const id = `mock_wh_${this.nextId++}`;\r\n const endpoint: WebhookEndpoint = {\r\n id,\r\n url: input.url,\r\n events: input.events,\r\n hasSecret: !!input.secret,\r\n status: 'active',\r\n createdAt: new Date().toISOString(),\r\n };\r\n this.endpoints.set(id, endpoint);\r\n return endpoint;\r\n }\r\n\r\n async list(_options?: WebhookScopeOptions): Promise<WebhookEndpoint[]> {\r\n return [...this.endpoints.values()];\r\n }\r\n\r\n async unregister(id: string, _options?: WebhookScopeOptions): Promise<{ ok: true }> {\r\n if (!this.endpoints.has(id)) {\r\n throw new NeetruError('not_found', `Webhook ${id} não encontrado`);\r\n }\r\n this.endpoints.delete(id);\r\n return { ok: true };\r\n }\r\n\r\n async test(id: string, _options?: WebhookScopeOptions): Promise<WebhookTestResult> {\r\n if (!this.endpoints.has(id)) {\r\n throw new NeetruError('not_found', `Webhook ${id} não encontrado`);\r\n }\r\n return { ok: true, statusCode: 200, durationMs: 42 };\r\n }\r\n}\r\n","/**\r\n * Notifications namespace (v1.2) — produtos SaaS enviam notificações in-app\r\n * pros SEUS usuários (distinto das `notifications/` staff-only do Core).\r\n *\r\n * Caso típico: produto gestovendas notifica usuário \"Pedido #X recebido\" no\r\n * portal sem precisar manter a própria coleção Firestore.\r\n *\r\n * Schema isolado por produto: `product_user_notifications/{productId}/{notifId}`.\r\n * Owner Neetru não vê o conteúdo (privacidade do produto), mas o Core\r\n * armazena + serve a leitura. Produto pode também listar via SDK.\r\n *\r\n * Endpoints REST (em prod):\r\n * - `POST /api/sdk/v1/notifications` — produto envia\r\n * - `GET /api/sdk/v1/notifications/user/{userId}` — produto lista do user\r\n * - `POST /api/sdk/v1/notifications/{id}/read` — user marca lida (proxy)\r\n * - `POST /api/sdk/v1/notifications/{id}/dismiss` — user descarta (proxy)\r\n *\r\n * Severidade canônica: `info | success | warning | error`.\r\n *\r\n * Mock em `NEETRU_ENV=dev`: in-memory.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport { assertValidSdkId } from './validators';\r\nimport type { ResolvedConfig } from './types';\r\n\r\nexport type ProductNotificationSeverity =\r\n | 'info'\r\n | 'success'\r\n | 'warning'\r\n | 'error';\r\n\r\nexport interface ProductNotification {\r\n id: string;\r\n /** UID do usuário final (do produto, não staff Neetru). */\r\n userId: string;\r\n /** Identificador semântico do evento (ex: `order.received`). */\r\n kind: string;\r\n severity: ProductNotificationSeverity;\r\n title: string;\r\n body?: string;\r\n /** Link opcional pra ação. */\r\n link?: string;\r\n /** Metadata livre (serializável). */\r\n metadata?: Record<string, string | number | boolean | null>;\r\n createdAt: string;\r\n /** ISO quando user marcou lida. */\r\n readAt?: string;\r\n /** ISO quando user descartou. */\r\n dismissedAt?: string;\r\n}\r\n\r\nexport interface SendNotificationInput {\r\n /**\r\n * **3.0 (breaking):** productId é obrigatório (Core valida via Zod). Default\r\n * resolve do `config.productId`; lança `validation_failed` se ausente.\r\n */\r\n productId?: string;\r\n userId: string;\r\n kind: string;\r\n title: string;\r\n severity?: ProductNotificationSeverity;\r\n body?: string;\r\n link?: string;\r\n metadata?: Record<string, string | number | boolean | null>;\r\n /**\r\n * Dedup — se já existir notificação com mesmo fingerprint dentro de 24h,\r\n * NÃO cria duplicata. Útil pra evitar spam quando webhook reentrega.\r\n */\r\n fingerprint?: string;\r\n}\r\n\r\nexport interface ListNotificationsOptions {\r\n /**\r\n * **3.0 (breaking):** productId é obrigatório no Core. Default resolve do\r\n * `config.productId`.\r\n */\r\n productId?: string;\r\n /** Inclui notificações dismissed (default false). */\r\n includeDismissed?: boolean;\r\n /** Filtro por unread. */\r\n onlyUnread?: boolean;\r\n /** Máx itens (default 50, máx 200). */\r\n limit?: number;\r\n}\r\n\r\n/** 3.0: scope option pra markRead/dismiss (productId obrigatório no Core). */\r\nexport interface NotificationScopeOptions {\r\n productId?: string;\r\n}\r\n\r\nexport interface NotificationsNamespace {\r\n /** Produto envia uma notificação pra um usuário do produto. */\r\n send(input: SendNotificationInput): Promise<ProductNotification>;\r\n /** Lista notificações de um usuário. */\r\n list(\r\n userId: string,\r\n options?: ListNotificationsOptions,\r\n ): Promise<ProductNotification[]>;\r\n /** Marca como lida. */\r\n markRead(id: string, options?: NotificationScopeOptions): Promise<{ ok: true }>;\r\n /** Descarta. */\r\n dismiss(id: string, options?: NotificationScopeOptions): Promise<{ ok: true }>;\r\n}\r\n\r\n// ─── HTTP impl ──────────────────────────────────────────────────────────────\r\n\r\nconst VALID_SEVERITIES: readonly ProductNotificationSeverity[] = [\r\n 'info',\r\n 'success',\r\n 'warning',\r\n 'error',\r\n];\r\n\r\nfunction toNotification(raw: unknown): ProductNotification {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Notification response is not an object');\r\n }\r\n const r = raw as Record<string, unknown>;\r\n if (typeof r.id !== 'string') {\r\n throw new NeetruError('invalid_response', 'Notification missing id');\r\n }\r\n const sev = VALID_SEVERITIES.includes(r.severity as ProductNotificationSeverity)\r\n ? (r.severity as ProductNotificationSeverity)\r\n : 'info';\r\n return {\r\n id: r.id,\r\n userId: typeof r.userId === 'string' ? r.userId : '',\r\n kind: typeof r.kind === 'string' ? r.kind : 'unknown',\r\n severity: sev,\r\n title: typeof r.title === 'string' ? r.title : '',\r\n body: typeof r.body === 'string' ? r.body : undefined,\r\n link: typeof r.link === 'string' ? r.link : undefined,\r\n metadata:\r\n r.metadata && typeof r.metadata === 'object'\r\n ? (r.metadata as Record<string, string | number | boolean | null>)\r\n : undefined,\r\n createdAt: typeof r.createdAt === 'string' ? r.createdAt : new Date().toISOString(),\r\n readAt: typeof r.readAt === 'string' ? r.readAt : undefined,\r\n dismissedAt: typeof r.dismissedAt === 'string' ? r.dismissedAt : undefined,\r\n };\r\n}\r\n\r\nfunction validateInput(input: SendNotificationInput): void {\r\n if (!input.userId) throw new NeetruError('validation_failed', 'userId obrigatório');\r\n if (!input.kind) throw new NeetruError('validation_failed', 'kind obrigatório');\r\n if (!input.title) throw new NeetruError('validation_failed', 'title obrigatório');\r\n if (input.severity && !VALID_SEVERITIES.includes(input.severity)) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n `severity inválida: ${input.severity} (use ${VALID_SEVERITIES.join('|')})`,\r\n );\r\n }\r\n if (input.title.length > 200) {\r\n throw new NeetruError('validation_failed', 'title máx 200 chars');\r\n }\r\n if (input.body && input.body.length > 2000) {\r\n throw new NeetruError('validation_failed', 'body máx 2000 chars');\r\n }\r\n}\r\n\r\n/** Resolve productId fail-closed (option > input > config).\r\n *\r\n * **M-03 fix (Opus review 2026-05-27):** valida client-side contra `SDK_ID_RE`. */\r\nfunction resolveProductId(\r\n config: ResolvedConfig,\r\n ...candidates: Array<string | undefined>\r\n): string {\r\n for (const c of candidates) {\r\n if (typeof c === 'string' && c.length > 0) {\r\n assertValidSdkId('productId', c);\r\n return c;\r\n }\r\n }\r\n if (config.productId) {\r\n assertValidSdkId('productId', config.productId);\r\n return config.productId;\r\n }\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productId required (pass to options/input or set on createNeetruClient)',\r\n );\r\n}\r\n\r\nexport function createNotificationsNamespace(\r\n config: ResolvedConfig,\r\n): NotificationsNamespace {\r\n return {\r\n async send(input) {\r\n validateInput(input);\r\n const productId = resolveProductId(config, input.productId);\r\n const body: Record<string, unknown> = {\r\n productId,\r\n userId: input.userId,\r\n kind: input.kind,\r\n title: input.title,\r\n severity: input.severity ?? 'info',\r\n };\r\n if (input.body !== undefined) body.body = input.body;\r\n if (input.link !== undefined) body.link = input.link;\r\n if (input.metadata !== undefined) body.metadata = input.metadata;\r\n if (input.fingerprint !== undefined) body.fingerprint = input.fingerprint;\r\n const raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/notifications',\r\n body,\r\n requireAuth: true,\r\n idempotencyKey: true,\r\n });\r\n return toNotification(raw);\r\n },\r\n async list(userId, options) {\r\n if (!userId) throw new NeetruError('validation_failed', 'userId obrigatório');\r\n const productId = resolveProductId(config, options?.productId);\r\n const query: Record<string, string | number | boolean | undefined> = {\r\n productId,\r\n };\r\n if (options?.includeDismissed) query.includeDismissed = true;\r\n if (options?.onlyUnread) query.onlyUnread = true;\r\n if (options?.limit) {\r\n query.limit = Math.min(Math.max(1, options.limit), 200);\r\n }\r\n const raw = await httpRequest<{ notifications?: unknown[] }>(config, {\r\n method: 'GET',\r\n path: `/api/sdk/v1/notifications/user/${encodeURIComponent(userId)}`,\r\n query,\r\n requireAuth: true,\r\n });\r\n const list = Array.isArray(raw?.notifications) ? raw.notifications : [];\r\n return list.map(toNotification);\r\n },\r\n async markRead(id, options) {\r\n if (!id) throw new NeetruError('validation_failed', 'id obrigatório');\r\n const productId = resolveProductId(config, options?.productId);\r\n await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: `/api/sdk/v1/notifications/${encodeURIComponent(id)}/read`,\r\n query: { productId },\r\n requireAuth: true,\r\n });\r\n return { ok: true };\r\n },\r\n async dismiss(id, options) {\r\n if (!id) throw new NeetruError('validation_failed', 'id obrigatório');\r\n const productId = resolveProductId(config, options?.productId);\r\n await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: `/api/sdk/v1/notifications/${encodeURIComponent(id)}/dismiss`,\r\n query: { productId },\r\n requireAuth: true,\r\n });\r\n return { ok: true };\r\n },\r\n };\r\n}\r\n\r\n// ─── Mock impl ──────────────────────────────────────────────────────────────\r\n\r\nexport class MockNotifications implements NotificationsNamespace {\r\n private notifications = new Map<string, ProductNotification>();\r\n private nextId = 1;\r\n\r\n async send(input: SendNotificationInput): Promise<ProductNotification> {\r\n validateInput(input);\r\n // Dedup por fingerprint: se já existe um com mesmo fingerprint < 24h, retorna ele.\r\n if (input.fingerprint) {\r\n const dayAgo = Date.now() - 86_400_000;\r\n for (const existing of this.notifications.values()) {\r\n const meta = existing.metadata ?? {};\r\n if (\r\n meta.fingerprint === input.fingerprint &&\r\n existing.userId === input.userId &&\r\n new Date(existing.createdAt).getTime() > dayAgo\r\n ) {\r\n return existing;\r\n }\r\n }\r\n }\r\n const id = `mock_notif_${this.nextId++}`;\r\n const notif: ProductNotification = {\r\n id,\r\n userId: input.userId,\r\n kind: input.kind,\r\n severity: input.severity ?? 'info',\r\n title: input.title,\r\n body: input.body,\r\n link: input.link,\r\n metadata: input.fingerprint\r\n ? { ...(input.metadata ?? {}), fingerprint: input.fingerprint }\r\n : input.metadata,\r\n createdAt: new Date().toISOString(),\r\n };\r\n this.notifications.set(id, notif);\r\n return notif;\r\n }\r\n\r\n async list(\r\n userId: string,\r\n options?: ListNotificationsOptions,\r\n ): Promise<ProductNotification[]> {\r\n if (!userId) throw new NeetruError('validation_failed', 'userId obrigatório');\r\n const limit = Math.min(Math.max(1, options?.limit ?? 50), 200);\r\n return [...this.notifications.values()]\r\n .filter((n) => n.userId === userId)\r\n .filter((n) => options?.includeDismissed || !n.dismissedAt)\r\n .filter((n) => !options?.onlyUnread || !n.readAt)\r\n .sort((a, b) => b.createdAt.localeCompare(a.createdAt))\r\n .slice(0, limit);\r\n }\r\n\r\n async markRead(id: string, _options?: NotificationScopeOptions): Promise<{ ok: true }> {\r\n const n = this.notifications.get(id);\r\n if (!n) throw new NeetruError('not_found', `Notification ${id} não encontrada`);\r\n if (!n.readAt) {\r\n n.readAt = new Date().toISOString();\r\n this.notifications.set(id, n);\r\n }\r\n return { ok: true };\r\n }\r\n\r\n async dismiss(id: string, _options?: NotificationScopeOptions): Promise<{ ok: true }> {\r\n const n = this.notifications.get(id);\r\n if (!n) throw new NeetruError('not_found', `Notification ${id} não encontrada`);\r\n if (!n.dismissedAt) {\r\n n.dismissedAt = new Date().toISOString();\r\n this.notifications.set(id, n);\r\n }\r\n return { ok: true };\r\n }\r\n}\r\n","/**\r\n * Mocks determinísticos do SDK — overridáveis em tests do consumer ou\r\n * ativados automaticamente quando `NEETRU_ENV=dev`.\r\n *\r\n * Nada aqui faz I/O. Tudo é puro/sincrono/in-memory. Compat total com\r\n * runtimes browser/Node/Edge — sem `node:` builtins.\r\n *\r\n * Cada mock implementa o mesmo namespace interface das implementações reais\r\n * (`AuthNamespace`, `UsageNamespace`, `SupportNamespace`) — caller pode\r\n * substituir 1:1 sem branching.\r\n *\r\n * @example\r\n * ```ts\r\n * import { createNeetruClient, MockAuth } from '@neetru/sdk';\r\n *\r\n * const client = createNeetruClient({\r\n * mocks: { auth: new MockAuth({ uid: 'fake-user', email: 'x@x.com' }) },\r\n * });\r\n * ```\r\n */\r\n\r\nimport type {\r\n AuthNamespace,\r\n AuthStateListener,\r\n CreateTicketInput,\r\n EntitlementCheck,\r\n NeetruUser,\r\n RedirectCallbackResult,\r\n SignInOptions,\r\n SupportNamespace,\r\n SupportTicket,\r\n UsageNamespace,\r\n UsageQuota,\r\n} from './types';\r\nimport type {\r\n NeetruDb,\r\n NeetruSqlClient,\r\n} from './db/client-db';\r\nimport type { DbCollectionRef, DbWhereFilter, DbListResult, DbGetResult, DbBatchOp, DbDocRef, DbQuery } from './db/collection-ref';\r\nimport type { SyncState, ConflictRecord, Unsubscribe } from './db/offline/types';\r\nimport { NeetruDbError } from './db-errors';\r\nimport { NeetruError } from './errors';\r\n\r\n// ─── User fixture default ──────────────────────────────────────────────────\r\n\r\n/**\r\n * User fixture determinístico — usado quando `NEETRU_ENV=dev` e nenhum mock\r\n * custom é injetado. Email/uid estáveis pra snapshot tests.\r\n */\r\nexport const DEV_FIXTURE_USER: NeetruUser = Object.freeze({\r\n uid: 'dev-fixture-uid-0001',\r\n email: 'dev@neetru.local',\r\n emailVerified: true,\r\n displayName: 'Dev Fixture',\r\n isCustomer: true,\r\n isStaff: false,\r\n}) as NeetruUser;\r\n\r\n// ─── MockAuth ──────────────────────────────────────────────────────────────\r\n\r\n/** Opções do construtor de `MockAuth`. */\r\nexport interface MockAuthOptions {\r\n /**\r\n * Permite que `verifyToken` decodifique tokens JWT sem verificar assinatura.\r\n *\r\n * **SOMENTE para uso em testes.** Com `allowUnsignedDecode: false` (default),\r\n * `verifyToken` lança `unauthorized` em vez de aceitar qualquer JWT não-assinado —\r\n * isso previne que misconfiguração de env (`NEETRU_ENV=dev` em prod) vire bypass\r\n * de autenticação. Testes que precisam do comportamento de decode devem passar\r\n * `{ allowUnsignedDecode: true }` explicitamente.\r\n */\r\n allowUnsignedDecode?: boolean;\r\n}\r\n\r\n/**\r\n * Implementação in-memory do `AuthNamespace`. signIn marca o user como\r\n * logado; signOut limpa. onAuthStateChanged dispara callback síncrono no\r\n * subscribe + a cada mudança.\r\n */\r\nexport class MockAuth implements AuthNamespace {\r\n private _user: NeetruUser | null;\r\n private _listeners: Set<AuthStateListener>;\r\n private _allowUnsignedDecode: boolean;\r\n\r\n constructor(initialUser: NeetruUser | null = null, options?: MockAuthOptions) {\r\n this._user = initialUser;\r\n this._listeners = new Set();\r\n this._allowUnsignedDecode = options?.allowUnsignedDecode ?? false;\r\n\r\n // Emite aviso proeminente em dev quando fora de testes, pra deixar claro\r\n // que verifyToken no mock NÃO valida assinaturas.\r\n // Guard: não spamma em ambientes de teste (process.env.NODE_ENV=test ou\r\n // VITEST=true). Emite só uma vez por instância (basta pra chamar atenção).\r\n if (this._allowUnsignedDecode) {\r\n const isTestEnv =\r\n (typeof process !== 'undefined' && (\r\n process.env?.NODE_ENV === 'test' ||\r\n process.env?.VITEST === 'true' ||\r\n process.env?.VITEST != null\r\n ));\r\n if (!isTestEnv && typeof console !== 'undefined') {\r\n console.warn(\r\n '[neetru-sdk] MockAuth.verifyToken está em modo allowUnsignedDecode=true: ' +\r\n 'tokens NÃO têm assinatura verificada. ' +\r\n 'Este modo é exclusivo para testes — NUNCA use como security boundary em código deployado.',\r\n );\r\n }\r\n }\r\n }\r\n\r\n async signIn(_options?: SignInOptions): Promise<NeetruUser> {\r\n // Mock: apenas marca user como logado (usa fixture se não havia).\r\n if (!this._user) this._user = { ...DEV_FIXTURE_USER };\r\n this._notify();\r\n return this._user;\r\n }\r\n\r\n async signOut(): Promise<void> {\r\n this._user = null;\r\n this._notify();\r\n }\r\n\r\n getUser(): NeetruUser | null {\r\n return this._user;\r\n }\r\n\r\n onAuthStateChanged(listener: AuthStateListener): () => void {\r\n this._listeners.add(listener);\r\n // Dispara imediatamente com estado atual (espelha API Firebase Auth).\r\n try {\r\n listener(this._user);\r\n } catch {\r\n // Callback do consumer não pode quebrar o subscribe.\r\n }\r\n return () => {\r\n this._listeners.delete(listener);\r\n };\r\n }\r\n\r\n /**\r\n * Mock de `verifyToken` — por default lança `unauthorized` pra prevenir uso\r\n * acidental como security boundary em código deployado.\r\n *\r\n * Para decodificar JWTs sem verificar assinatura em testes, crie a instância\r\n * com `new MockAuth(user, { allowUnsignedDecode: true })`. Isso é um opt-in\r\n * explícito — nunca acontece silenciosamente.\r\n *\r\n * Para simular falhas ou resultados customizados, use `__mockVerifyToken(fn)`.\r\n */\r\n async verifyToken(token: string): Promise<NeetruUser> {\r\n if (this._verifyTokenOverride) {\r\n return this._verifyTokenOverride(token);\r\n }\r\n if (!token) {\r\n throw new NeetruError('token_invalid_signature', 'Token inválido: string vazia');\r\n }\r\n // Sem opt-in explícito, recusa-se a decodificar — decodificar JWTs sem\r\n // verificar assinatura é uma vulnerabilidade se este mock vazar pra produção\r\n // (ex: NEETRU_ENV=dev configurado erroneamente, ou globalThis.NEETRU_ENV\r\n // injetado por bundle). O caller deve usar __mockVerifyToken() ou passar\r\n // allowUnsignedDecode: true no construtor.\r\n if (!this._allowUnsignedDecode) {\r\n throw new NeetruError(\r\n 'unauthorized',\r\n 'MockAuth.verifyToken não verifica assinaturas JWT e NÃO deve ser usado como ' +\r\n 'security boundary em código deployado. ' +\r\n 'Em testes, use new MockAuth(user, { allowUnsignedDecode: true }) para habilitar ' +\r\n 'decodificação sem assinatura, ou __mockVerifyToken(fn) para injetar resultado customizado.',\r\n );\r\n }\r\n // allowUnsignedDecode=true: decodifica claims base64 sem verificar assinatura (testes).\r\n try {\r\n const parts = token.split('.');\r\n if (parts.length === 3) {\r\n const b64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');\r\n const pad = '='.repeat((4 - (b64.length % 4)) % 4);\r\n const decoded = JSON.parse(\r\n typeof atob === 'function'\r\n ? atob(b64 + pad)\r\n : Buffer.from(b64 + pad, 'base64').toString('utf-8'),\r\n ) as Record<string, unknown>;\r\n if (typeof decoded.sub === 'string') {\r\n return {\r\n uid: decoded.sub,\r\n email: typeof decoded.email === 'string' ? decoded.email : '',\r\n emailVerified: typeof decoded.email_verified === 'boolean' ? decoded.email_verified : undefined,\r\n displayName: typeof decoded.name === 'string' ? decoded.name : undefined,\r\n photoURL: typeof decoded.picture === 'string' ? decoded.picture : undefined,\r\n isStaff: decoded.is_staff === true,\r\n isCustomer: decoded.is_customer === true,\r\n tenantId: typeof decoded.tenant_id === 'string' ? decoded.tenant_id : undefined,\r\n ...decoded,\r\n };\r\n }\r\n }\r\n } catch {\r\n /* fall through to return current user */\r\n }\r\n // Fallback: retorna o user atual do mock.\r\n if (this._user) return this._user;\r\n throw new NeetruError('token_invalid_signature', 'Nenhum user mock disponível e JWT sem sub válido');\r\n }\r\n\r\n /**\r\n * Mock de `handleRedirectCallback` (Bug 2 / 3.1.3) — não há redirect real no\r\n * mock, então retorna `null` por default. Use `__setPendingCallback(result)`\r\n * em testes pra simular um retorno do IdP.\r\n */\r\n async handleRedirectCallback(_currentUrl?: string): Promise<RedirectCallbackResult | null> {\r\n return this._pendingCallback;\r\n }\r\n\r\n /**\r\n * Mock de `getIdToken` (Bug 2 / 3.1.3). Retorna `null` por default; use\r\n * `__setIdToken(token)` pra injetar um token cru em testes.\r\n */\r\n getIdToken(): string | null {\r\n return this._idToken;\r\n }\r\n\r\n private _pendingCallback: RedirectCallbackResult | null = null;\r\n private _idToken: string | null = null;\r\n\r\n /** Test helper — simula o material devolvido por um callback OIDC. */\r\n __setPendingCallback(result: RedirectCallbackResult | null): void {\r\n this._pendingCallback = result;\r\n }\r\n\r\n /** Test helper — injeta o id_token cru retornado por `getIdToken`. */\r\n __setIdToken(token: string | null): void {\r\n this._idToken = token;\r\n }\r\n\r\n private _verifyTokenOverride: ((token: string) => Promise<NeetruUser>) | null = null;\r\n\r\n /**\r\n * Injeta override pra `verifyToken` em testes — permite simular expiração,\r\n * assinatura inválida etc sem precisar de JWT real.\r\n *\r\n * @example\r\n * ```ts\r\n * const mock = new MockAuth(null);\r\n * mock.__mockVerifyToken(async () => { throw new NeetruError('token_expired', '...'); });\r\n * ```\r\n */\r\n __mockVerifyToken(fn: ((token: string) => Promise<NeetruUser>) | null): void {\r\n this._verifyTokenOverride = fn;\r\n }\r\n\r\n /** Helper de tests — força um user state arbitrário. */\r\n __setUser(user: NeetruUser | null): void {\r\n this._user = user;\r\n this._notify();\r\n }\r\n\r\n private _notify(): void {\r\n for (const l of this._listeners) {\r\n try {\r\n l(this._user);\r\n } catch {\r\n // ignore consumer errors\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ─── MockUsage (3.0 — track/getQuota removidos) ────────────────────────────\r\n\r\ninterface UsageReportRecord {\r\n resource: string;\r\n qty: number;\r\n productId?: string;\r\n tenantId?: string;\r\n timestamp: string;\r\n}\r\n\r\n/**\r\n * In-memory `UsageNamespace` 3.0. `report()` acumula counter local; `check()`\r\n * compara com `__setQuota(resource, {used, limit})` fixture.\r\n *\r\n * Breaking 3.0:\r\n * - `track(event, props)` REMOVIDO.\r\n * - `getQuota(metric)` REMOVIDO.\r\n * - `__getRecords()` agora retorna `UsageReportRecord[]` (resource/qty).\r\n */\r\nexport class MockUsage implements UsageNamespace {\r\n private _reports: UsageReportRecord[] = [];\r\n private _quotas: Map<string, UsageQuota>;\r\n private _counters: Map<string, number> = new Map();\r\n\r\n constructor(initialQuotas: Record<string, UsageQuota> = {}) {\r\n this._quotas = new Map(Object.entries(initialQuotas));\r\n }\r\n\r\n async report(\r\n resource: string,\r\n qty: number = 1,\r\n options?: { productId?: string; tenantId?: string },\r\n ): Promise<{\r\n ok: true;\r\n counterId?: string;\r\n value?: number;\r\n limit?: number;\r\n remaining?: number;\r\n status?: string;\r\n }> {\r\n if (!resource) throw new Error('resource required');\r\n const safeQty = Number.isFinite(qty) && qty > 0 ? Math.floor(qty) : 1;\r\n const existing = this._counters.get(resource) ?? 0;\r\n const next = existing + safeQty;\r\n this._counters.set(resource, next);\r\n this._reports.push({\r\n resource,\r\n qty: safeQty,\r\n productId: options?.productId,\r\n tenantId: options?.tenantId,\r\n timestamp: new Date().toISOString(),\r\n });\r\n const limitFixture = this._quotas.get(resource);\r\n const limit = limitFixture?.limit ?? -1;\r\n return {\r\n ok: true,\r\n counterId: `mock_${resource}`,\r\n value: next,\r\n limit,\r\n remaining: limit < 0 ? -1 : Math.max(0, limit - next),\r\n status: limit > 0 && next >= limit ? 'read_only_overlimit' : 'ok',\r\n };\r\n }\r\n\r\n async check(\r\n resource: string,\r\n _options?: { productId?: string; tenantId?: string },\r\n ): Promise<{\r\n allowed: boolean;\r\n reason?: string;\r\n remaining?: number;\r\n limit?: number;\r\n planId?: string | null;\r\n planFeatures?: string[];\r\n behavior?: 'readonly' | null;\r\n }> {\r\n const quota = this._quotas.get(resource);\r\n const used = this._counters.get(resource) ?? 0;\r\n if (!quota) {\r\n return { allowed: true, reason: 'granted', limit: -1, remaining: -1, behavior: null };\r\n }\r\n const remaining = quota.limit < 0 ? -1 : Math.max(0, quota.limit - used);\r\n if (remaining === 0) {\r\n return {\r\n allowed: false,\r\n reason: 'limit_exceeded',\r\n limit: quota.limit,\r\n remaining: 0,\r\n behavior: 'readonly',\r\n };\r\n }\r\n return {\r\n allowed: true,\r\n reason: 'granted',\r\n limit: quota.limit,\r\n remaining,\r\n behavior: null,\r\n };\r\n }\r\n\r\n /** Test helper — retorna histórico de `report()` calls. */\r\n __getReports(): readonly UsageReportRecord[] {\r\n return [...this._reports];\r\n }\r\n /** @deprecated Removido em 3.0 (usage.track foi removido). Use `__getReports`. */\r\n __getRecords(): readonly UsageReportRecord[] {\r\n return this.__getReports();\r\n }\r\n /** Test helper — substitui quota fixture. */\r\n __setQuota(metric: string, quota: UsageQuota): void {\r\n this._quotas.set(metric, quota);\r\n }\r\n /** Test helper — limpa estado. */\r\n __reset(): void {\r\n this._reports = [];\r\n this._quotas.clear();\r\n this._counters.clear();\r\n }\r\n}\r\n\r\n// ─── MockSupport ───────────────────────────────────────────────────────────\r\n\r\n/**\r\n * In-memory `SupportNamespace`. createTicket gera ID `mock-ticket-{n}`;\r\n * listMyTickets retorna todos criados (FIFO). Sequência por instância\r\n * (evita poluição cross-test do estado de módulo).\r\n */\r\nexport class MockSupport implements SupportNamespace {\r\n private _tickets: SupportTicket[] = [];\r\n private _ticketSeq = 0;\r\n\r\n async createTicket(input: CreateTicketInput): Promise<SupportTicket> {\r\n // L-03 fix (Opus review): MockSupport agora espelha contrato 3.0 do Core.\r\n // Antes aceitava input sem productSlug, mascarando bugs em tests que\r\n // passariam em prod com 400 validation_failed.\r\n if (!input?.subject) throw new NeetruError('validation_failed', 'subject required');\r\n if (!input?.message) throw new NeetruError('validation_failed', 'message required');\r\n if (!input?.productSlug) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productSlug required (3.0 breaking — pass to input or set on createNeetruClient)',\r\n );\r\n }\r\n const ticket: SupportTicket = {\r\n id: `mock-ticket-${++this._ticketSeq}`,\r\n subject: input.subject,\r\n message: input.message,\r\n severity: input.severity ?? 'normal',\r\n status: 'open',\r\n createdAt: new Date().toISOString(),\r\n productSlug: input.productSlug,\r\n };\r\n this._tickets.push(ticket);\r\n return ticket;\r\n }\r\n\r\n async listMyTickets(options?: { productSlug?: string }): Promise<SupportTicket[]> {\r\n if (options?.productSlug) {\r\n return this._tickets.filter((t) => t.productSlug === options.productSlug);\r\n }\r\n return [...this._tickets];\r\n }\r\n\r\n /** Test helper. */\r\n __reset(): void {\r\n this._tickets = [];\r\n this._ticketSeq = 0;\r\n }\r\n}\r\n\r\n// ─── MockEntitlements ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * In-memory entitlements. Por default `allowed=true` em tudo (dev convém).\r\n * Use `__deny(slug, feature)` em tests pra simular bloqueio.\r\n */\r\nexport class MockEntitlements {\r\n private _denied: Set<string> = new Set();\r\n\r\n async check(productSlug: string, feature: string): Promise<boolean> {\r\n return !this._denied.has(`${productSlug}:${feature}`);\r\n }\r\n\r\n async checkDetailed(productSlug: string, feature: string): Promise<EntitlementCheck> {\r\n const allowed = await this.check(productSlug, feature);\r\n return {\r\n allowed,\r\n productSlug,\r\n feature,\r\n reason: allowed ? 'granted' : 'mock_denied',\r\n };\r\n }\r\n\r\n /** Test helper. */\r\n __deny(productSlug: string, feature: string): void {\r\n this._denied.add(`${productSlug}:${feature}`);\r\n }\r\n /** Test helper. */\r\n __reset(): void {\r\n this._denied.clear();\r\n }\r\n}\r\n\r\n// ─── MockDb (v2.0) ─────────────────────────────────────────────────────────\r\n\r\n/**\r\n * In-memory `NeetruDb`. Cada `collection(name)` aponta para um Map; ops\r\n * são totalmente síncronas (mas API await-friendly).\r\n *\r\n * v2.0: implementa a interface `NeetruDb` completa (collection, sql, syncState,\r\n * flush, clearCache, getConflicts, onSyncStateChanged).\r\n *\r\n * Útil para testar produtos consumidores sem rodar Core REST nem IndexedDB.\r\n */\r\nexport class MockDb implements NeetruDb {\r\n private _store: Map<string, Map<string, Record<string, unknown>>> = new Map();\r\n private _fixtures: Map<string, Record<string, Record<string, unknown>>>;\r\n\r\n constructor(initialFixtures: Record<string, Record<string, Record<string, unknown>>> = {}) {\r\n this._fixtures = new Map(Object.entries(initialFixtures));\r\n }\r\n\r\n collection<T = Record<string, unknown>>(name: string): DbCollectionRef<T> {\r\n const _store = this._store;\r\n const _fixtures = this._fixtures;\r\n if (!_store.has(name)) {\r\n const init = _fixtures.get(name);\r\n _store.set(\r\n name,\r\n init ? new Map(Object.entries(init)) : new Map(),\r\n );\r\n }\r\n const coll = _store.get(name)!;\r\n\r\n const matchesFilter = (\r\n doc: Record<string, unknown>,\r\n f: DbWhereFilter,\r\n ): boolean => {\r\n const v = doc[f.field];\r\n switch (f.op) {\r\n case '==':\r\n return v === f.value;\r\n case '!=':\r\n return v !== f.value;\r\n case '<':\r\n return typeof v === 'number' && typeof f.value === 'number' && v < f.value;\r\n case '<=':\r\n return typeof v === 'number' && typeof f.value === 'number' && v <= f.value;\r\n case '>':\r\n return typeof v === 'number' && typeof f.value === 'number' && v > f.value;\r\n case '>=':\r\n return typeof v === 'number' && typeof f.value === 'number' && v >= f.value;\r\n case 'in':\r\n return Array.isArray(f.value) && (f.value as unknown[]).includes(v);\r\n case 'array-contains':\r\n return Array.isArray(v) && (v as unknown[]).includes(f.value);\r\n case 'not-in':\r\n return Array.isArray(f.value) && !(f.value as unknown[]).includes(v);\r\n default:\r\n return true;\r\n }\r\n };\r\n\r\n let autoSeq = 0;\r\n\r\n // Helper to build a minimal DbListResult from raw items\r\n function buildListResult<U>(items: Array<Record<string, unknown>>): DbListResult<U> {\r\n return {\r\n docs: items.map((d, i) => ({ id: (d.id as string) ?? String(i), data: d as U })),\r\n nextCursor: null,\r\n fromCache: false,\r\n stale: false,\r\n hasPendingWrites: false,\r\n changes: [],\r\n };\r\n }\r\n\r\n // Helper to build a DbGetResult for a single doc\r\n function buildGetResult<U>(data: Record<string, unknown>, id: string): DbGetResult<U> {\r\n return {\r\n docs: [{ id, data: data as U }],\r\n fromCache: false,\r\n stale: false,\r\n hasPendingWrites: false,\r\n changes: [],\r\n };\r\n }\r\n\r\n const ref: DbCollectionRef<T> = {\r\n async list(q?: DbQuery): Promise<DbListResult<T>> {\r\n let items = Array.from(coll.values());\r\n if (q?.where && q.where.length > 0) {\r\n items = items.filter((doc) =>\r\n (q.where as DbWhereFilter[]).every((f) => matchesFilter(doc, f)),\r\n );\r\n }\r\n if (q?.orderBy) {\r\n const { field, direction } = q.orderBy;\r\n items = items.slice().sort((a, b) => {\r\n const av = a[field];\r\n const bv = b[field];\r\n const avs = av ?? '';\r\n const bvs = bv ?? '';\r\n const cmp = (avs as string) < (bvs as string) ? -1 : (avs as string) > (bvs as string) ? 1 : 0;\r\n return direction === 'desc' ? -cmp : cmp;\r\n });\r\n }\r\n const limit = q?.limit ?? 20;\r\n items = items.slice(0, limit);\r\n return buildListResult<T>(items);\r\n },\r\n async get(id: string): Promise<DbGetResult<T> | null> {\r\n const data = coll.get(id);\r\n if (!data) return null;\r\n return buildGetResult<T>(data, id);\r\n },\r\n async add(data: Omit<T, 'id'>): Promise<{ ok: true; id: string }> {\r\n const id = `mock-${++autoSeq}-${Math.random().toString(36).slice(2, 8)}`;\r\n coll.set(id, { ...(data as Record<string, unknown>), id });\r\n return { ok: true, id };\r\n },\r\n async set(id: string, data: Omit<T, 'id'>): Promise<{ ok: true }> {\r\n coll.set(id, { ...(data as Record<string, unknown>), id });\r\n return { ok: true };\r\n },\r\n async update(id: string, data: Partial<Omit<T, 'id'>>): Promise<{ ok: true }> {\r\n const cur = coll.get(id);\r\n if (!cur) {\r\n coll.set(id, { ...(data as Record<string, unknown>), id });\r\n } else {\r\n coll.set(id, { ...cur, ...(data as Record<string, unknown>) });\r\n }\r\n return { ok: true };\r\n },\r\n async remove(id: string): Promise<{ ok: true }> {\r\n coll.delete(id);\r\n return { ok: true };\r\n },\r\n async batch(ops: DbBatchOp[]): Promise<{ ok: true }> {\r\n for (const op of ops) {\r\n // Mock usa a coleção corrente (collName) — o campo collection foi removido\r\n // do discriminated union em 2.1.1; batch opera sempre na coleção do ref.\r\n const collMap = coll;\r\n if (op.kind === 'add') {\r\n const id = `mock-batch-${++autoSeq}`;\r\n collMap.set(id, { ...(op.data as Record<string, unknown>), id });\r\n } else if (op.kind === 'set') {\r\n collMap.set(op.id, { ...(op.data as Record<string, unknown>), id: op.id });\r\n } else if (op.kind === 'update') {\r\n const cur = collMap.get(op.id);\r\n collMap.set(op.id, { ...(cur ?? {}), ...(op.data as Record<string, unknown>), id: op.id });\r\n } else if (op.kind === 'remove') {\r\n collMap.delete(op.id);\r\n }\r\n }\r\n return { ok: true };\r\n },\r\n onDoc(id: string, cb: (doc: T | null) => void): Unsubscribe {\r\n // Entrega snapshot inicial imediato (sync mock)\r\n const data = coll.get(id);\r\n Promise.resolve().then(() => cb(data ? (data as T) : null));\r\n // Mock: não há feed realtime — retorna no-op unsubscribe\r\n return () => {};\r\n },\r\n onSnapshot(q: DbQuery | undefined, cb: (snap: DbListResult<T>) => void): Unsubscribe {\r\n // Entrega snapshot inicial imediato (sync mock)\r\n Promise.resolve().then(async () => {\r\n const snap = await ref.list(q);\r\n cb(snap);\r\n });\r\n return () => {};\r\n },\r\n doc(id: string): DbDocRef<T> {\r\n return {\r\n get id(): string { return id; },\r\n get path(): string { return `${name}/${id}`; },\r\n get collection(): string { return name; },\r\n async get() {\r\n const data = coll.get(id);\r\n if (!data) return null;\r\n return buildGetResult<T>(data, id);\r\n },\r\n async set(data: Omit<T, 'id'>) {\r\n coll.set(id, { ...(data as Record<string, unknown>), id });\r\n return { ok: true };\r\n },\r\n async update(data: Partial<Omit<T, 'id'>>) {\r\n const cur = coll.get(id);\r\n if (!cur) {\r\n coll.set(id, { ...(data as Record<string, unknown>), id });\r\n } else {\r\n coll.set(id, { ...cur, ...(data as Record<string, unknown>) });\r\n }\r\n return { ok: true };\r\n },\r\n async remove() {\r\n coll.delete(id);\r\n return { ok: true };\r\n },\r\n onSnapshot(cb: (snap: DbGetResult<T> | null) => void): Unsubscribe {\r\n const data = coll.get(id);\r\n Promise.resolve().then(() =>\r\n cb(data ? buildGetResult<T>(data, id) : null),\r\n );\r\n return () => {};\r\n },\r\n };\r\n },\r\n };\r\n\r\n return ref;\r\n }\r\n\r\n /**\r\n * Implementa SQL in-memory para testes — preferência: `@electric-sql/pglite`\r\n * + `drizzle-orm/pglite`; fallback: `pg-mem` + `drizzle-orm/node-postgres`\r\n * com strip interceptor.\r\n *\r\n * bug_6bae8674461f4600809e2f9de13c6043 (HIGH 26/05): fix anterior (2.3.3)\r\n * teve efeito INVERSO. Injetar `pool.types.getTypeParser` fez drizzle-orm\r\n * passar `query.types.getTypeParser` pro pg-mem, que tem guard interno\r\n * `if (query.types?.getTypeParser) throw NotSupported`. Ou seja: presença\r\n * de getTypeParser é o gatilho do erro — não ausência.\r\n *\r\n * Solução A (pglite, preferida): `@electric-sql/pglite` é WASM-Postgres\r\n * nativo — sem adapter pg-mem, sem esse conflito de tipos.\r\n * Solução B (fallback pg-mem): strip interceptor no pool.query que deleta\r\n * `types.getTypeParser` do objeto de query ANTES do pg-mem ver. Compat com\r\n * consumers que só têm pg-mem nas devDeps.\r\n *\r\n * Use `options.initSql` pra rodar DDL no setup (CREATE TABLE etc).\r\n */\r\n async sql<TSchema extends Record<string, unknown>>(\r\n schema: TSchema,\r\n options?: { database?: string; initSql?: string | string[] },\r\n ): Promise<NeetruSqlClient<TSchema>> {\r\n const ddls = options?.initSql\r\n ? Array.isArray(options.initSql) ? options.initSql : [options.initSql]\r\n : [];\r\n\r\n // ── Solução A: pglite (preferida) ────────────────────────────────────────\r\n // PGlite é WASM-Postgres nativo — sem adapter pg-mem, sem o conflito de\r\n // tipos (pg-mem rejeita queries com getTypeParser presente; pglite não tem\r\n // esse guard).\r\n try {\r\n // bug_168368ae: webpackIgnore obrigatório — peerDeps optional server-only.\r\n const pglitePkg = await import(/* webpackIgnore: true */ '@electric-sql/pglite');\r\n const drizzlePglitePkg = await import(/* webpackIgnore: true */ 'drizzle-orm/pglite');\r\n\r\n // PGlite.create() retorna instância já pronta (waitReady resolvido).\r\n const pglite = await pglitePkg.PGlite.create();\r\n\r\n for (const ddl of ddls) {\r\n await pglite.query(ddl);\r\n }\r\n\r\n const pgliteOrm = drizzlePglitePkg.drizzle(pglite, { schema });\r\n\r\n // NeetruSqlClient.orm é tipado como NodePgDatabase — pglite e node-postgres\r\n // implementam a mesma superfície Drizzle mas com tipos de resultado internos\r\n // distintos (Results vs QueryResult). Cast via unknown necessário.\r\n const ormAsNode = pgliteOrm as unknown as import('drizzle-orm/node-postgres').NodePgDatabase<TSchema>;\r\n\r\n return {\r\n orm: ormAsNode,\r\n async transaction(fn, _opts) {\r\n return await pgliteOrm.transaction(fn as never) as never;\r\n },\r\n async close() {\r\n if (!pglite.closed) await pglite.close();\r\n },\r\n };\r\n } catch (_pgliteErr) {\r\n // Pglite indisponível (não instalado ou WASM falhou) — cai no pg-mem.\r\n }\r\n\r\n // ── Solução B: pg-mem + strip interceptor (fallback) ─────────────────────\r\n let pgMemMod: typeof import('pg-mem');\r\n let drizzlePg: typeof import('drizzle-orm/node-postgres');\r\n try {\r\n // bug_168368ae: webpackIgnore obrigatório.\r\n pgMemMod = await import(/* webpackIgnore: true */ 'pg-mem');\r\n drizzlePg = await import(/* webpackIgnore: true */ 'drizzle-orm/node-postgres');\r\n } catch {\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n '[MockDb] sql() requer @electric-sql/pglite OU pg-mem + drizzle-orm + pg como devDependencies. ' +\r\n 'Preferido: npm install -D @electric-sql/pglite drizzle-orm. ' +\r\n 'Alternativo: npm install -D pg-mem drizzle-orm pg.',\r\n );\r\n }\r\n\r\n const memDb = pgMemMod.newDb({ noAstCoverageCheck: true });\r\n\r\n if (ddls.length > 0) {\r\n for (const ddl of ddls) {\r\n memDb.public.none(ddl);\r\n }\r\n }\r\n\r\n const adapters = memDb.adapters.createPg();\r\n const PoolCtor = (adapters as { Pool: new () => unknown }).Pool;\r\n const pool = new PoolCtor() as Record<string, unknown>;\r\n\r\n // bug_6bae8674 strip interceptor: pg-mem rejeita queries que TÊM\r\n // `query.types.getTypeParser` presente (guard interno NotSupported).\r\n // drizzle-orm/node-postgres/session.js injeta `rawQuery.types = pool.types`\r\n // em toda query. Ao interceptar pool.query e deletar getTypeParser do objeto\r\n // de query antes de passar pro pg-mem, o guard não dispara.\r\n // NÃO adicionar getTypeParser ao pool.types (fix 2.3.3 causou efeito inverso).\r\n const origQuery = (pool as { query: (...a: unknown[]) => unknown }).query.bind(pool);\r\n (pool as { query: (...a: unknown[]) => unknown }).query = (q: unknown, ...rest: unknown[]) => {\r\n if (q !== null && typeof q === 'object') {\r\n const queryObj = q as Record<string, unknown>;\r\n const types = queryObj['types'];\r\n if (types !== null && typeof types === 'object' && 'getTypeParser' in (types as object)) {\r\n delete (types as Record<string, unknown>)['getTypeParser'];\r\n }\r\n }\r\n return origQuery(q, ...rest);\r\n };\r\n\r\n const orm = drizzlePg.drizzle(pool as never, { schema }) as unknown as\r\n import('drizzle-orm/node-postgres').NodePgDatabase<TSchema>;\r\n\r\n return {\r\n orm,\r\n async transaction(fn, _opts) {\r\n return await orm.transaction(fn as never) as never;\r\n },\r\n async close() {\r\n const p = pool as { end?: () => Promise<void> };\r\n if (p.end) await p.end();\r\n },\r\n };\r\n }\r\n\r\n get syncState(): SyncState {\r\n return {\r\n status: 'idle',\r\n pendingWrites: 0,\r\n lastSyncedAt: null,\r\n isLeaderTab: true,\r\n };\r\n }\r\n\r\n onSyncStateChanged(_cb: (s: SyncState) => void): Unsubscribe {\r\n return () => {};\r\n }\r\n\r\n async flush(): Promise<void> {\r\n // no-op in mock\r\n }\r\n\r\n async clearCache(): Promise<void> {\r\n this._store.clear();\r\n }\r\n\r\n async getConflicts(): Promise<ConflictRecord[]> {\r\n return [];\r\n }\r\n\r\n /** Test helper — substitui fixture inteira de uma collection. */\r\n __setFixture(name: string, items: Record<string, Record<string, unknown>>): void {\r\n this._store.set(name, new Map(Object.entries(items)));\r\n }\r\n\r\n /** Test helper — reset total. */\r\n __reset(): void {\r\n this._store.clear();\r\n }\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/idempotency.ts","../src/http.ts","../src/db-errors.ts","../src/db/sql/lease.ts","../src/db/sql/sql-client.ts","../src/auth.ts","../src/api-key.ts","../src/base-url-allowlist.ts","../src/types.ts","../src/catalog.ts","../src/entitlements.ts","../src/telemetry.ts","../src/usage.ts","../src/validators.ts","../src/support.ts","../src/db/client-db.ts","../src/db/offline/query-engine.ts","../src/db/offline/local-store.ts","../src/db/offline/memory-store.ts","../src/db/offline/mutation-queue.ts","../src/db/field-value.ts","../src/db/offline/sync-engine.ts","../src/db/offline/conflict-resolver.ts","../src/db/offline/change-bus.ts","../src/db/offline/connectivity-monitor.ts","../src/db/offline/tab-coordinator.ts","../src/db/collection-ref.ts","../src/db/realtime/realtime-client.ts","../src/checkout.ts","../src/webhooks.ts","../src/notifications.ts","../src/mocks.ts"],"names":["err","message","RETRYABLE_CODES","httpRequest","openDB","resolveProductId","VALID_SEVERITIES","validateInput","createRemoteJWKSet","crypto","storage","jwtVerify"],"mappings":"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","file":"auth.cjs","sourcesContent":["/**\n * Erros tipados do SDK.\n *\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\n * por `.code` (string estável) sem parsing de message.\n */\n\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\nexport type NeetruErrorCode =\n | 'invalid_config'\n | 'missing_api_key'\n | 'unauthorized'\n | 'forbidden'\n | 'not_found'\n | 'rate_limited'\n | 'validation_failed'\n | 'network_error'\n | 'invalid_response'\n | 'server_error'\n | 'token_expired'\n | 'token_invalid_signature'\n | 'token_invalid_audience'\n | 'token_invalid_issuer'\n /** 3.0: runtime não expõe API necessária (ex: WebCrypto ausente). */\n | 'runtime_unsupported'\n /**\n * 3.1.3 (bug_c1c96a00): o `state` retornado pelo IdP no callback OIDC não bate com o gerado em\n * `signIn` (CSRF). Também usado quando não há transação OIDC pendente.\n */\n | 'oidc_state_mismatch'\n /** HTTP 409 — colisão de idempotência ou conflito de recurso. */\n | 'conflict'\n | 'unknown';\n\n/**\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\n *\n * @example\n * ```ts\n * try { await client.catalog.list(); }\n * catch (e) {\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\n * }\n * ```\n */\nexport class NeetruError extends Error {\n public readonly code: NeetruErrorCode | string;\n public readonly status?: number;\n public readonly requestId?: string;\n\n constructor(\n code: NeetruErrorCode | string,\n message: string,\n status?: number,\n requestId?: string,\n ) {\n super(message);\n this.name = 'NeetruError';\n this.code = code;\n this.status = status;\n this.requestId = requestId;\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\n Object.setPrototypeOf(this, NeetruError.prototype);\n }\n}\n","/**\n * Idempotency-Key helper — gera UUID v4 cripto-seguro para identificar\n * mutations não-idempotentes (`usage.report`, `support.createTicket`,\n * `notifications.send`, `webhooks.test`).\n *\n * Estratégia 3.0:\n * - SDK gera UUID v4 por chamada via `randomUUID()` (WebCrypto.subtle não\n * necessário aqui — `crypto.randomUUID()` está em Node 14.17+ e em todos\n * os browsers/Edge runtimes modernos).\n * - Header `Idempotency-Key: <uuid>` é injetado pelo `httpRequest` quando\n * `opts.idempotencyKey === true` OU caller passa explicit `opts.idempotencyKeyValue`.\n * - Core dedup em coleção `usage_idempotency_keys/{key}` TTL 24h (vide\n * `docs/CORE_CHANGES_REQUIRED.md` §2). Se Core ainda não dedupa, o header\n * é benign (ignorado).\n *\n * Defesa em camadas: combinado com `retries: 0` em POSTs (vide http.ts), o\n * risco de double-write em transientes vai pra zero.\n */\nimport { NeetruError } from './errors';\n\n/**\n * Gera UUID v4 criptograficamente seguro. Universal: Node 14.17+, browsers\n * modernos, Edge runtimes (Workers/Vercel Edge/Cloudflare).\n *\n * Fallback puro-JS removido em 3.0 — `crypto.randomUUID()` é ubíquo desde\n * 2022. Se runtime não tem, lança `NeetruError('runtime_unsupported')`\n * (consumer deve polyfillar).\n *\n * **L-01 fix (Opus review 2026-05-27):** antes lançava `Error` cru, que\n * não era pego por `catch (err) { if (err instanceof NeetruError) ... }`\n * dos consumers. Agora throw canonical.\n *\n * @throws NeetruError('runtime_unsupported') se `crypto.randomUUID` não disponível.\n */\nexport function generateIdempotencyKey(): string {\n // WebCrypto (browser/Edge) e Node 14.17+ expõem `crypto.randomUUID()`.\n // Node anterior precisa de `node:crypto` mas SDK 3.0 exige Node ≥20 (vide engines).\n const cryptoObj: { randomUUID?: () => string } | undefined =\n typeof globalThis !== 'undefined' && 'crypto' in globalThis\n ? (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n : undefined;\n if (cryptoObj && typeof cryptoObj.randomUUID === 'function') {\n return cryptoObj.randomUUID();\n }\n throw new NeetruError(\n 'runtime_unsupported',\n 'crypto.randomUUID not available in this runtime. SDK 3.0 requires Node ≥20 or modern browser/Edge.',\n );\n}\n\n/** Regex UUID v4 — validação para uso interno. */\nexport const UUID_V4_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\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 const body = (await safeJson(res)) as\r\n | { error?: { code?: string; message?: string } | string }\r\n | undefined;\r\n let code: string = statusToCode(res.status);\r\n let message = `HTTP ${res.status}`;\r\n if (body && typeof body === 'object' && 'error' in body) {\r\n const errField = body.error;\r\n if (typeof errField === 'string') {\r\n message = errField;\r\n } else if (errField && typeof errField === 'object') {\r\n if (typeof errField.code === 'string') code = errField.code;\r\n if (typeof errField.message === 'string') message = errField.message;\r\n }\r\n }\r\n const err = new NeetruError(code, message, res.status, requestId);\r\n lastError = err;\r\n\r\n const isRetryable = RETRYABLE_CODES.has(code as NeetruErrorCode);\r\n if (isRetryable && attempt < maxRetries) {\r\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\r\n const delay = retryAfter ?? backoffMs(attempt);\r\n await sleep(delay);\r\n continue;\r\n }\r\n throw err;\r\n }\r\n\r\n // Unreachable — loop sempre retorna ou lança. Safety net.\r\n throw lastError ?? new NeetruError('unknown', 'unexpected httpRequest exit');\r\n}\r\n","/**\r\n * NeetruDbError — classe de erro especializada para o módulo `db`.\r\n *\r\n * Conforma com 02-sdk.md §3.5: `NeetruDbError extends NeetruError`,\r\n * campo `code` fechado em `NeetruDbErrorCode`, campo `retryable` booleano,\r\n * campo `dbId` opaco para correlação.\r\n *\r\n * Herda de `NeetruError` para que um `catch (e) { if (e instanceof NeetruError) }`\r\n * genérico continue pegando erros de DB. Quem quer granularidade usa\r\n * `instanceof NeetruDbError` e o `code` fechado.\r\n */\r\n\r\nimport { NeetruError } from './errors';\r\n\r\n/**\r\n * Códigos de erro específicos do módulo `db`.\r\n *\r\n * - `db_unavailable` — lifecycle: provisionando / falhou / arquivado.\r\n * NÃO significa \"sem rede\" — offline é transparente.\r\n * - `db_not_found` — documento/coleção não encontrado no servidor.\r\n * - `db_conflict` — conflito de escrita detectado.\r\n * - `db_quota_exceeded` — quota de escrita/leitura excedida no banco.\r\n * - `db_permission_denied` — sem permissão para a operação.\r\n * - `db_invalid_query` — query inválida (campo, operador, tipo).\r\n * - `db_timeout` — operação excedeu o timeout.\r\n * - `offline_quota_exceeded`— IndexedDB cheio; a escrita não pode ser enfileirada.\r\n * - `offline_unavailable` — IndexedDB indisponível; SDK degrado para cache RAM.\r\n */\r\nexport type NeetruDbErrorCode =\r\n | 'db_unavailable'\r\n | 'db_not_found'\r\n | 'db_conflict'\r\n | 'db_quota_exceeded'\r\n | 'db_permission_denied'\r\n | 'db_invalid_query'\r\n | 'db_timeout'\r\n | 'offline_quota_exceeded'\r\n | 'offline_unavailable';\r\n\r\n/**\r\n * Códigos que são retryable por natureza.\r\n */\r\nconst RETRYABLE_CODES = new Set<NeetruDbErrorCode>([\r\n 'db_unavailable',\r\n 'db_conflict',\r\n 'db_timeout',\r\n]);\r\n\r\n/**\r\n * Erro tipado do módulo `db` — estende `NeetruError` para compatibilidade.\r\n *\r\n * @example\r\n * ```ts\r\n * try {\r\n * await client.db.collection('orders').add({ ... });\r\n * } catch (e) {\r\n * if (e instanceof NeetruDbError && e.code === 'offline_quota_exceeded') {\r\n * // IndexedDB cheio — notificar usuário\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport class NeetruDbError extends NeetruError {\r\n /** Código de erro fechado — específico de DB. */\r\n public override readonly code: NeetruDbErrorCode;\r\n\r\n /**\r\n * `true` para erros transientes que o produto pode tentar novamente.\r\n * São retryable: `db_unavailable`, `db_conflict`, `db_timeout`.\r\n */\r\n public readonly retryable: boolean;\r\n\r\n /**\r\n * ID opaco do banco lógico — só para correlação com logs do Core.\r\n * Nunca deve ser exibido ao usuário final.\r\n */\r\n public readonly dbId?: string;\r\n\r\n constructor(code: NeetruDbErrorCode, message: string, dbId?: string) {\r\n super(code, message);\r\n this.name = 'NeetruDbError';\r\n this.code = code;\r\n this.retryable = RETRYABLE_CODES.has(code);\r\n this.dbId = dbId;\r\n // Preserva o prototype chain (TypeScript + downlevel).\r\n Object.setPrototypeOf(this, NeetruDbError.prototype);\r\n }\r\n}\r\n","/**\r\n * SqlLeaseManager — gestão de lease de credencial SQL (M2).\r\n *\r\n * Peça canônica 8 da 00-RELATORIO-CENTRAL.md §6.1:\r\n * - Busca o `DbSqlLease` no startup via `fetchLease()`.\r\n * - Agenda renovação proativa aos ~80% do TTL.\r\n * - Faz hot-swap da credencial: quando o lease renova (ou `credentialVersion`\r\n * muda), o pool antigo drena enquanto o novo aceita conexões.\r\n * - NUNCA loga a senha; NUNCA persiste o lease.\r\n *\r\n * Implementação do hot-swap: pg.Pool não tem API de primeira classe para trocar\r\n * credencial. A estratégia aqui é \"novo pool aceita, velho pool drena\":\r\n * 1. Cria pool novo com o lease renovado.\r\n * 2. Atualiza o ponteiro `_pool` e `_orm` (novos queries vão pro pool novo).\r\n * 3. Chama `end()` no pool antigo (drena gracioso — espera queries em curso).\r\n *\r\n * A janela de dois pools coexistindo é curta (~queries em voo), aceitável e\r\n * esperada (documentada em 02-sdk.md §5 risco 7).\r\n */\r\n\r\nimport { NeetruDbError } from '../../db-errors';\r\nimport type {\r\n DbSqlLease,\r\n SqlClientDeps,\r\n PgPoolLike,\r\n NeetruSqlClient,\r\n} from './types';\r\nimport type { NodePgDatabase } from 'drizzle-orm/node-postgres';\r\n\r\n// ─── Constantes ──────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Proporção do TTL após a qual o lease é renovado proativamente.\r\n *\r\n * 0.80 = renova aos 80% — para um lease de 15 min isso é ~12 min.\r\n * Garante margem antes da expiração real mesmo com latência de rede.\r\n */\r\nconst RENEWAL_THRESHOLD = 0.8;\r\n\r\n/** Tempo mínimo de espera antes de tentar renovar (evita tight-loop). */\r\nconst MIN_RENEWAL_DELAY_MS = 30_000; // 30 s\r\n\r\n// ─── SqlLeaseManager ─────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Implementação interna de `NeetruSqlClient`.\r\n *\r\n * O produto nunca constrói `SqlLeaseManager` diretamente — usa `createSqlClient`\r\n * (a factory pública que faz o primeiro lease + abre o pool).\r\n */\r\nexport class SqlLeaseManager<TSchema extends Record<string, unknown>>\r\n implements NeetruSqlClient<TSchema>\r\n{\r\n private _lease: DbSqlLease;\r\n private _pool: PgPoolLike;\r\n private _orm: NodePgDatabase<TSchema>;\r\n private _renewalTimer: ReturnType<typeof setTimeout> | null = null;\r\n private _closed = false;\r\n\r\n private readonly _deps: Required<Omit<SqlClientDeps<TSchema>, 'database'>> & { database?: string };\r\n\r\n constructor(\r\n lease: DbSqlLease,\r\n pool: PgPoolLike,\r\n orm: NodePgDatabase<TSchema>,\r\n deps: SqlClientDeps<TSchema>,\r\n ) {\r\n this._lease = lease;\r\n this._pool = pool;\r\n this._orm = orm;\r\n // Aplica default de `now` se não fornecido.\r\n this._deps = {\r\n ...deps,\r\n now: deps.now ?? (() => Date.now()),\r\n };\r\n this._scheduleRenewal();\r\n }\r\n\r\n // ─── Superfície pública (NeetruSqlClient) ──────────────────────────────────\r\n\r\n get orm(): NodePgDatabase<TSchema> {\r\n this._assertOpen();\r\n return this._orm;\r\n }\r\n\r\n async transaction<T>(\r\n fn: (tx: NodePgDatabase<TSchema>) => Promise<T>,\r\n opts?: {\r\n isolationLevel?: 'read committed' | 'repeatable read' | 'serializable';\r\n },\r\n ): Promise<T> {\r\n this._assertOpen();\r\n try {\r\n if (opts?.isolationLevel) {\r\n return await this._orm.transaction(fn, {\r\n isolationLevel: opts.isolationLevel,\r\n });\r\n }\r\n return await this._orm.transaction(fn);\r\n } catch (err) {\r\n throw mapPoolError(err);\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n if (this._closed) return;\r\n this._closed = true;\r\n this._cancelRenewal();\r\n await this._pool.end().catch(() => {\r\n // Melhor esforço — não relança no shutdown.\r\n });\r\n }\r\n\r\n // ─── Renovação proativa ────────────────────────────────────────────────────\r\n\r\n /**\r\n * Calcula o delay de renovação: momento de ~80% do TTL restante.\r\n *\r\n * Fórmula: `renewAt = issuedAt + TTL * RENEWAL_THRESHOLD`\r\n * = `expiresAt - TTL * (1 - RENEWAL_THRESHOLD)`\r\n *\r\n * Se o lease já está além do ponto de renovação (ou TTL não calculável),\r\n * usa `MIN_RENEWAL_DELAY_MS` como fallback seguro.\r\n */\r\n _calcRenewalDelayMs(): number {\r\n const expiresAtMs = Date.parse(this._lease.expiresAt);\r\n if (!Number.isFinite(expiresAtMs)) return MIN_RENEWAL_DELAY_MS;\r\n\r\n const now = this._deps.now();\r\n const remainingMs = expiresAtMs - now;\r\n if (remainingMs <= 0) return MIN_RENEWAL_DELAY_MS;\r\n\r\n // Renova quando restar (1 - RENEWAL_THRESHOLD) do TTL.\r\n // Ex: 15 min de TTL total → renova quando restar 3 min.\r\n const renewInMs = remainingMs * (1 - RENEWAL_THRESHOLD);\r\n return Math.max(MIN_RENEWAL_DELAY_MS, Math.round(renewInMs));\r\n }\r\n\r\n _scheduleRenewal(): void {\r\n if (this._closed) return;\r\n const delayMs = this._calcRenewalDelayMs();\r\n this._renewalTimer = setTimeout(() => {\r\n void this._doRenew();\r\n }, delayMs);\r\n }\r\n\r\n _cancelRenewal(): void {\r\n if (this._renewalTimer !== null) {\r\n clearTimeout(this._renewalTimer);\r\n this._renewalTimer = null;\r\n }\r\n }\r\n\r\n async _doRenew(): Promise<void> {\r\n if (this._closed) return;\r\n try {\r\n const renewOpts: import('./types').LeaseFetchOptions = {\r\n leaseId: this._lease.leaseId,\r\n };\r\n // Propaga o database original (contrato C-H) na renovação.\r\n if (this._deps.database !== undefined) {\r\n renewOpts.database = this._deps.database;\r\n }\r\n const newLease = await this._deps.fetchLease(renewOpts);\r\n await this._swapPool(newLease);\r\n } catch (err) {\r\n // Renovação falhou — reagenda com delay mínimo e tenta de novo.\r\n // O pool atual ainda funciona enquanto o lease não expirou.\r\n // Ignora silenciosamente (melhor esforço) e reagenda.\r\n this._renewalTimer = setTimeout(() => {\r\n void this._doRenew();\r\n }, MIN_RENEWAL_DELAY_MS);\r\n // Registra no console apenas em dev para diagnóstico; produção é silenciosa.\r\n if (process.env['NODE_ENV'] !== 'production') {\r\n // eslint-disable-next-line no-console\r\n console.warn('[SqlLeaseManager] Lease renewal failed, will retry:', err);\r\n }\r\n return;\r\n }\r\n this._scheduleRenewal();\r\n }\r\n\r\n /**\r\n * Hot-swap do pool: cria pool novo, atualiza ponteiros, drena pool antigo.\r\n *\r\n * Exposto como método protegido para testes.\r\n */\r\n async _swapPool(newLease: DbSqlLease): Promise<void> {\r\n const credRotated =\r\n newLease.credentialVersion !== this._lease.credentialVersion;\r\n\r\n // Se a versão não mudou e o lease é o mesmo, nada a fazer além de\r\n // atualizar `expiresAt`.\r\n if (!credRotated && newLease.leaseId === this._lease.leaseId) {\r\n this._lease = newLease;\r\n return;\r\n }\r\n\r\n // Cria novo pool + handle Drizzle antes de desconectar o antigo.\r\n const newPool = this._deps.createPool(newLease);\r\n const newOrm = this._deps.createDrizzle(newPool, this._deps.schema);\r\n\r\n const oldPool = this._pool;\r\n\r\n // Atualiza ponteiros — queries novas vão pro pool novo.\r\n this._lease = newLease;\r\n this._pool = newPool;\r\n this._orm = newOrm;\r\n\r\n // Drena o pool antigo graciosamente (não bloqueia o caller).\r\n void oldPool.end().catch(() => {\r\n /* best-effort */\r\n });\r\n }\r\n\r\n // ─── Helpers ───────────────────────────────────────────────────────────────\r\n\r\n private _assertOpen(): void {\r\n if (this._closed) {\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n 'SqlLeaseManager foi fechado — chame close() apenas no shutdown.',\r\n );\r\n }\r\n }\r\n}\r\n\r\n// ─── Mapeamento de erros de pool ─────────────────────────────────────────────\r\n\r\n/**\r\n * Mapeia erros de `pg` / PgBouncer / timeout para `NeetruDbError` canônico.\r\n *\r\n * Erros desconhecidos são relançados como `db_unavailable` (retryable).\r\n */\r\nexport function mapPoolError(err: unknown): NeetruDbError {\r\n if (err instanceof NeetruDbError) return err;\r\n\r\n const message = err instanceof Error ? err.message : String(err);\r\n const code = err instanceof Error ? (err as NodeJS.ErrnoException).code : undefined;\r\n\r\n // ECONNREFUSED / ENOTFOUND / ETIMEDOUT — pool não conseguiu conectar.\r\n if (\r\n typeof code === 'string' &&\r\n (code === 'ECONNREFUSED' || code === 'ENOTFOUND' || code === 'ETIMEDOUT')\r\n ) {\r\n return new NeetruDbError(\r\n 'db_unavailable',\r\n `Pool connection failed (${code}): ${message}`,\r\n );\r\n }\r\n\r\n // Timeout de query Postgres (statement_timeout / lock_timeout).\r\n if (message.includes('statement timeout') || message.includes('lock timeout')) {\r\n return new NeetruDbError('db_timeout', `Query timeout: ${message}`);\r\n }\r\n\r\n // Serialization failure / deadlock (código Postgres 40001 / 40P01).\r\n if (message.includes('40001') || message.includes('40P01') || message.includes('deadlock')) {\r\n return new NeetruDbError('db_conflict', `Transaction conflict: ${message}`);\r\n }\r\n\r\n // Permission denied (Postgres 42501).\r\n if (message.includes('42501') || message.toLowerCase().includes('permission denied')) {\r\n return new NeetruDbError('db_permission_denied', `Permission denied: ${message}`);\r\n }\r\n\r\n // Fallback — genérico db_unavailable (retryable).\r\n return new NeetruDbError('db_unavailable', `Database error: ${message}`);\r\n}\r\n","/**\r\n * `createSqlClient` — factory pública do Mundo SQL.\r\n *\r\n * É a implementação de `client.db.sql(schema)` (02-sdk.md §3.3):\r\n * 1. Busca o lease inicial no Core (`POST /api/sdk/v1/db/lease`).\r\n * 2. Abre um `pg.Pool` com as credenciais do lease.\r\n * 3. Cria o handle Drizzle (`drizzle-orm/node-postgres`).\r\n * 4. Instancia o `SqlLeaseManager` que renova o lease proativamente.\r\n *\r\n * Em produção, usar `createSqlClientFromConfig` (que injeta `pg.Pool` real e\r\n * Drizzle real). Para testes, injetar deps fake via `createSqlClientWithDeps`.\r\n */\r\n\r\nimport type { ResolvedConfig } from '../../types';\r\nimport { NeetruDbError } from '../../db-errors';\r\nimport { SqlLeaseManager } from './lease';\r\nimport type {\r\n DbSqlLease,\r\n NeetruSqlClient,\r\n PgPoolLike,\r\n SqlClientDeps,\r\n LeaseFetcher,\r\n SqlOptions,\r\n} from './types';\r\n\r\n// ─── Endpoint do Core ─────────────────────────────────────────────────────────\r\n\r\n/** Endpoint de emissão de lease SQL no Core. */\r\nexport const LEASE_ENDPOINT = '/api/sdk/v1/db/lease';\r\n\r\n/** Endpoint de renovação de lease SQL no Core. */\r\nexport const LEASE_RENEW_ENDPOINT = '/api/sdk/v1/db/lease/renew';\r\n\r\n// ─── Lease fetcher HTTP ───────────────────────────────────────────────────────\r\n\r\n// ─── Mapeamento de env SDK → env Core ────────────────────────────────────────\r\n\r\n/**\r\n * Mapeia o env do SDK (`'dev'|'workspace'|'prod'`) para o enum aceito pelo\r\n * Core (`'dev'|'staging'|'production'`).\r\n *\r\n * O Core usa `z.enum(['dev', 'staging', 'production'])` no LeaseRequestSchema;\r\n * o SDK expõe `'dev'|'workspace'|'prod'` (NeetruEnv). Sem este mapeamento o\r\n * Core retornaria 400 validation_failed para `workspace` e `prod`.\r\n */\r\nfunction mapEnvToCore(sdkEnv: string): 'dev' | 'staging' | 'production' {\r\n if (sdkEnv === 'workspace') return 'staging';\r\n if (sdkEnv === 'prod') return 'production';\r\n return 'dev'; // 'dev' passa direto\r\n}\r\n\r\n/**\r\n * Cria um `LeaseFetcher` que chama o Core via `httpRequest`.\r\n *\r\n * BL-7 fix:\r\n * - Novo lease: envia `{ productId, environment }` (obrigatório pelo Core).\r\n * - Mapeia SDK env (`prod`→`production`, `workspace`→`staging`, `dev`→`dev`).\r\n * - Parseia a resposta desembrulhando `response.lease` (Core retorna\r\n * `{ kind, lease: {...} }`, não campos no topo).\r\n * - Renovação: envia `{ leaseId }` e desembrulha `response.lease`.\r\n *\r\n * Importação dinâmica de `./http` mantém o `pg` fora do bundle de quem não\r\n * usa SQL (tree-shaking é garantido pois `pg` só entra via `createPool`).\r\n */\r\nexport function createHttpLeaseFetcher(config: ResolvedConfig): LeaseFetcher {\r\n return async (opts) => {\r\n // Import dinâmico não disponível em CJS isolatedModules — importamos\r\n // estaticamente mas só quando a factory é chamada (lazy init).\r\n const { httpRequest } = await import('../../http');\r\n\r\n const isRenewal = Boolean(opts?.leaseId);\r\n const path = isRenewal ? LEASE_RENEW_ENDPOINT : LEASE_ENDPOINT;\r\n\r\n // BL-7: monta o body conforme o contrato de CADA rota do Core.\r\n //\r\n // Rota de novo lease (POST /lease): { productId, environment }\r\n // Rota de renovação (POST /lease/renew): { leaseId }\r\n //\r\n // Para novo lease inclui `database` quando fornecido (contrato C-H) como\r\n // campo extra — o Core o aceita via passthrough no `issueLease`.\r\n let body: Record<string, unknown>;\r\n if (isRenewal) {\r\n // Renovação: apenas leaseId\r\n body = { leaseId: opts!.leaseId };\r\n } else {\r\n // Novo lease: obrigatório productId + environment (mapeado)\r\n body = {\r\n productId: config.productId ?? '',\r\n environment: mapEnvToCore(config.env ?? 'prod'),\r\n };\r\n if (opts?.database !== undefined) {\r\n body['database'] = opts.database;\r\n }\r\n }\r\n\r\n let raw: unknown;\r\n try {\r\n raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path,\r\n body,\r\n requireAuth: true,\r\n // Lease fetch é idempotente do ponto de vista de segurança — retries OK.\r\n retries: 2,\r\n });\r\n } catch (err) {\r\n // Mapeia NeetruError → NeetruDbError(db_unavailable).\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n `Falha ao ${isRenewal ? 'renovar' : 'obter'} lease SQL: ${msg}`,\r\n );\r\n }\r\n\r\n return parseLease(raw);\r\n };\r\n}\r\n\r\n/**\r\n * Parseia e valida a resposta do Core como `DbSqlLease`.\r\n *\r\n * BL-7 fix: o Core retorna `{ kind, lease: { leaseId, host, ... } }` — não\r\n * campos no topo. `parseLease` agora desembrulha `response.lease` antes de\r\n * validar os campos obrigatórios.\r\n *\r\n * Lança `NeetruDbError(db_unavailable)` se o shape estiver errado.\r\n */\r\nfunction parseLease(raw: unknown): DbSqlLease {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruDbError('db_unavailable', 'Resposta de lease inválida (não é objeto).');\r\n }\r\n\r\n // BL-7: desembrulha o envelope { kind, lease: {...} }\r\n const envelope = raw as Record<string, unknown>;\r\n const leaseObj = envelope['lease'];\r\n\r\n if (!leaseObj || typeof leaseObj !== 'object') {\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n 'Resposta de lease inválida: campo \"lease\" ausente ou não é objeto. ' +\r\n 'O Core retorna { kind, lease: { leaseId, host, ... } }.',\r\n );\r\n }\r\n\r\n const r = leaseObj as Record<string, unknown>;\r\n\r\n function req<T>(field: string, type: string): T {\r\n if (typeof r[field] !== type) {\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n `Campo obrigatório \"${field}\" ausente ou tipo inválido na resposta de lease.`,\r\n );\r\n }\r\n return r[field] as T;\r\n }\r\n\r\n return {\r\n leaseId: req<string>('leaseId', 'string'),\r\n host: req<string>('host', 'string'),\r\n port: (typeof r['port'] === 'number' ? r['port'] : 5433) as 5433,\r\n dbName: req<string>('dbName', 'string'),\r\n user: req<string>('user', 'string'),\r\n password: req<string>('password', 'string'),\r\n sslca: typeof r['sslca'] === 'string' ? r['sslca'] : null,\r\n clientCert: typeof r['clientCert'] === 'string' ? r['clientCert'] : null,\r\n clientKey: typeof r['clientKey'] === 'string' ? r['clientKey'] : null,\r\n credentialVersion:\r\n typeof r['credentialVersion'] === 'number' ? r['credentialVersion'] : 1,\r\n expiresAt: req<string>('expiresAt', 'string'),\r\n };\r\n}\r\n\r\n// ─── Pool real (produção) ─────────────────────────────────────────────────────\r\n\r\n/**\r\n * Cria um `pg.Pool` real a partir do lease.\r\n *\r\n * - Aponta sempre para a porta 5433 (PgBouncer).\r\n * - `max: 3` — conservador para serverless (Cloud Run).\r\n * - SSL opcional: usa `sslca` quando presente.\r\n */\r\nexport async function createPgPool(lease: DbSqlLease): Promise<PgPoolLike> {\r\n // bug_168368ae (CRITICAL 26/05): webpackIgnore obrigatório aqui também.\r\n // Sem ele, webpack do consumer ainda processa o module ID 'pg' e segue o\r\n // module graph → 'tls/fs not found' no client bundle. `pg` é server-only.\r\n const { Pool } = await import(/* webpackIgnore: true */ 'pg');\r\n\r\n // C-07 (Codex BLOCKER 2026-05-22): Core retorna PEM strings via\r\n // `.toString('pem')` do @peculiar/x509 (formato `-----BEGIN ...-----`).\r\n // Buffer.from(pem, 'base64') silenciosamente SKIPA chars inválidos do\r\n // header/footer e corrompe os bytes. `pg` Pool aceita PEM string direto —\r\n // passa cru.\r\n const ssl: Record<string, unknown> | false =\r\n lease.sslca\r\n ? {\r\n ca: lease.sslca,\r\n cert: lease.clientCert ?? undefined,\r\n key: lease.clientKey ?? undefined,\r\n rejectUnauthorized: true,\r\n }\r\n : false;\r\n\r\n return new Pool({\r\n host: lease.host,\r\n port: lease.port,\r\n database: lease.dbName,\r\n user: lease.user,\r\n password: lease.password,\r\n ssl,\r\n max: 3,\r\n idleTimeoutMillis: 30_000,\r\n connectionTimeoutMillis: 10_000,\r\n });\r\n}\r\n\r\n/**\r\n * Cria o handle Drizzle real.\r\n *\r\n * Import dinâmico de `drizzle-orm/node-postgres` para tree-shaking.\r\n */\r\nexport async function createDrizzleHandle<TSchema extends Record<string, unknown>>(\r\n pool: PgPoolLike,\r\n schema: TSchema,\r\n) {\r\n // bug_168368ae: webpackIgnore obrigatório (idem createPgPool).\r\n const { drizzle } = await import(/* webpackIgnore: true */ 'drizzle-orm/node-postgres');\r\n // `PgPoolLike` é mais estreito que `Pool` do pg — cast necessário.\r\n // Em produção o valor sempre é um `pg.Pool` real.\r\n return drizzle(pool as unknown as import('pg').Pool, { schema });\r\n}\r\n\r\n// ─── Factory principal ────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Cria `NeetruSqlClient` com dependências injetadas explicitamente.\r\n *\r\n * Usado pelos testes e pela factory de produção.\r\n *\r\n * @param deps — dependências injetáveis (fetchLease, createPool, createDrizzle, schema).\r\n * @param options — opções de `client.db.sql(schema, options?)` (contrato C-H).\r\n * `options.database` desambigua quando o produto tem N>1 bancos SQL.\r\n */\r\nexport async function createSqlClientWithDeps<\r\n TSchema extends Record<string, unknown>,\r\n>(\r\n deps: SqlClientDeps<TSchema>,\r\n options?: SqlOptions,\r\n): Promise<NeetruSqlClient<TSchema>> {\r\n // Mescla `database` das options com deps para que o SqlLeaseManager\r\n // propague o valor em todas as renovações de lease (contrato C-H).\r\n const depsWithDb: SqlClientDeps<TSchema> =\r\n options?.database !== undefined\r\n ? { ...deps, database: options.database }\r\n : deps;\r\n\r\n // 1. Busca o lease inicial, incluindo `database` quando fornecido.\r\n // Quando não há `database`, chama fetchLease() sem argumento — compatibilidade\r\n // exata com o comportamento v1.x (o teste verifica chamada sem parâmetros).\r\n let lease: DbSqlLease;\r\n try {\r\n if (options?.database !== undefined) {\r\n lease = await depsWithDb.fetchLease({ database: options.database });\r\n } else {\r\n lease = await depsWithDb.fetchLease();\r\n }\r\n } catch (err) {\r\n if (err instanceof NeetruDbError) throw err;\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new NeetruDbError('db_unavailable', `Falha ao obter lease inicial: ${msg}`);\r\n }\r\n\r\n // 2. Abre o pool.\r\n let pool: PgPoolLike;\r\n try {\r\n pool = depsWithDb.createPool(lease);\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new NeetruDbError('db_unavailable', `Falha ao abrir pool: ${msg}`);\r\n }\r\n\r\n // 3. Cria handle Drizzle.\r\n let orm;\r\n try {\r\n orm = depsWithDb.createDrizzle(pool, depsWithDb.schema);\r\n } catch (err) {\r\n // Pool aberto mas Drizzle falhou — fechar o pool antes de relançar.\r\n await pool.end().catch(() => {});\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new NeetruDbError('db_unavailable', `Falha ao criar handle Drizzle: ${msg}`);\r\n }\r\n\r\n // 4. Instancia o manager (que agenda o timer de renovação).\r\n // Passa `depsWithDb` para que `database` seja propagado nas renovações.\r\n return new SqlLeaseManager(lease, pool, orm, depsWithDb);\r\n}\r\n\r\n/**\r\n * Factory de produção — usa `pg.Pool` real e Drizzle real.\r\n *\r\n * `schema` deve ser o objeto Drizzle do produto (exportado de `db/schema.ts`).\r\n * `options.database` desambigua quando o produto tem N>1 bancos SQL (C-H).\r\n *\r\n * @example\r\n * ```ts\r\n * import { createNeetruClient } from '@neetru/sdk';\r\n * import * as schema from './db/schema';\r\n * const client = createNeetruClient();\r\n * // banco padrão:\r\n * export const db = await client.db.sql(schema);\r\n * // banco específico:\r\n * export const analytics = await client.db.sql(schema, { database: 'analytics' });\r\n * ```\r\n */\r\nexport async function createSqlClientFromConfig<\r\n TSchema extends Record<string, unknown>,\r\n>(\r\n config: ResolvedConfig,\r\n schema: TSchema,\r\n options?: SqlOptions,\r\n): Promise<NeetruSqlClient<TSchema>> {\r\n const fetchLease = createHttpLeaseFetcher(config);\r\n\r\n // bug_0f836014 (CRITICAL 26/05): require('pg') + require('drizzle-orm/node-postgres')\r\n // literais eram inlined pelo tsup no entry index.mjs. Webpack do consumer\r\n // Next.js seguia o module graph e tentava bundle pg → puxa fs → 'Module not\r\n // found: fs' no client bundle. Fix: dynamic import com /* webpackIgnore: true */\r\n // que instrui webpack a NÃO processar (deixa pro runtime Node resolver). sql()\r\n // é server-only por contrato — browser nunca chega aqui em runtime.\r\n let pgMod: typeof import('pg');\r\n let drizzlePgMod: typeof import('drizzle-orm/node-postgres');\r\n try {\r\n pgMod = (await import(/* webpackIgnore: true */ 'pg')) as typeof import('pg');\r\n drizzlePgMod = (await import(/* webpackIgnore: true */ 'drizzle-orm/node-postgres')) as typeof import('drizzle-orm/node-postgres');\r\n } catch (err) {\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n `[client.db.sql] requer pg + drizzle-orm como peerDependencies do servidor. ` +\r\n `Instale: npm install pg drizzle-orm. (${(err as Error).message})`,\r\n );\r\n }\r\n\r\n // Wrappers síncronos — Pool/drizzle já carregados acima via dynamic import.\r\n const createPool = (lease: DbSqlLease): PgPoolLike => {\r\n const Pool =\r\n (pgMod as { Pool?: typeof import('pg').Pool }).Pool ??\r\n ((pgMod as { default?: { Pool?: typeof import('pg').Pool } }).default?.Pool as typeof import('pg').Pool);\r\n\r\n // C-07 (Codex BLOCKER 2026-05-22) — PEM direto.\r\n const ssl: Record<string, unknown> | false =\r\n lease.sslca\r\n ? {\r\n ca: lease.sslca,\r\n cert: lease.clientCert ?? undefined,\r\n key: lease.clientKey ?? undefined,\r\n rejectUnauthorized: true,\r\n }\r\n : false;\r\n\r\n return new Pool({\r\n host: lease.host,\r\n port: lease.port,\r\n database: lease.dbName,\r\n user: lease.user,\r\n password: lease.password,\r\n ssl,\r\n max: 3,\r\n idleTimeoutMillis: 30_000,\r\n connectionTimeoutMillis: 10_000,\r\n });\r\n };\r\n\r\n const createDrizzle = <S extends Record<string, unknown>>(\r\n pool: PgPoolLike,\r\n s: S,\r\n ) => {\r\n // bug_0f836014: usa drizzlePgMod pré-carregado via dynamicImport acima.\r\n return drizzlePgMod.drizzle(pool as unknown as import('pg').Pool, { schema: s });\r\n };\r\n\r\n return createSqlClientWithDeps(\r\n {\r\n fetchLease,\r\n createPool,\r\n createDrizzle: createDrizzle as SqlClientDeps<TSchema>['createDrizzle'],\r\n schema,\r\n },\r\n options,\r\n );\r\n}\r\n","/**\r\n * Factory `createNeetruClient` + namespace `auth` (v0.2).\r\n *\r\n * Responsabilidades:\r\n * - Factory: resolver `apiKey`, `baseUrl`, `fetch`, `env`, e montar handle\r\n * imutável com namespaces (`auth`, `catalog`, `entitlements`, `telemetry`,\r\n * `usage`, `support`).\r\n * - Auth namespace: signIn (OIDC redirect ou mock dev), signOut, getUser,\r\n * onAuthStateChanged.\r\n *\r\n * v0.1 expunha apenas Bearer estático (long-lived `nrt_*_*`). v0.2 adiciona\r\n * camada de auth para SaaS produtos consumirem identity Neetru via OIDC\r\n * (auth.neetru.com já live).\r\n */\r\nimport { jwtVerify, createRemoteJWKSet, type JWTPayload } from 'jose';\r\nimport { NeetruError } from './errors';\r\nimport { parseApiKey, tryParseApiKey } from './api-key';\r\nimport { validateBaseUrl } from './base-url-allowlist';\r\nimport {\r\n DEFAULT_BASE_URL,\r\n type AuthNamespace,\r\n type AuthStateListener,\r\n type NeetruClient,\r\n type NeetruClientConfig,\r\n type NeetruEnv,\r\n type NeetruUser,\r\n type RedirectCallbackResult,\r\n type ResolvedConfig,\r\n type SignInOptions,\r\n type VerifyTokenOptions,\r\n} from './types';\r\nimport { createCatalogNamespace } from './catalog';\r\nimport { createEntitlementsNamespace } from './entitlements';\r\nimport { createTelemetryNamespace } from './telemetry';\r\nimport { createUsageNamespace } from './usage';\r\nimport { createSupportNamespace } from './support';\r\nimport { createNeetruDb } from './db/client-db';\r\nimport { createCheckoutNamespace } from './checkout';\r\nimport { createWebhooksNamespace, MockWebhooks } from './webhooks';\r\nimport { createNotificationsNamespace, MockNotifications } from './notifications';\r\nimport { DEV_FIXTURE_USER, MockAuth, MockUsage, MockSupport, MockEntitlements } from './mocks';\r\n\r\n/**\r\n * Lê `NEETRU_API_KEY` do ambiente Node de forma defensiva. Em browser,\r\n * `process` não existe — try/catch evita ReferenceError. Em Edge runtimes\r\n * que polyfillam `process` parcialmente, optional chaining absorve undefined.\r\n */\r\nfunction readEnvApiKey(): string | undefined {\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const proc = (globalThis as any).process;\r\n const val = proc?.env?.NEETRU_API_KEY;\r\n return typeof val === 'string' && val.length > 0 ? val : undefined;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Resolve `NEETRU_ENV` de várias fontes:\r\n * 1. Config arg `env`.\r\n * 2. `process.env.NEETRU_ENV` em Node.\r\n * 3. `globalThis.NEETRU_ENV` em browser/Edge (se setado por bundler).\r\n * 4. Default `prod`.\r\n */\r\nfunction resolveEnv(configEnv?: NeetruEnv): NeetruEnv {\r\n if (configEnv) return configEnv;\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const proc = (globalThis as any).process;\r\n const val = proc?.env?.NEETRU_ENV;\r\n if (val === 'dev' || val === 'workspace' || val === 'prod') return val;\r\n } catch {\r\n /* ignore */\r\n }\r\n // SECURITY TODO (audit 2026-06-18): globalThis.NEETRU_ENV pode ser influenciado por\r\n // código de terceiros em bundles browser (ex: script injection, prototype pollution).\r\n // Se NEETRU_ENV='dev' for aceito via globalThis em prod, o client ativa MockAuth\r\n // (incluindo MockAuth.verifyToken com allowUnsignedDecode=true) silenciosamente.\r\n // Mitigação segura: honrar globalThis apenas quando process.env não está disponível\r\n // (puro browser), e nunca aceitar 'dev' via globalThis em builds de produção.\r\n // Esta mudança requer alinhamento com bundlers (define plugin) e testes E2E —\r\n // deixada como TODO para não introduzir regressão sem suite de integração full.\r\n // Mitigação atual: MockAuth.verifyToken sem allowUnsignedDecode=true lança\r\n // 'unauthorized', portanto mesmo que env='dev' seja ativado via globalThis,\r\n // verifyToken não aceita tokens não-assinados sem opt-in explícito (Finding 2 fix).\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const g = (globalThis as any).NEETRU_ENV;\r\n if (g === 'dev' || g === 'workspace' || g === 'prod') return g;\r\n } catch {\r\n /* ignore */\r\n }\r\n return 'prod';\r\n}\r\n\r\n// ─── JWKS cache ────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Cache de JWKS por URL. Cada entrada é uma `RemoteJWKSet` retornada por\r\n * `createRemoteJWKSet` (jose) — já faz internal caching e refresh automático\r\n * de chaves. O mapa aqui evita criar múltiplas instâncias pra mesma URL em\r\n * processos com vários clientes.\r\n */\r\nconst _jwksCache = new Map<string, { jwks: ReturnType<typeof createRemoteJWKSet>; createdAt: number }>();\r\n\r\nconst DEFAULT_JWKS_TTL_MS = 60 * 60 * 1000; // 1h\r\n\r\nfunction _getJwks(jwksUrl: string, cacheTtlMs: number): ReturnType<typeof createRemoteJWKSet> {\r\n const now = Date.now();\r\n const cached = _jwksCache.get(jwksUrl);\r\n if (cached && now - cached.createdAt < cacheTtlMs) {\r\n return cached.jwks;\r\n }\r\n const jwks = createRemoteJWKSet(new URL(jwksUrl));\r\n _jwksCache.set(jwksUrl, { jwks, createdAt: now });\r\n return jwks;\r\n}\r\n\r\n/** Limpa o cache de JWKS — uso exclusivo em testes. */\r\nexport function __resetJwksCacheForTests(): void {\r\n _jwksCache.clear();\r\n}\r\n\r\n/** Mapeia claims do JWT pra `NeetruUser`. */\r\nfunction _jwtPayloadToUser(payload: JWTPayload): NeetruUser {\r\n const sub = payload.sub ?? '';\r\n const email = typeof payload.email === 'string' ? payload.email : '';\r\n return {\r\n uid: sub,\r\n email,\r\n emailVerified: typeof payload.email_verified === 'boolean' ? payload.email_verified : undefined,\r\n displayName: typeof payload.name === 'string' ? payload.name : undefined,\r\n photoURL: typeof payload.picture === 'string' ? payload.picture : undefined,\r\n isStaff: payload.is_staff === true,\r\n isCustomer: payload.is_customer === true,\r\n tenantId: typeof payload.tenant_id === 'string' ? payload.tenant_id : undefined,\r\n // Spreads todos os claims originais (aud, iss, iat, exp, etc).\r\n ...payload,\r\n };\r\n}\r\n\r\n// ─── PKCE / OIDC redirect helpers (3.1.3) ────────────────────────────────────\r\n\r\n/** Chave da transação OIDC pendente em `sessionStorage` (state + nonce + PKCE). */\r\nconst OIDC_TX_KEY = 'neetru_oauth_tx';\r\n\r\n/** Transação de um `signIn` em voo, retomada em `handleRedirectCallback`. */\r\ninterface OidcTransaction {\r\n state: string;\r\n nonce: string;\r\n codeVerifier: string;\r\n redirectUri: string;\r\n postLoginRedirect?: string;\r\n}\r\n\r\n/**\r\n * Deriva o origin do IdP (`auth.neetru.com`) a partir do `baseUrl` (api.* →\r\n * auth.*). Override por `globalThis.NEETRU_AUTH_URL` (testes / staging).\r\n */\r\nfunction resolveIdpOrigin(baseUrl: string): string {\r\n const overrideAuthUrl =\r\n typeof (globalThis as { NEETRU_AUTH_URL?: string }).NEETRU_AUTH_URL === 'string'\r\n ? (globalThis as { NEETRU_AUTH_URL?: string }).NEETRU_AUTH_URL\r\n : null;\r\n return overrideAuthUrl ?? baseUrl.replace(/^https?:\\/\\/api\\./, 'https://auth.');\r\n}\r\n\r\n/**\r\n * Acessa WebCrypto de forma defensiva. O fluxo PKCE exige `getRandomValues` +\r\n * `subtle.digest`. Em runtimes sem WebCrypto (http inseguro, browser muito\r\n * antigo) lança `runtime_unsupported` em vez de gerar PKCE fraco.\r\n */\r\nfunction getWebCrypto(): Crypto {\r\n const c = (globalThis as { crypto?: Crypto }).crypto;\r\n if (!c || typeof c.getRandomValues !== 'function' || !c.subtle) {\r\n throw new NeetruError(\r\n 'runtime_unsupported',\r\n 'auth.signIn requer WebCrypto (crypto.subtle) — indisponível neste runtime. Use HTTPS (ou http://localhost) num browser moderno.',\r\n );\r\n }\r\n return c;\r\n}\r\n\r\n/** Codifica bytes em base64url sem padding (browser/Node compat). */\r\nfunction base64UrlFromBytes(bytes: Uint8Array): string {\r\n let str = '';\r\n for (const b of bytes) str += String.fromCharCode(b);\r\n const b64 =\r\n typeof btoa === 'function' ? btoa(str) : Buffer.from(str, 'binary').toString('base64');\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\r\n}\r\n\r\n/** Token URL-safe aleatório de `byteLen` bytes (base64url). 32 bytes → 43 chars. */\r\nfunction randomUrlSafe(crypto: Crypto, byteLen: number): string {\r\n const bytes = new Uint8Array(byteLen);\r\n crypto.getRandomValues(bytes);\r\n return base64UrlFromBytes(bytes);\r\n}\r\n\r\n/** PKCE S256 (RFC 7636 §4.2): `base64url(sha256(code_verifier))`. */\r\nasync function pkceChallengeS256(crypto: Crypto, verifier: string): Promise<string> {\r\n const data = new TextEncoder().encode(verifier);\r\n const digest = await crypto.subtle.digest('SHA-256', data);\r\n return base64UrlFromBytes(new Uint8Array(digest));\r\n}\r\n\r\n/**\r\n * Remove os params do callback OIDC (`code`, `state`, `error`, ...) da URL via\r\n * `history.replaceState`, sem recarregar a página nem deixar o code no histórico.\r\n * Best-effort: no-op se `history` indisponível.\r\n */\r\nfunction cleanCallbackUrl(parsed: URL): void {\r\n try {\r\n const history = (globalThis as { history?: History }).history;\r\n if (!history || typeof history.replaceState !== 'function') return;\r\n const clean = new URL(parsed.toString());\r\n for (const p of ['code', 'state', 'error', 'error_description', 'iss', 'session_state']) {\r\n clean.searchParams.delete(p);\r\n }\r\n history.replaceState(history.state ?? null, '', clean.pathname + clean.search + clean.hash);\r\n } catch {\r\n /* best-effort — não falha o callback se history estiver indisponível */\r\n }\r\n}\r\n\r\n// ─── Real OIDC auth namespace ──────────────────────────────────────────────\r\n\r\n/**\r\n * Implementação real do namespace auth — redireciona pra auth.neetru.com\r\n * em signIn, lê id_token do localStorage (se browser) ou do env em Node.\r\n *\r\n * Storage key: `neetru_id_token`. JWT decoded inline (sem verifyJWT — backend\r\n * já validou; SDK só lê claims pra populate getUser).\r\n */\r\nfunction createOidcAuthNamespace(config: ResolvedConfig): AuthNamespace {\r\n const STORAGE_KEY = 'neetru_id_token';\r\n const listeners = new Set<AuthStateListener>();\r\n let cachedUser: NeetruUser | null = null;\r\n // Bug fix: timer pra notificar listeners quando o token expira proativamente.\r\n // Sem isso, componentes com `onAuthStateChanged` ficam com `user` stale até\r\n // a próxima chamada de `getUser()`. Timer cancelado no signOut.\r\n let _expiryTimerId: ReturnType<typeof setTimeout> | null = null;\r\n\r\n function getStorage(): Storage | null {\r\n try {\r\n return typeof globalThis.localStorage !== 'undefined' ? globalThis.localStorage : null;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /** sessionStorage pra transação OIDC em voo (PKCE verifier + state + nonce). */\r\n function getSessionStorage(): Storage | null {\r\n try {\r\n return typeof globalThis.sessionStorage !== 'undefined' ? globalThis.sessionStorage : null;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n function decodeJwtPayload(token: string): Record<string, unknown> | null {\r\n const parts = token.split('.');\r\n if (parts.length !== 3) return null;\r\n try {\r\n // base64url decode (browser/Node compat).\r\n const b64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');\r\n const pad = '='.repeat((4 - (b64.length % 4)) % 4);\r\n const decoded =\r\n typeof atob === 'function'\r\n ? atob(b64 + pad)\r\n : Buffer.from(b64 + pad, 'base64').toString('utf-8');\r\n return JSON.parse(decoded);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n function tokenToUser(token: string): NeetruUser | null {\r\n const payload = decodeJwtPayload(token);\r\n if (!payload || typeof payload.sub !== 'string') return null;\r\n // BUG fix: valida expiração do JWT antes de retornar usuário.\r\n // `exp` é timestamp Unix em segundos; multiplicamos por 1000 pra comparar\r\n // com Date.now() (ms). Token expirado → null, independente do cache.\r\n if (typeof payload.exp === 'number' && payload.exp * 1000 < Date.now()) {\r\n return null;\r\n }\r\n return {\r\n uid: payload.sub,\r\n email: typeof payload.email === 'string' ? payload.email : '',\r\n emailVerified: typeof payload.email_verified === 'boolean' ? payload.email_verified : undefined,\r\n displayName: typeof payload.name === 'string' ? payload.name : undefined,\r\n photoURL: typeof payload.picture === 'string' ? payload.picture : undefined,\r\n isStaff: payload.is_staff === true,\r\n isCustomer: payload.is_customer === true,\r\n tenantId: typeof payload.tenant_id === 'string' ? payload.tenant_id : undefined,\r\n ...payload,\r\n };\r\n }\r\n\r\n function loadCachedUser(): NeetruUser | null {\r\n // Re-valida cachedUser — pode ter expirado entre chamadas sem reload de página.\r\n // `tokenToUser` já verifica `exp`; ao reler do storage verificamos novamente.\r\n if (cachedUser) {\r\n // `tokenToUser` faz o spread de payload, então `exp` está em cachedUser.\r\n // Verifica expiração diretamente no objeto cached (campo exp é timestamp Unix s).\r\n const exp = (cachedUser as unknown as Record<string, unknown>).exp;\r\n if (typeof exp === 'number' && exp * 1000 < Date.now()) {\r\n // Token expirado — limpa cache e storage.\r\n cachedUser = null;\r\n const storage = getStorage();\r\n storage?.removeItem(STORAGE_KEY);\r\n notify();\r\n return null;\r\n }\r\n return cachedUser;\r\n }\r\n const storage = getStorage();\r\n if (!storage) return null;\r\n const token = storage.getItem(STORAGE_KEY);\r\n if (!token) return null;\r\n const user = tokenToUser(token);\r\n if (!user) {\r\n // Token inválido ou expirado — remove do storage.\r\n storage.removeItem(STORAGE_KEY);\r\n return null;\r\n }\r\n cachedUser = user;\r\n // Agenda notificação proativa de expiração pra listeners não ficarem stale.\r\n scheduleExpiryTimer(user);\r\n return cachedUser;\r\n }\r\n\r\n function notify(): void {\r\n for (const l of listeners) {\r\n try {\r\n l(cachedUser);\r\n } catch {\r\n /* ignore consumer errors */\r\n }\r\n }\r\n }\r\n\r\n /** Cancela o timer de expiração pendente, se houver. */\r\n function cancelExpiryTimer(): void {\r\n if (_expiryTimerId !== null) {\r\n clearTimeout(_expiryTimerId);\r\n _expiryTimerId = null;\r\n }\r\n }\r\n\r\n /**\r\n * Agenda um timer para notificar listeners quando o token expirar.\r\n * Chama `loadCachedUser()` no vencimento, que já limpa cache + chama `notify()`.\r\n * Se `exp` for inválido ou já expirado, não agenda.\r\n */\r\n function scheduleExpiryTimer(user: NeetruUser): void {\r\n cancelExpiryTimer();\r\n const exp = (user as unknown as Record<string, unknown>).exp;\r\n if (typeof exp !== 'number') return;\r\n const msUntilExpiry = exp * 1000 - Date.now();\r\n if (msUntilExpiry <= 0) return; // já expirado — não agendar\r\n // +1ms garante que Date.now() esteja estritamente após exp*1000 quando\r\n // o callback rodar (evita race condition com igualdade exata de ms).\r\n _expiryTimerId = setTimeout(() => {\r\n _expiryTimerId = null;\r\n loadCachedUser(); // detecta expiração, limpa cache e chama notify()\r\n }, msUntilExpiry + 1);\r\n }\r\n\r\n return {\r\n async signIn(options?: SignInOptions): Promise<NeetruUser | void> {\r\n // Em browser, redireciona pro authorize endpoint do IdP (auth.neetru.com).\r\n // Fix audit 2026-05-15: antes apontava `api.neetru.com/oauth/authorize`\r\n // (404 — middleware só roteia /api/v1/oauth a partir de auth.neetru.com).\r\n // O issuer canônico é `auth.neetru.com` (vide PLATFORM_IDENTIDADE.md).\r\n if (typeof globalThis.location !== 'undefined' && typeof globalThis.location.assign === 'function') {\r\n // Bug 2 (bug_c1c96a00): o /authorize do Core EXIGE `nonce` + `state` e\r\n // valida PKCE. Antes mandávamos só response_type/redirect/scope/state(=href)\r\n // → 302 de volta com `invalid_request: nonce is required` (fluxo quebrado\r\n // ponta-a-ponta). Agora geramos state CSRF aleatório, nonce e o par PKCE\r\n // S256, e guardamos a transação pra retomar no callback.\r\n const crypto = getWebCrypto();\r\n const redirectUri = options?.redirectUri ?? globalThis.location.origin;\r\n const scope = options?.scope ?? 'openid profile email';\r\n\r\n // client_id: prefere o oidcClientId (oidc_clients/{id}, par id+segredo do\r\n // produto). Cai no keyId da apiKey por compat — mas o Core só reconhece um\r\n // oidc_clients válido, então oidcClientId é o caminho correto em produção.\r\n let clientId = config.oidcClientId;\r\n if (!clientId && config.apiKey) {\r\n // H-02 fix: parse seguro (throws se malformado) — nunca vaza a apiKey\r\n // inteira como client_id.\r\n clientId = parseApiKey(config.apiKey).keyId;\r\n }\r\n if (!clientId) {\r\n throw new NeetruError(\r\n 'invalid_config',\r\n 'auth.signIn requer `oidcClientId` (ou `apiKey`) configurado para montar o client_id.',\r\n );\r\n }\r\n\r\n const state = randomUrlSafe(crypto, 16);\r\n const nonce = randomUrlSafe(crypto, 16);\r\n // RFC 7636 §4.1: verifier 43..128 chars. 32 bytes → 43 chars base64url.\r\n const codeVerifier = randomUrlSafe(crypto, 32);\r\n const codeChallenge = await pkceChallengeS256(crypto, codeVerifier);\r\n\r\n // Persiste a transação ANTES do redirect (sobrevive ao round-trip same-tab).\r\n const session = getSessionStorage();\r\n if (!session) {\r\n throw new NeetruError(\r\n 'runtime_unsupported',\r\n 'auth.signIn requer sessionStorage para guardar a transação PKCE entre o redirect e o callback.',\r\n );\r\n }\r\n const tx: OidcTransaction = {\r\n state,\r\n nonce,\r\n codeVerifier,\r\n redirectUri,\r\n postLoginRedirect: options?.postLoginRedirect,\r\n };\r\n session.setItem(OIDC_TX_KEY, JSON.stringify(tx));\r\n\r\n const idpOrigin = resolveIdpOrigin(config.baseUrl);\r\n const url = new URL('/api/v1/oauth/authorize', idpOrigin);\r\n url.searchParams.set('response_type', 'code');\r\n url.searchParams.set('client_id', clientId);\r\n url.searchParams.set('redirect_uri', redirectUri);\r\n url.searchParams.set('scope', scope);\r\n url.searchParams.set('state', state);\r\n url.searchParams.set('nonce', nonce);\r\n url.searchParams.set('code_challenge', codeChallenge);\r\n url.searchParams.set('code_challenge_method', 'S256');\r\n globalThis.location.assign(url.toString());\r\n return;\r\n }\r\n // Não-browser sem mock — não dá pra signIn interativo.\r\n throw new NeetruError(\r\n 'invalid_config',\r\n 'auth.signIn requires a browser context or mocks. Use NEETRU_ENV=dev or pass mocks.auth.',\r\n );\r\n },\r\n\r\n async handleRedirectCallback(currentUrl?: string): Promise<RedirectCallbackResult | null> {\r\n const href =\r\n currentUrl ??\r\n (typeof globalThis.location !== 'undefined' ? globalThis.location.href : undefined);\r\n if (!href) return null;\r\n let parsed: URL;\r\n try {\r\n parsed = new URL(href);\r\n } catch {\r\n return null;\r\n }\r\n const params = parsed.searchParams;\r\n\r\n // IdP devolveu erro (ex: access_denied, invalid_scope) — propaga com o\r\n // próprio código de erro do OAuth e limpa a transação pendente.\r\n const idpError = params.get('error');\r\n if (idpError) {\r\n const desc = params.get('error_description') ?? idpError;\r\n getSessionStorage()?.removeItem(OIDC_TX_KEY);\r\n cleanCallbackUrl(parsed);\r\n throw new NeetruError(idpError, `OIDC authorize falhou: ${desc}`);\r\n }\r\n\r\n const code = params.get('code');\r\n if (!code) return null; // não é um callback OIDC — nada a fazer\r\n\r\n const returnedState = params.get('state');\r\n const session = getSessionStorage();\r\n const txRaw = session?.getItem(OIDC_TX_KEY) ?? null;\r\n let tx: OidcTransaction | null = null;\r\n if (txRaw) {\r\n try {\r\n tx = JSON.parse(txRaw) as OidcTransaction;\r\n } catch {\r\n tx = null;\r\n }\r\n }\r\n\r\n if (!tx) {\r\n throw new NeetruError(\r\n 'oidc_state_mismatch',\r\n 'Callback OIDC sem transação pendente — `signIn` não foi iniciado nesta sessão (ou já consumido).',\r\n );\r\n }\r\n // CSRF: o state retornado precisa bater com o gerado no signIn.\r\n if (!returnedState || returnedState !== tx.state) {\r\n session?.removeItem(OIDC_TX_KEY);\r\n cleanCallbackUrl(parsed);\r\n throw new NeetruError(\r\n 'oidc_state_mismatch',\r\n 'state do callback OIDC não confere com o da transação (possível CSRF).',\r\n );\r\n }\r\n\r\n // Sucesso: consome a transação (single-use) e tira os params da URL.\r\n session?.removeItem(OIDC_TX_KEY);\r\n cleanCallbackUrl(parsed);\r\n\r\n return {\r\n code,\r\n codeVerifier: tx.codeVerifier,\r\n redirectUri: tx.redirectUri,\r\n nonce: tx.nonce,\r\n state: tx.state,\r\n postLoginRedirect: tx.postLoginRedirect,\r\n };\r\n },\r\n\r\n getIdToken(): string | null {\r\n const storage = getStorage();\r\n const token = storage?.getItem(STORAGE_KEY) ?? null;\r\n if (!token) return null;\r\n // Não devolve token expirado/malformado — o BFF rejeitaria de qualquer forma.\r\n // `tokenToUser` retorna null se exp no passado ou payload inválido.\r\n return tokenToUser(token) ? token : null;\r\n },\r\n\r\n async signOut(): Promise<void> {\r\n // BUG fix (RFC 7009): lê o token ANTES de remover do storage para incluir\r\n // no corpo do POST de revoke. Sem o token, o servidor não tem como\r\n // identificar qual sessão invalidar — refresh token permaneceria válido.\r\n const storage = getStorage();\r\n const storedToken = storage?.getItem(STORAGE_KEY) ?? null;\r\n if (storage) storage.removeItem(STORAGE_KEY);\r\n cancelExpiryTimer(); // cancela timer de expiração pendente ao fazer logout\r\n cachedUser = null;\r\n // Best-effort revoke no server. O endpoint canônico é\r\n // auth.neetru.com/api/v1/oauth/revoke (não api.neetru.com). Aplica a\r\n // mesma derivação api.* → auth.* usada no signIn().\r\n //\r\n // L-02 fix (Opus review): retry 1× com backoff 500ms em falha network.\r\n // Refresh token continua válido se ambas tentativas falharem — caller\r\n // deve assumir que pode ter sessão server-side stale e re-autenticar.\r\n const overrideAuthUrl =\r\n typeof (globalThis as { NEETRU_AUTH_URL?: string }).NEETRU_AUTH_URL === 'string'\r\n ? (globalThis as { NEETRU_AUTH_URL?: string }).NEETRU_AUTH_URL\r\n : null;\r\n const idpOrigin =\r\n overrideAuthUrl ?? config.baseUrl.replace(/^https?:\\/\\/api\\./, 'https://auth.');\r\n const revokeUrl = `${idpOrigin}/api/v1/oauth/revoke`;\r\n // RFC 7009 §2.1: inclui `token` no corpo sem `token_type_hint`.\r\n // Bug fix: o token em storage é um id_token OIDC — usar hint 'access_token'\r\n // faz servidores que roteiam por tipo não encontrarem a sessão e ignorarem\r\n // a revogação. Sem hint o servidor tenta todos os tipos (RFC 7009 §2.1 §4.1.2).\r\n // Se não há token armazenado (ex: signIn em Node sem storage), pula o revoke.\r\n const revokeBody = storedToken\r\n ? JSON.stringify({ token: storedToken })\r\n : null;\r\n let revokeError: unknown = null;\r\n for (let attempt = 0; attempt < 2; attempt++) {\r\n try {\r\n if (revokeBody) {\r\n await config.fetch(revokeUrl, {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n body: revokeBody,\r\n });\r\n }\r\n revokeError = null;\r\n break;\r\n } catch (err) {\r\n revokeError = err;\r\n if (attempt === 0) {\r\n // Backoff 500ms antes do retry final.\r\n await new Promise((resolve) => setTimeout(resolve, 500));\r\n }\r\n }\r\n }\r\n if (revokeError && typeof console !== 'undefined') {\r\n console.warn(\r\n '[neetru-sdk] signOut: server-side revoke falhou (2 tentativas). Refresh token pode estar stale.',\r\n revokeError,\r\n );\r\n }\r\n notify();\r\n },\r\n\r\n getUser(): NeetruUser | null {\r\n return loadCachedUser();\r\n },\r\n\r\n onAuthStateChanged(listener: AuthStateListener): () => void {\r\n listeners.add(listener);\r\n try {\r\n listener(loadCachedUser());\r\n } catch {\r\n /* ignore */\r\n }\r\n return () => {\r\n listeners.delete(listener);\r\n };\r\n },\r\n\r\n async verifyToken(token: string, options?: VerifyTokenOptions): Promise<NeetruUser> {\r\n if (!token || typeof token !== 'string') {\r\n throw new NeetruError('token_invalid_signature', 'token must be a non-empty string');\r\n }\r\n\r\n // Deriva o issuer e JWKS URL a partir do baseUrl (api.* → auth.*).\r\n const overrideAuthUrl =\r\n typeof (globalThis as { NEETRU_AUTH_URL?: string }).NEETRU_AUTH_URL === 'string'\r\n ? (globalThis as { NEETRU_AUTH_URL?: string }).NEETRU_AUTH_URL\r\n : null;\r\n const idpOrigin = overrideAuthUrl ?? config.baseUrl.replace(/^https?:\\/\\/api\\./, 'https://auth.');\r\n const issuer = idpOrigin;\r\n const jwksUrl = `${idpOrigin}/api/v1/oauth/.well-known/jwks.json`;\r\n const cacheTtlMs = options?.jwksCacheTtlMs ?? DEFAULT_JWKS_TTL_MS;\r\n\r\n // Audience é OBRIGATÓRIA — sem ela um token emitido para um client diferente\r\n // passaria na verificação de assinatura/issuer sem ser detectado.\r\n // Fontes (em ordem de prioridade):\r\n // 1. options.audience passado explicitamente pelo caller.\r\n // 2. keyId derivado do apiKey configurado no client.\r\n // Se nenhuma fonte estiver disponível, lança invalid_config imediatamente.\r\n const audienceFromOptions = options?.audience;\r\n const parsedKey = tryParseApiKey(config.apiKey);\r\n const audience = audienceFromOptions ?? parsedKey?.keyId;\r\n\r\n if (!audience) {\r\n throw new NeetruError(\r\n 'invalid_config',\r\n 'verifyToken requires an audience: provide apiKey on the client or pass options.audience. ' +\r\n 'Calling jwtVerify without an audience allows tokens issued for other OIDC clients to pass.',\r\n );\r\n }\r\n\r\n const jwks = _getJwks(jwksUrl, cacheTtlMs);\r\n\r\n try {\r\n const { payload } = await jwtVerify(token, jwks, {\r\n issuer,\r\n audience,\r\n algorithms: ['RS256'],\r\n });\r\n return _jwtPayloadToUser(payload);\r\n } catch (err: unknown) {\r\n // jose lança JWTExpired, JWTClaimValidationFailed, JWSSignatureVerificationFailed etc.\r\n // Mapeamos pra NeetruErrorCode tipado.\r\n const errName = (err as { code?: string })?.code ?? (err as Error)?.name ?? '';\r\n const errMsg = (err as Error)?.message ?? String(err);\r\n\r\n if (errName === 'ERR_JWT_EXPIRED') {\r\n throw new NeetruError('token_expired', `Token expired: ${errMsg}`);\r\n }\r\n if (errName === 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED') {\r\n throw new NeetruError('token_invalid_signature', `Token signature invalid: ${errMsg}`);\r\n }\r\n if (errName === 'ERR_JWT_CLAIM_VALIDATION_FAILED') {\r\n // jose inclui o nome do claim na mensagem. Ex: 'unexpected \"aud\" claim value'\r\n // ou 'iss claim value mismatch'.\r\n if (errMsg.includes('\"aud\"') || errMsg.includes('audience')) {\r\n throw new NeetruError('token_invalid_audience', `Token audience mismatch: ${errMsg}`);\r\n }\r\n if (errMsg.includes('\"iss\"') || errMsg.includes('issuer')) {\r\n throw new NeetruError('token_invalid_issuer', `Token issuer mismatch: ${errMsg}`);\r\n }\r\n throw new NeetruError('token_invalid_signature', `Token claim validation failed: ${errMsg}`);\r\n }\r\n // Qualquer outro erro de verificação (JWKS fetch, parse, exp checado via claim etc).\r\n throw new NeetruError('token_invalid_signature', `Token verification failed: ${errMsg}`);\r\n }\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Cria uma instância imutável do cliente Neetru SDK.\r\n *\r\n * @example\r\n * ```ts\r\n * import { createNeetruClient } from '@neetru/sdk';\r\n *\r\n * const client = createNeetruClient({\r\n * apiKey: 'nrt_a1b2c3d4_xY9z...',\r\n * });\r\n *\r\n * const { products } = await client.catalog.list();\r\n * const can = await client.entitlements.check('neetru-pulse', 'export-pdf');\r\n * await client.telemetry.event({ name: 'report_exported' });\r\n * await client.usage.track('api_call', { route: '/x' });\r\n * await client.support.createTicket({ subject: 'help', message: '...' });\r\n * ```\r\n *\r\n * @throws {NeetruError} `invalid_config` se fetch não disponível no runtime.\r\n */\r\nexport function createNeetruClient(config: NeetruClientConfig = {}): NeetruClient {\r\n const fetchImpl = config.fetch ?? globalThis.fetch;\r\n if (typeof fetchImpl !== 'function') {\r\n throw new NeetruError(\r\n 'invalid_config',\r\n 'fetch is not available in this runtime. Pass `fetch` explicitly to createNeetruClient.',\r\n );\r\n }\r\n\r\n // 3.0: validateBaseUrl rejeita URLs fora da allowlist (*.neetru.com /\r\n // localhost / configured allowedHosts). Bypass via NEETRU_ALLOW_INSECURE_BASEURL=1.\r\n const rawBaseUrl = config.baseUrl ?? DEFAULT_BASE_URL;\r\n const baseUrl = validateBaseUrl(rawBaseUrl, config.allowedHosts ?? []);\r\n const apiKey = config.apiKey ?? readEnvApiKey();\r\n const env = resolveEnv(config.env);\r\n\r\n // `bind` garante `this` correto em runtimes que validam (ex: undici).\r\n const resolved: ResolvedConfig = Object.freeze({\r\n apiKey,\r\n oidcClientId: config.oidcClientId,\r\n baseUrl,\r\n fetch: fetchImpl.bind(globalThis),\r\n env,\r\n productId: config.productId,\r\n tenantId: config.tenantId,\r\n });\r\n\r\n // Em dev, sempre ativa mocks. Mocks explícitos sempre vencem.\r\n const isDev = env === 'dev';\r\n const auth = config.mocks?.auth ?? (isDev ? new MockAuth({ ...DEV_FIXTURE_USER }) : createOidcAuthNamespace(resolved));\r\n const usage = config.mocks?.usage ?? (isDev ? new MockUsage() : createUsageNamespace(resolved));\r\n const support = config.mocks?.support ?? (isDev ? new MockSupport() : createSupportNamespace(resolved));\r\n const entitlements = config.mocks?.entitlements ?? (isDev ? new MockEntitlements() : createEntitlementsNamespace(resolved));\r\n const db = config.mocks?.db ?? createNeetruDb(resolved, config.db);\r\n const webhooks = config.mocks?.webhooks ?? (isDev ? new MockWebhooks() : createWebhooksNamespace(resolved));\r\n const notifications = config.mocks?.notifications ?? (isDev ? new MockNotifications() : createNotificationsNamespace(resolved));\r\n\r\n const client: NeetruClient = Object.freeze({\r\n config: resolved,\r\n auth,\r\n catalog: createCatalogNamespace(resolved),\r\n entitlements,\r\n telemetry: createTelemetryNamespace(resolved),\r\n usage,\r\n support,\r\n db,\r\n checkout: createCheckoutNamespace(resolved),\r\n webhooks,\r\n notifications,\r\n });\r\n\r\n return client;\r\n}\r\n","/**\n * Helper canonical pra parsing de apiKey Neetru.\n *\n * Formato: `nrt_<keyId>_<secret>` onde keyId e secret sao tokens\n * alfanumericos sem underscore.\n *\n * **H-02 fix (Opus review 2026-05-27):** o uso anterior `apiKey.split('_')[1]`\n * com fallback `?? apiKey` vazava a chave inteira como `client_id` na URL\n * publica de OAuth se o consumer passasse uma string malformada\n * (typo, ou key de outro provider colada por engano).\n *\n * Agora valida o formato e throws `NeetruError('invalid_config')` em\n * input malformado.\n */\nimport { NeetruError } from './errors';\n\nconst API_KEY_RE = /^nrt_([A-Za-z0-9]+)_([A-Za-z0-9]+)$/;\n\nexport interface ParsedApiKey {\n keyId: string;\n secret: string;\n}\n\n/**\n * Faz parse seguro da apiKey. Throws `NeetruError('invalid_config')`\n * se o formato nao bater.\n *\n * @example\n * ```ts\n * const { keyId, secret } = parseApiKey('nrt_kid123_sec456');\n * // -> { keyId: 'kid123', secret: 'sec456' }\n * ```\n */\nexport function parseApiKey(apiKey: string | undefined | null): ParsedApiKey {\n if (typeof apiKey !== 'string' || apiKey.length === 0) {\n throw new NeetruError(\n 'invalid_config',\n 'apiKey is required (formato nrt_<keyId>_<secret>)',\n );\n }\n const match = API_KEY_RE.exec(apiKey);\n if (!match) {\n throw new NeetruError(\n 'invalid_config',\n 'apiKey malformado - esperado formato nrt_<keyId>_<secret>',\n );\n }\n return { keyId: match[1], secret: match[2] };\n}\n\n/**\n * Variante que retorna `null` ao inves de throw - util pra paths\n * opcionais onde apiKey pode estar vazio (signOut sem auth previo).\n */\nexport function tryParseApiKey(apiKey: string | undefined | null): ParsedApiKey | null {\n if (typeof apiKey !== 'string' || apiKey.length === 0) return null;\n const match = API_KEY_RE.exec(apiKey);\n if (!match) return null;\n return { keyId: match[1], secret: match[2] };\n}\n","/**\n * baseUrl allowlist (HIGH-SDK-05) — fail-closed contra phishing/MITM.\n *\n * Default allow:\n * - HTTPS para `*.neetru.com` (apex e qualquer subdomínio)\n * - HTTP **apenas** para localhost / 127.0.0.1 / [::1] / *.test / *.localhost\n * - HTTPS para qualquer hostname **se** estiver em `allowedHosts` configurado\n * pelo consumer (override explícito)\n *\n * Bypass: `NEETRU_ALLOW_INSECURE_BASEURL=1` no env (Node) ou `globalThis.NEETRU_ALLOW_INSECURE_BASEURL = '1'`\n * (browser/Edge). Útil em tests / staging customizado / proxies. Lança warning\n * no console quando ativo.\n *\n * Por que: caller pode configurar `createNeetruClient({apiKey: 'nrt_xxx', baseUrl: 'http://attacker.example/'})`.\n * Sem allowlist, todo Bearer vaza pro atacker. SDK 3.0 fail-closed.\n */\nimport { NeetruError } from './errors';\n\n/** Hosts considerados loopback (dev local). */\nconst LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]', '::1']);\n\n/** Suffix oficial de produção/staging Neetru. */\nconst NEETRU_SUFFIX = '.neetru.com';\n\n/** Hostnames apex sem dot (raríssimo, mas defensivo). */\nconst NEETRU_APEX = 'neetru.com';\n\n/**\n * Detecta sub-host de dev TLD seguro (M-02 fix).\n *\n * Antes: `hostname.endsWith('.localhost')` aceitava `evil.com.localhost`\n * (TLD `.localhost` real). Agora regex força que `.localhost`/`.test` seja\n * o SUFFIX TLD e o subdomínio seja simples (sem outros pontos seguindo).\n *\n * Aceita:\n * - `myapp.test`\n * - `frontend.localhost`\n * - `app.localhost`\n * - `localhost` (cai no LOOPBACK_HOSTS, não aqui)\n *\n * Rejeita:\n * - `evil.com.localhost` (TLD `.localhost` malicioso registrado)\n * - `attacker.evil.test` (subdomínio profundo)\n * - `xn--neetr-rta.localhost` (IDN punycode)\n */\nconst SAFE_DEV_HOST_RE = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?\\.(test|localhost)$/;\n\nfunction isSafeDevHost(hostname: string): boolean {\n return SAFE_DEV_HOST_RE.test(hostname);\n}\n\n/** Normaliza trailing-dot FQDN (`api.neetru.com.` → `api.neetru.com`). L-06 fix. */\nfunction normalizeHostname(hostname: string): string {\n return hostname.toLowerCase().replace(/\\.+$/, '');\n}\n\n/**\n * Valida que `baseUrl` é seguro pra enviar Bearer tokens. Retorna URL\n * normalizada (trim trailing slash). Lança `NeetruError('invalid_config')`\n * em rejeição, exceto se override estiver ativo.\n *\n * @param baseUrl URL configurada pelo caller (raw, antes de normalização).\n * @param allowedHosts Hostnames extras permitidos (override do consumer). Suffix match.\n * @returns URL validada e normalizada (sem trailing slash).\n *\n * @throws NeetruError('invalid_config') se URL inválida ou fora da allowlist.\n */\nexport function validateBaseUrl(baseUrl: string, allowedHosts: string[] = []): string {\n if (typeof baseUrl !== 'string' || baseUrl.length === 0) {\n throw new NeetruError('invalid_config', 'baseUrl is required');\n }\n\n let parsed: URL;\n try {\n parsed = new URL(baseUrl);\n } catch {\n throw new NeetruError('invalid_config', `baseUrl is not a valid URL: ${baseUrl}`);\n }\n\n const protocol = parsed.protocol;\n // L-06: normaliza trailing dot (FQDN absoluto). M-02: já em lowercase.\n const hostname = normalizeHostname(parsed.hostname);\n\n // Bypass explícito — útil em tests / staging custom proxies.\n if (isInsecureBypassActive()) {\n if (typeof console !== 'undefined') {\n console.warn(\n `[neetru-sdk] NEETRU_ALLOW_INSECURE_BASEURL=1 ativo. baseUrl=${baseUrl} aceito sem validação.`,\n );\n }\n return baseUrl.replace(/\\/+$/, '');\n }\n\n // Bloqueia file:, javascript:, etc.\n if (protocol !== 'https:' && protocol !== 'http:') {\n throw new NeetruError(\n 'invalid_config',\n `baseUrl protocol must be http: or https:, got ${protocol}`,\n );\n }\n\n // HTTP só pra loopback / dev seguro.\n if (protocol === 'http:') {\n const isLoopback =\n LOOPBACK_HOSTS.has(hostname) ||\n isSafeDevHost(hostname);\n if (!isLoopback) {\n throw new NeetruError(\n 'invalid_config',\n `baseUrl with http: only allowed for localhost/127.0.0.1/*.test/*.localhost. Got: ${hostname}. Use https: or set NEETRU_ALLOW_INSECURE_BASEURL=1 to bypass.`,\n );\n }\n return baseUrl.replace(/\\/+$/, '');\n }\n\n // HTTPS: aceita *.neetru.com automaticamente, ou hostnames em allowedHosts.\n const isNeetruDomain =\n hostname === NEETRU_APEX || hostname.endsWith(NEETRU_SUFFIX);\n const isAllowedHost = allowedHosts.some((allowed) => {\n const norm = allowed.toLowerCase();\n return hostname === norm || hostname.endsWith(`.${norm}`);\n });\n // Loopback HTTPS também aceito (raro mas válido).\n const isLoopbackHttps =\n LOOPBACK_HOSTS.has(hostname) ||\n isSafeDevHost(hostname);\n\n if (!isNeetruDomain && !isAllowedHost && !isLoopbackHttps) {\n throw new NeetruError(\n 'invalid_config',\n `baseUrl ${hostname} is not in the allowlist. Allowed: *.neetru.com, localhost, or configure { allowedHosts: ['...'] }. Bypass: NEETRU_ALLOW_INSECURE_BASEURL=1.`,\n );\n }\n\n return baseUrl.replace(/\\/+$/, '');\n}\n\n/** Lê flag de bypass do env (Node) ou globalThis (browser/Edge). */\nfunction isInsecureBypassActive(): boolean {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const proc = (globalThis as any).process;\n const envVal = proc?.env?.NEETRU_ALLOW_INSECURE_BASEURL;\n if (envVal === '1' || envVal === 'true') return true;\n } catch {\n /* ignore */\n }\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const g = (globalThis as any).NEETRU_ALLOW_INSECURE_BASEURL;\n if (g === '1' || g === 'true' || g === true) return true;\n } catch {\n /* ignore */\n }\n return false;\n}\n","/**\r\n * Tipos públicos do SDK Neetru.\r\n *\r\n * Vendor-neutral: nada aqui referencia `firebase/*`, `stripe`, ou qualquer\r\n * provider interno. Caller só vê superfície neutra (Product, Entitlement, ...).\r\n */\r\n\r\n/** Default base URL pra API pública Neetru. */\r\nexport const DEFAULT_BASE_URL = 'https://api.neetru.com';\r\n\r\n/**\r\n * Configuração passada pra `createNeetruClient`.\r\n */\r\nexport interface NeetruClientConfig {\r\n /**\r\n * Bearer token Neetru (formato `nrt_<keyId>_<secret>`). Opcional —\r\n * se ausente, o SDK tenta `process.env.NEETRU_API_KEY` em Node.\r\n *\r\n * Endpoints públicos (catalog) funcionam sem apiKey. Endpoints autenticados\r\n * (entitlements, telemetry) lançam `missing_api_key` se ausente.\r\n */\r\n apiKey?: string;\r\n /**\r\n * 3.1.3 — `client_id` do client OIDC confidencial do produto, registrado em\r\n * `oidc_clients/{id}` no Core (par id + segredo, modelo Firebase/Facebook).\r\n *\r\n * Usado como `client_id` no fluxo `auth.signIn()` (Authorization Code + PKCE).\r\n * É **distinto** do `keyId` embutido na `apiKey` (`nrt_<keyId>_<secret>`), que\r\n * identifica a API key de máquina — não um client OIDC. Se ausente, `signIn`\r\n * cai no `keyId` por compat, mas o `/authorize` do Core só reconhece um\r\n * `oidc_clients` válido, então registre e passe `oidcClientId` em produção.\r\n */\r\n oidcClientId?: string;\r\n /**\r\n * URL base da API Neetru. Default: `https://api.neetru.com`.\r\n * Útil em testes apontando pra staging ou mock server.\r\n */\r\n baseUrl?: string;\r\n /**\r\n * Implementação de fetch customizada. Default: `globalThis.fetch`.\r\n * Necessário em runtimes que não exponham fetch global por default.\r\n */\r\n fetch?: typeof globalThis.fetch;\r\n /**\r\n * Modo de runtime. `dev` ativa mocks (auth retorna user fixture, usage só\r\n * loga, support retorna lista fake). `workspace` e `prod` chamam HTTP real.\r\n *\r\n * Default: lê `process.env.NEETRU_ENV` (Node) ou `globalThis.NEETRU_ENV`\r\n * (browser); fallback `prod`.\r\n */\r\n env?: 'dev' | 'workspace' | 'prod';\r\n /**\r\n * Override de mocks — útil em tests do consumer pra injetar fixtures\r\n * determinísticos (sem depender de NEETRU_ENV=dev).\r\n */\r\n mocks?: {\r\n auth?: AuthNamespace;\r\n usage?: UsageNamespace;\r\n support?: SupportNamespace;\r\n entitlements?: NeetruClient['entitlements'];\r\n /** v2.0: aceita NeetruDb (inclui MockDb). DbNamespace legado não é mais aceito. */\r\n db?: import('./db/client-db').NeetruDb;\r\n webhooks?: import('./webhooks').WebhooksNamespace;\r\n notifications?: import('./notifications').NotificationsNamespace;\r\n };\r\n /**\r\n * v0.3 — productId default usado por `usage.report()` / `usage.check()` /\r\n * `db.collection()` quando não passado explicitamente nas options.\r\n */\r\n productId?: string;\r\n /**\r\n * v0.3 — tenantId default usado por `usage.report()` / `usage.check()` /\r\n * `db.collection()` quando não passado explicitamente nas options.\r\n */\r\n tenantId?: string;\r\n /**\r\n * v2.0 — Configuração do banco lógico: transport, dbId, coleções.\r\n * Gerado pelo scaffold `neetru db init`. Opcional — padrão é transport='rest'.\r\n *\r\n * Use `transport` (v2.3+) em vez do campo `engine` depreciado.\r\n * Valores: `'rest'` | `'firestore'` | `'nosql-vm'`.\r\n */\r\n db?: import('./db/client-db').NeetruDbOptions;\r\n /**\r\n * 3.0 — hosts adicionais permitidos para `baseUrl`. Por default, SDK aceita\r\n * `*.neetru.com` HTTPS + localhost. Para apontar pra staging/proxy custom em\r\n * `https://meu-proxy.empresa.com`, adicione `['empresa.com']`.\r\n *\r\n * Bypass total: `NEETRU_ALLOW_INSECURE_BASEURL=1` no env.\r\n */\r\n allowedHosts?: string[];\r\n}\r\n\r\n/**\r\n * Status do produto no catálogo público.\r\n */\r\nexport type ProductStatus = 'live' | 'soon' | 'beta';\r\n\r\n/**\r\n * Produto SaaS publicado pelo Neetru Core.\r\n *\r\n * Schema neutro — alinhado com `public_products/{slug}` no backend mas\r\n * nunca expõe campos internos (Firestore Timestamps, draft state, etc).\r\n */\r\nexport interface Product {\r\n /** Identificador estável do produto, ex: `neetru-pulse`. */\r\n slug: string;\r\n /** Nome de exibição, ex: `Neetru Pulse`. */\r\n name: string;\r\n /** Subtítulo curto, ex: `Gestão de operações`. */\r\n tagline?: string;\r\n /** Descrição longa em prosa. */\r\n description?: string;\r\n /** Status público do produto. */\r\n status?: ProductStatus;\r\n /** Hint de ícone (catálogo de keys interno do Core). */\r\n iconKey?: string;\r\n /** Link override do CTA principal (default: página do produto). */\r\n ctaHref?: string;\r\n /** Label override do CTA. */\r\n ctaLabel?: string;\r\n /** Lista opcional de planos cobrados. Pode ser preenchida v0.2+. */\r\n plans?: ProductPlan[];\r\n}\r\n\r\n/** Plano cobrado de um produto (placeholder v0.1 — schema final v0.2). */\r\nexport interface ProductPlan {\r\n id: string;\r\n name: string;\r\n /** Preço mensal em centavos (BRL). Pode ser undefined em planos custom. */\r\n amountCents?: number;\r\n features?: string[];\r\n}\r\n\r\n/**\r\n * Resposta do `client.catalog.list()`.\r\n */\r\nexport interface CatalogListResponse {\r\n products: Product[];\r\n fetchedAt: string;\r\n}\r\n\r\n/**\r\n * Resposta do `client.entitlements.check(productSlug, feature)`.\r\n *\r\n * `allowed` é o sinal forte; `reason` ajuda a debugar (não exibir pro user\r\n * final).\r\n */\r\nexport interface EntitlementCheck {\r\n allowed: boolean;\r\n productSlug: string;\r\n feature: string;\r\n /** Reason code estável: `granted` | `not_subscribed` | `feature_not_in_plan` | `expired`. */\r\n reason?: string;\r\n}\r\n\r\n/**\r\n * Payload pra `client.telemetry.event()`.\r\n */\r\nexport interface TelemetryEventInput {\r\n /** Nome do evento, ex: `dashboard_opened`, `report_exported`. */\r\n name: string;\r\n /** Atributos adicionais (chave → valor primitivo). */\r\n properties?: Record<string, string | number | boolean | null>;\r\n /** Timestamp ISO opcional; default = server time. */\r\n timestamp?: string;\r\n}\r\n\r\n/**\r\n * Confirmação de aceitação do evento de telemetria.\r\n */\r\nexport interface TelemetryEventAck {\r\n ok: true;\r\n /** ID gerado pelo backend pra evento (`usage_events/{id}`). */\r\n eventId: string;\r\n}\r\n\r\n// ─── Sprint 6 — Telemetry log per-product ──────────────────────────────────\r\n\r\nexport type TelemetryLogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal';\r\n\r\nexport interface TelemetryLogInput {\r\n level: TelemetryLogLevel;\r\n message: string;\r\n metadata?: Record<string, unknown>;\r\n /** Override correlationId (default: lê dos headers/env automaticamente). */\r\n correlationId?: string;\r\n /** Slug do produto. Se ausente, o SDK usa `config.productId` como default\r\n * (o backend NÃO infere — exige productSlug no body, fail-closed). */\r\n productSlug?: string;\r\n}\r\n\r\nexport interface TelemetryLogAck {\r\n ok: true;\r\n /** ID do log gravado (`logs/{productId}/{yyyymmdd}/{logId}`) — opcional em mocks. */\r\n logId?: string;\r\n /** Indicador de modo (mock vs http). */\r\n mode: 'mock' | 'http';\r\n}\r\n\r\n/**\r\n * Handle imutável retornado por `createNeetruClient`. Carrega namespaces\r\n * `auth`, `catalog`, `entitlements`, `telemetry`, `usage`, `support`.\r\n *\r\n * Cada namespace é exposto como objeto chamável — espelha API Firebase\r\n * (`auth`, `firestore`) ou Stripe (`paymentIntents`, `customers`).\r\n */\r\nexport interface NeetruClient {\r\n /** Configuração resolvida (apiKey, baseUrl, fetch). Read-only. */\r\n readonly config: ResolvedConfig;\r\n /** Namespace auth (v0.2 — OIDC + mocks dev). */\r\n readonly auth: AuthNamespace;\r\n /** Namespace catálogo público de produtos. */\r\n readonly catalog: {\r\n /** Lista produtos publicados. */\r\n list(opts?: CatalogListOptions): Promise<CatalogListResponse>;\r\n /** Busca produto único por slug. */\r\n get(slug: string): Promise<Product>;\r\n };\r\n /** Namespace entitlements (v1.2: cache LRU 60s TTL). */\r\n readonly entitlements: {\r\n /**\r\n * Verifica se o portador da apiKey pode usar `feature` do produto `slug`.\r\n * Cacheado 60s. `{ cacheBust: true }` força ida ao servidor.\r\n */\r\n check(\r\n productSlug: string,\r\n feature: string,\r\n opts?: { cacheBust?: boolean },\r\n ): Promise<boolean>;\r\n /** Variante que retorna o objeto completo com `reason`. */\r\n checkDetailed(\r\n productSlug: string,\r\n feature: string,\r\n opts?: { cacheBust?: boolean },\r\n ): Promise<EntitlementCheck>;\r\n };\r\n /** Namespace telemetria (v1.2: track fire-and-forget + flush). */\r\n readonly telemetry: {\r\n /** Persiste um evento single-shot. await retorna { ok, eventId }. */\r\n event(input: TelemetryEventInput): Promise<TelemetryEventAck>;\r\n /** Fire-and-forget: enqueue + flush 500ms debounce. Sem retorno. */\r\n track(input: TelemetryEventInput): void;\r\n /** Força flush da queue do track() (chamar antes de unload). */\r\n flush(): Promise<void>;\r\n /**\r\n * Registra um log estruturado per-product (Sprint 6).\r\n *\r\n * - Em `NEETRU_ENV=dev`: apenas console.{level} (sem network).\r\n * - Em `workspace`/`prod`: POST `/api/sdk/v1/telemetry/log` com Bearer + correlationId.\r\n */\r\n log(input: TelemetryLogInput): Promise<TelemetryLogAck>;\r\n };\r\n /** Namespace usage (v0.2 — track + quota; v0.3 — report + check). */\r\n readonly usage: UsageNamespace;\r\n /** Namespace support (v0.2 — tickets). */\r\n readonly support: SupportNamespace;\r\n /**\r\n * Namespace db (v2.0 — Mundo Documentos offline-first + Mundo SQL).\r\n *\r\n * Breaking change v2.0: `client.db` agora é `NeetruDb` em vez de `DbNamespace`.\r\n * - `db.collection(name)` → `DbCollectionRef` (offline-first, com `onSnapshot`,\r\n * `batch`, `doc(id)`, `onDoc`; `list()` retorna `DbListResult` com cursor).\r\n * - `db.sql(schema)` → `Promise<NeetruSqlClient>` (Mundo SQL).\r\n * - `db.syncState` / `db.flush()` / `db.clearCache()` (camada offline).\r\n *\r\n * O antigo `DbNamespace` (list retornava `T[]`) foi removido em v2.0.\r\n */\r\n readonly db: import('./db/client-db').NeetruDb;\r\n /** Namespace checkout (v1.1 — start/get/cancel intent + auto-redirect). */\r\n readonly checkout: import('./checkout').CheckoutNamespace;\r\n /** Namespace webhooks (v1.2 — register/list/unregister/test). */\r\n readonly webhooks: import('./webhooks').WebhooksNamespace;\r\n /** Namespace notifications (v1.2 — send/list/markRead/dismiss). */\r\n readonly notifications: import('./notifications').NotificationsNamespace;\r\n}\r\n\r\n// ─── v0.2 — Auth namespace ──────────────────────────────────────────────────\r\n\r\n/**\r\n * User retornado pelo OIDC ID token. Schema neutro — não vaza Firebase\r\n * decoded token shape. Subset estável do RFC 7519 + custom claims Neetru.\r\n */\r\nexport interface NeetruUser {\r\n /** Subject — uid estável. */\r\n uid: string;\r\n email: string;\r\n emailVerified?: boolean;\r\n displayName?: string;\r\n photoURL?: string;\r\n /** Custom claim Neetru — true quando staff. */\r\n isStaff?: boolean;\r\n /** Custom claim Neetru — true quando customer enrolled. */\r\n isCustomer?: boolean;\r\n /** Tenant assigned (multi-tenant deployments). */\r\n tenantId?: string;\r\n /** Outros claims OIDC (aud, iss, iat, exp). */\r\n [extra: string]: unknown;\r\n}\r\n\r\nexport interface SignInOptions {\r\n /** OIDC redirect_uri override. Default = window.location origin. */\r\n redirectUri?: string;\r\n /** OIDC scope. Default `openid profile email`. */\r\n scope?: string;\r\n /** Onde mandar após login completo. Default = window.location.href. */\r\n postLoginRedirect?: string;\r\n}\r\n\r\nexport type AuthStateListener = (user: NeetruUser | null) => void;\r\n\r\n/**\r\n * 3.1.3 — Resultado de `auth.handleRedirectCallback()`: o material que o **backend\r\n * do produto** (confidential client) usa pra trocar o code por tokens no\r\n * endpoint `/api/v1/oauth/token` (POST x-www-form-urlencoded, `grant_type=\r\n * authorization_code`, autenticação `Basic base64(clientId:clientSecret)`).\r\n *\r\n * O SDK nunca faz essa troca no browser (exigiria o `client_secret`). Ele só\r\n * gera/valida o PKCE + state e entrega estes campos pro lado servidor.\r\n */\r\nexport interface RedirectCallbackResult {\r\n /** `authorization_code` emitido pelo IdP — single-use, TTL curto. */\r\n code: string;\r\n /** PKCE `code_verifier` (RFC 7636) — enviar junto do code no `/token`. */\r\n codeVerifier: string;\r\n /**\r\n * `redirect_uri` exato usado no `/authorize`. O `/token` exige reenvio\r\n * idêntico (exact match) — passe este valor sem alterar.\r\n */\r\n redirectUri: string;\r\n /**\r\n * `nonce` enviado no `/authorize`. O backend deve validar que o claim\r\n * `nonce` do `id_token` retornado bate com este valor (anti-replay OIDC).\r\n */\r\n nonce: string;\r\n /** `state` validado (CSRF). Exposto pra logging/correlação. */\r\n state: string;\r\n /**\r\n * Destino pós-login que o app passou em `signIn({ postLoginRedirect })`.\r\n * `undefined` se não informado.\r\n */\r\n postLoginRedirect?: string;\r\n}\r\n\r\nexport interface AuthNamespace {\r\n /**\r\n * Inicia fluxo de login OIDC (Authorization Code + PKCE). Em dev\r\n * (`NEETRU_ENV=dev`) retorna mock user direto sem redirect. Em browser\r\n * gera `state` (CSRF), `nonce` e o par PKCE `code_verifier`/`code_challenge`\r\n * (S256), persiste a transação em `sessionStorage` e redireciona pro\r\n * `/authorize`. Complete o fluxo no retorno com `handleRedirectCallback()`.\r\n */\r\n signIn(options?: SignInOptions): Promise<NeetruUser | void>;\r\n /**\r\n * 3.1.3 — Processa o retorno do IdP após `signIn`. Lê `code` + `state` da URL\r\n * (default `location.href`; passe `currentUrl` pra override), valida o\r\n * `state` contra a transação salva em `signIn` (CSRF), consome a transação\r\n * (single-use), limpa os params da URL e devolve o material pro backend\r\n * trocar por tokens. Retorna `null` se a URL não é um callback (sem `code`).\r\n *\r\n * @throws {NeetruError} `oidc_state_mismatch` se o `state` não bate ou não há\r\n * transação pendente; ou um erro com `.code` = o `error` do IdP (ex:\r\n * `access_denied`) quando a URL traz `?error=`.\r\n */\r\n handleRedirectCallback(currentUrl?: string): Promise<RedirectCallbackResult | null>;\r\n /**\r\n * 3.1.3 — Retorna o `id_token` cru (string JWT) que o app armazenou em\r\n * `localStorage['neetru_id_token']`, ou `null` se ausente/expirado. Útil pra\r\n * mandar como `Authorization: Bearer` ao BFF do produto. Para os claims\r\n * decodificados use `getUser()`; para validar assinatura use `verifyToken()`.\r\n */\r\n getIdToken(): string | null;\r\n /** Limpa session local + revoga refresh token no servidor. */\r\n signOut(): Promise<void>;\r\n /** Retorna o user atual (do id_token cached) ou `null` se não logado. */\r\n getUser(): NeetruUser | null;\r\n /**\r\n * Subscreve a mudanças de estado de auth. Listener é invocado imediatamente\r\n * com user atual. Retorna função de unsubscribe.\r\n */\r\n onAuthStateChanged(listener: AuthStateListener): () => void;\r\n /**\r\n * Valida um id_token JWT emitido por `auth.neetru.com` server-side.\r\n *\r\n * Usa JWKS local cacheado (1h TTL, configurável via `jwksCacheTtlMs`).\r\n * Ideal para Next.js route handlers, middleware e qualquer ambiente Node/Edge\r\n * server-side onde verificação rápida sem round-trip é necessária.\r\n *\r\n * @param token - JWT id_token obtido do cookie ou header Authorization.\r\n * @param options - Opções opcionais de verificação.\r\n * @returns `NeetruUser` com claims validados.\r\n *\r\n * @throws {NeetruError} com `.code`:\r\n * - `token_expired` — token expirado (`exp` no passado)\r\n * - `token_invalid_signature` — assinatura não verificada pela JWKS\r\n * - `token_invalid_audience` — `aud` não bate com o `clientId` configurado\r\n * - `token_invalid_issuer` — `iss` não é `https://auth.neetru.com`\r\n *\r\n * @example\r\n * ```ts\r\n * // Next.js route handler\r\n * import { createNeetruClient } from '@neetru/sdk';\r\n * const client = createNeetruClient({ apiKey: 'nrt_...' });\r\n *\r\n * export async function POST(req: Request) {\r\n * const token = req.cookies.get('neetru-session')?.value;\r\n * try {\r\n * const user = await client.auth.verifyToken(token);\r\n * // user.uid, user.email, user.isStaff etc disponíveis\r\n * } catch (err) {\r\n * return new Response('Unauthorized', { status: 401 });\r\n * }\r\n * }\r\n * ```\r\n */\r\n verifyToken(token: string, options?: VerifyTokenOptions): Promise<NeetruUser>;\r\n}\r\n\r\n/** Opções para `auth.verifyToken()`. */\r\nexport interface VerifyTokenOptions {\r\n /**\r\n * TTL do cache de JWKS em milissegundos. Default: 3600000 (1h).\r\n * Valores menores aumentam latência (mais fetches); maiores aumentam\r\n * o tempo de janela após rotação de chaves.\r\n */\r\n jwksCacheTtlMs?: number;\r\n /**\r\n * Audience (`aud`) esperada no token. Se ausente, o SDK tenta derivar do\r\n * `apiKey` configurado no client (campo `keyId`). Pelo menos uma das duas\r\n * fontes é **obrigatória** — `verifyToken` lança `invalid_config` se nenhuma\r\n * audience puder ser resolvida, pois verificar um token sem `aud` permitiria\r\n * tokens emitidos para outros clients passarem sem detecção.\r\n */\r\n audience?: string;\r\n}\r\n\r\n// ─── v0.2 — Usage namespace ─────────────────────────────────────────────────\r\n\r\n/**\r\n * 3.0 BREAKING: `UsageEventInput` mantido só como tipo para tests/legacy\r\n * imports — não é mais retorno de método. `usage.track`/`usage.getQuota`\r\n * **REMOVIDOS** em 3.0. Use `usage.report(resource, qty, options)`.\r\n */\r\nexport interface UsageEventInput {\r\n event: string;\r\n properties?: Record<string, string | number | boolean | null>;\r\n quantity?: number;\r\n}\r\n\r\n/**\r\n * 3.0 BREAKING: `UsageQuota` mantido só para compat de imports. Não é mais\r\n * retorno de método ativo. `usage.report()` devolve `{value, limit, remaining}`\r\n * inline; `usage.check()` devolve detalhes do entitlement.\r\n */\r\nexport interface UsageQuota {\r\n metric: string;\r\n used: number;\r\n limit: number;\r\n resetsAt?: string;\r\n plan?: string;\r\n}\r\n\r\n/**\r\n * 3.0 — superfície limpa: `report` (POST metered) + `check` (GET entitlement).\r\n *\r\n * Métodos removidos vs 2.x:\r\n * - `track(event, props)` — vaporware contra Core. Use `report()`.\r\n * - `getQuota(metric)` — endpoint nunca existiu. `report()` devolve quota.\r\n */\r\nexport interface UsageNamespace {\r\n /**\r\n * Reporta consumo metered. Incrementa `usage_counters` no Core atomicamente.\r\n * Idempotency-Key gerado por chamada (defesa anti-dup em retry transient).\r\n *\r\n * `productId`/`tenantId` lidos do contexto do client se ausentes nas options.\r\n */\r\n report(\r\n resource: string,\r\n qty?: number,\r\n options?: { productId?: string; tenantId?: string },\r\n ): Promise<{\r\n ok: true;\r\n counterId?: string;\r\n value?: number;\r\n limit?: number;\r\n remaining?: number;\r\n status?: string;\r\n }>;\r\n /**\r\n * Verifica entitlement de um resource/feature. GET cacheável (HTTP 60s).\r\n * Resposta inclui `allowed`, `reason`, `remaining`, `limit`, `planId`,\r\n * `planFeatures` e `behavior` ('readonly' quando limit_exceeded).\r\n */\r\n check(\r\n resource: string,\r\n options?: { productId?: string; tenantId?: string },\r\n ): Promise<{\r\n allowed: boolean;\r\n reason?: string;\r\n remaining?: number;\r\n limit?: number;\r\n planId?: string | null;\r\n planFeatures?: string[];\r\n behavior?: 'readonly' | null;\r\n }>;\r\n}\r\n\r\n// ─── v0.3 — Datastore namespace ────────────────────────────────────────────\r\n\r\n/**\r\n * Namespace `db` (v0.3) — wrapper minimalista para CRUD em coleções tenant-scoped\r\n * via Core REST. Em dev retorna fixtures in-memory por collection.\r\n *\r\n * O Core injeta automaticamente o tenantId no path do Firestore:\r\n * `tenant_{tid}_{name}/{docId}`.\r\n */\r\n/** Filtro `where` simples — alinhado com endpoint REST `field:op:value`. */\r\nexport interface DbWhereFilter {\r\n field: string;\r\n op: '==' | '!=' | '<' | '<=' | '>' | '>=' | 'in';\r\n value: string | number | boolean | null | Array<string | number | boolean>;\r\n}\r\n\r\nexport interface DbListOptions {\r\n limit?: number;\r\n /** Lista de filtros — máximo 5 (alinhado ao backend). */\r\n where?: DbWhereFilter[];\r\n}\r\n\r\nexport interface DbCollectionRef {\r\n /** Lista documentos com filtros opcionais. */\r\n list<T = Record<string, unknown>>(opts?: DbListOptions): Promise<T[]>;\r\n /** Lê um documento por id. Retorna `null` se não existe. */\r\n get<T = Record<string, unknown>>(id: string): Promise<T | null>;\r\n /** Cria/upsert um documento com id explícito. */\r\n set(id: string, data: Record<string, unknown>): Promise<{ ok: true }>;\r\n /**\r\n * v0.3.1 — Adiciona doc com id auto-gerado pelo backend. Retorna `{id}` do\r\n * doc criado. Diferente de `set(id, data)` que requer caller fornecer id.\r\n */\r\n add(data: Record<string, unknown>): Promise<{ ok: true; id: string }>;\r\n /** Atualiza doc com merge — só campos passados em `data`. */\r\n update(id: string, data: Record<string, unknown>): Promise<{ ok: true }>;\r\n /** Deleta um documento. */\r\n remove(id: string): Promise<{ ok: true }>;\r\n}\r\n\r\nexport interface DbNamespace {\r\n collection(name: string): DbCollectionRef;\r\n}\r\n\r\n// ─── v0.2 — Support namespace ───────────────────────────────────────────────\r\n\r\nexport type SupportSeverity = 'low' | 'normal' | 'high' | 'urgent';\r\nexport type SupportStatus = 'open' | 'pending' | 'resolved' | 'closed';\r\n\r\nexport interface SupportTicket {\r\n id: string;\r\n subject: string;\r\n message: string;\r\n severity: SupportSeverity;\r\n status: SupportStatus;\r\n createdAt: string;\r\n updatedAt?: string;\r\n /** Slug do produto referenciado. */\r\n productSlug?: string;\r\n}\r\n\r\nexport interface CreateTicketInput {\r\n subject: string;\r\n message: string;\r\n severity?: SupportSeverity;\r\n productSlug?: string;\r\n /**\r\n * **L-05 fix (Opus review 2026-05-27):** metadata opcional (Core já aceita\r\n * via `metadata: z.record(...)` no Zod). Útil pra anexar contexto como\r\n * `{ orderId, userAgent, route, sessionId }` sem inflar subject/message.\r\n *\r\n * Chaves limitadas a 64 chars; valores primitive (string/number/boolean/null).\r\n */\r\n metadata?: Record<string, string | number | boolean | null>;\r\n}\r\n\r\nexport interface SupportNamespace {\r\n /**\r\n * Cria um novo ticket. **3.0**: POST `/api/sdk/v1/support/tickets`\r\n * (canonical, requer `productId` no body — default `config.productId`).\r\n * Mock em dev.\r\n */\r\n createTicket(input: CreateTicketInput): Promise<SupportTicket>;\r\n /**\r\n * Lista meus tickets abertos. **3.0**: GET `/api/sdk/v1/support/tickets?productId=...`\r\n * (canonical). `options.productSlug` override do `config.productId` default.\r\n */\r\n listMyTickets(options?: { productSlug?: string }): Promise<SupportTicket[]>;\r\n}\r\n\r\n// ─── v0.2 — Env detection ───────────────────────────────────────────────────\r\n\r\n/**\r\n * Modo do SDK. `dev` ativa mocks automáticos (úteis pra testes e\r\n * desenvolvimento sem precisar de backend rodando).\r\n */\r\nexport type NeetruEnv = 'dev' | 'workspace' | 'prod';\r\n\r\n/**\r\n * Configuração resolvida (defaults aplicados, fetch garantido).\r\n */\r\nexport interface ResolvedConfig {\r\n readonly apiKey?: string;\r\n /** 3.1.3 — client_id OIDC confidencial do produto (vide NeetruClientConfig). */\r\n readonly oidcClientId?: string;\r\n readonly baseUrl: string;\r\n readonly fetch: typeof globalThis.fetch;\r\n /** Resolved env — `dev` | `workspace` | `prod`. Default `prod`. */\r\n readonly env: NeetruEnv;\r\n /** Default productId (v0.3). */\r\n readonly productId?: string;\r\n /** Default tenantId (v0.3). */\r\n readonly tenantId?: string;\r\n}\r\n\r\n/** Opções pra `catalog.list()`. */\r\nexport interface CatalogListOptions {\r\n /** Inclui rascunhos (apenas com Bearer staff). Default false. */\r\n includeDrafts?: boolean;\r\n}\r\n","/**\r\n * Catálogo público de produtos SaaS Neetru.\r\n *\r\n * Endpoints consumidos (v1.2+):\r\n * - `GET /api/sdk/v1/catalog` — listagem pública (sem auth)\r\n * - `GET /api/sdk/v1/catalog/{slug}` — produto único (sem auth)\r\n *\r\n * v1.1 e anteriores usavam `/api/v1/cli/catalog` (staff CLI), o que forçava\r\n * SDK consumers a manter Bearer staff-only. v1.2 separa: SDK consome o\r\n * endpoint público (`published === true`), staff continua usando CLI quando\r\n * precisa de rascunho.\r\n *\r\n * Read-only. Publicação de produto continua via CLI `neetru publish`.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type {\r\n CatalogListOptions,\r\n CatalogListResponse,\r\n Product,\r\n ResolvedConfig,\r\n} from './types';\r\n\r\ninterface RawCatalogListResponse {\r\n ok?: boolean;\r\n count?: number;\r\n products?: unknown[];\r\n fetchedAt?: string;\r\n}\r\n\r\ninterface RawCatalogGetResponse {\r\n ok?: boolean;\r\n product?: unknown;\r\n}\r\n\r\nfunction toProduct(raw: unknown): Product {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Catalog response item is not an object');\r\n }\r\n const r = raw as Record<string, unknown>;\r\n if (typeof r.slug !== 'string' || !r.slug) {\r\n throw new NeetruError('invalid_response', 'Catalog product missing slug');\r\n }\r\n if (typeof r.name !== 'string' || !r.name) {\r\n throw new NeetruError('invalid_response', 'Catalog product missing name');\r\n }\r\n const product: Product = {\r\n slug: r.slug,\r\n name: r.name,\r\n };\r\n if (typeof r.tagline === 'string') product.tagline = r.tagline;\r\n if (typeof r.description === 'string') product.description = r.description;\r\n if (r.status === 'live' || r.status === 'soon' || r.status === 'beta') {\r\n product.status = r.status;\r\n }\r\n if (typeof r.iconKey === 'string') product.iconKey = r.iconKey;\r\n if (typeof r.ctaHref === 'string') product.ctaHref = r.ctaHref;\r\n if (typeof r.ctaLabel === 'string') product.ctaLabel = r.ctaLabel;\r\n // plans é placeholder v0.2 — preservar se backend mandar\r\n if (Array.isArray(r.plans)) {\r\n product.plans = r.plans.filter(\r\n (p): p is { id: string; name: string } =>\r\n typeof p === 'object' &&\r\n p !== null &&\r\n typeof (p as Record<string, unknown>).id === 'string' &&\r\n typeof (p as Record<string, unknown>).name === 'string',\r\n ) as Product['plans'];\r\n }\r\n return product;\r\n}\r\n\r\nexport function createCatalogNamespace(config: ResolvedConfig) {\r\n return {\r\n /**\r\n * Lista produtos publicados. Por default só `published=true`; staff\r\n * pode passar `includeDrafts: true` (requer Bearer com role admin/operator).\r\n */\r\n async list(_opts: CatalogListOptions = {}): Promise<CatalogListResponse> {\r\n // SDK só lê produtos publicados. `includeDrafts` legado é ignorado:\r\n // rascunhos só via CLI staff (`/api/v1/cli/catalog?drafts=true`).\r\n const raw = await httpRequest<RawCatalogListResponse>(config, {\r\n method: 'GET',\r\n path: '/api/sdk/v1/catalog',\r\n });\r\n\r\n if (!raw || !Array.isArray(raw.products)) {\r\n throw new NeetruError(\r\n 'invalid_response',\r\n 'Catalog list response missing products array',\r\n );\r\n }\r\n\r\n return {\r\n products: raw.products.map(toProduct),\r\n fetchedAt: typeof raw.fetchedAt === 'string'\r\n ? raw.fetchedAt\r\n : new Date().toISOString(),\r\n };\r\n },\r\n\r\n /**\r\n * Busca produto único por slug.\r\n *\r\n * @throws {NeetruError} `not_found` se slug inexistente ou não publicado.\r\n */\r\n async get(slug: string): Promise<Product> {\r\n if (!slug || typeof slug !== 'string') {\r\n throw new NeetruError('validation_failed', 'slug is required');\r\n }\r\n const raw = await httpRequest<RawCatalogGetResponse>(config, {\r\n method: 'GET',\r\n path: `/api/sdk/v1/catalog/${encodeURIComponent(slug)}`,\r\n });\r\n\r\n if (!raw || !raw.product) {\r\n throw new NeetruError(\r\n 'invalid_response',\r\n 'Catalog get response missing product',\r\n );\r\n }\r\n return toProduct(raw.product);\r\n },\r\n };\r\n}\r\n","/**\r\n * Entitlements — verifica se o portador da apiKey pode usar feature X\r\n * do produto Y.\r\n *\r\n * **3.0**: endpoint canonical é `GET /api/sdk/v1/entitlements?productId&tenantId&feature`.\r\n * Path legacy `/api/v1/sdk/entitlements/check?slug=X&feature=Y` ainda\r\n * funciona no Core (compat 2.x), mas SDK 3.0 padroniza pra canonical.\r\n *\r\n * **Atenção**: `client.entitlements.check(productSlug, feature)` é o\r\n * **legacy boolean API** (sem tenant). Continua funcional contra\r\n * `/api/v1/sdk/entitlements/check` (que segue ativo). Para o check completo\r\n * com `behavior`/`remaining`/`limit`, use `client.usage.check(resource, opts)`\r\n * que aponta para o canonical `/api/sdk/v1/entitlements`.\r\n *\r\n * v1.2 introduz cache LRU em memória (default 60s TTL, 100 entries). Cada\r\n * (productSlug, feature) pareando o `apiKey` é cacheado. Caller pode invalidar\r\n * via `__resetCache()` (test helper) ou via `cacheBust: true` na chamada.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type { EntitlementCheck, ResolvedConfig } from './types';\r\n\r\ninterface RawEntitlementCheck {\r\n allowed?: boolean;\r\n productSlug?: string;\r\n feature?: string;\r\n reason?: string;\r\n}\r\n\r\nfunction toEntitlementCheck(raw: unknown): EntitlementCheck {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Entitlement response is not an object');\r\n }\r\n const r = raw as RawEntitlementCheck;\r\n if (typeof r.allowed !== 'boolean') {\r\n throw new NeetruError('invalid_response', 'Entitlement response missing `allowed` boolean');\r\n }\r\n return {\r\n allowed: r.allowed,\r\n productSlug: typeof r.productSlug === 'string' ? r.productSlug : '',\r\n feature: typeof r.feature === 'string' ? r.feature : '',\r\n reason: typeof r.reason === 'string' ? r.reason : undefined,\r\n };\r\n}\r\n\r\n/** TTL default — 60s. Pareando com tempo de propagação típico de mudança de plano. */\r\nconst CACHE_TTL_MS = 60_000;\r\n/** Máx entries por instância de namespace — LRU. */\r\nconst CACHE_MAX = 100;\r\n\r\ninterface CacheEntry {\r\n value: EntitlementCheck;\r\n expiresAt: number;\r\n}\r\n\r\nexport interface EntitlementsCheckOptions {\r\n /** Se true, ignora cache local e força ida ao servidor. Default false. */\r\n cacheBust?: boolean;\r\n}\r\n\r\nexport function createEntitlementsNamespace(config: ResolvedConfig) {\r\n // Map preserva ordem de inserção — readequa LRU manualmente em hit.\r\n const cache = new Map<string, CacheEntry>();\r\n\r\n function cacheKey(productSlug: string, feature: string): string {\r\n return `${productSlug}::${feature}`;\r\n }\r\n\r\n function readCache(key: string): EntitlementCheck | null {\r\n const entry = cache.get(key);\r\n if (!entry) return null;\r\n if (entry.expiresAt < Date.now()) {\r\n cache.delete(key);\r\n return null;\r\n }\r\n // LRU touch: reinsere no final.\r\n cache.delete(key);\r\n cache.set(key, entry);\r\n return entry.value;\r\n }\r\n\r\n function writeCache(key: string, value: EntitlementCheck): void {\r\n if (cache.size >= CACHE_MAX) {\r\n const oldest = cache.keys().next().value;\r\n if (oldest !== undefined) cache.delete(oldest);\r\n }\r\n cache.set(key, { value, expiresAt: Date.now() + CACHE_TTL_MS });\r\n }\r\n\r\n async function checkDetailed(\r\n productSlug: string,\r\n feature: string,\r\n opts: EntitlementsCheckOptions = {},\r\n ): Promise<EntitlementCheck> {\r\n if (!productSlug) throw new NeetruError('validation_failed', 'productSlug is required');\r\n if (!feature) throw new NeetruError('validation_failed', 'feature is required');\r\n\r\n const key = cacheKey(productSlug, feature);\r\n if (!opts.cacheBust) {\r\n const cached = readCache(key);\r\n if (cached) return cached;\r\n }\r\n\r\n const raw = await httpRequest<RawEntitlementCheck>(config, {\r\n method: 'GET',\r\n path: '/api/v1/sdk/entitlements/check',\r\n query: { slug: productSlug, feature },\r\n requireAuth: true,\r\n });\r\n const result = toEntitlementCheck(raw);\r\n writeCache(key, result);\r\n return result;\r\n }\r\n\r\n return {\r\n /**\r\n * Verifica se o caller pode usar `feature` no produto `productSlug`.\r\n * Retorno simples: `true` libera, `false` bloqueia. Cache 60s automático.\r\n *\r\n * Use `checkDetailed` se precisar do `reason` pra mensagem de upgrade.\r\n */\r\n async check(\r\n productSlug: string,\r\n feature: string,\r\n opts?: EntitlementsCheckOptions,\r\n ): Promise<boolean> {\r\n const result = await checkDetailed(productSlug, feature, opts);\r\n return result.allowed;\r\n },\r\n checkDetailed,\r\n /** Test helper: limpa o cache LRU. */\r\n __resetCache(): void {\r\n cache.clear();\r\n },\r\n };\r\n}\r\n","/**\r\n * Telemetria — emite eventos do produto cliente pro Core.\r\n *\r\n * APIs disponíveis:\r\n * - `event(input)` — chamada single-shot, await retorna { ok, eventId }.\r\n * `POST /api/sdk/v1/telemetry/event` — persiste em `usage_events/{id}`.\r\n * - `track(input)` — fire-and-forget (v1.2). Enqueue + flush 500ms debounce.\r\n * Reusa o mesmo endpoint mas não bloqueia o caller — ideal pra alta\r\n * frequência (cliques, page-views). Falhas viram warning no console.\r\n * - `flush()` — força flush imediato da queue (chamar antes de unload).\r\n * - `log(input)` — log estruturado `POST /api/sdk/v1/telemetry/log` com\r\n * Bearer + correlationId. Em `NEETRU_ENV=dev` cai pra console.{level}.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type {\r\n ResolvedConfig,\r\n TelemetryEventAck,\r\n TelemetryEventInput,\r\n TelemetryLogAck,\r\n TelemetryLogInput,\r\n TelemetryLogLevel,\r\n} from './types';\r\n\r\ninterface RawTelemetryAck {\r\n ok?: boolean;\r\n eventId?: string;\r\n}\r\n\r\ninterface RawLogAck {\r\n ok?: boolean;\r\n logId?: string;\r\n}\r\n\r\nconst VALID_LOG_LEVELS: readonly TelemetryLogLevel[] = ['debug', 'info', 'warn', 'error', 'fatal'];\r\n\r\nfunction consoleFor(level: TelemetryLogLevel): (message?: unknown, ...optional: unknown[]) => void {\r\n switch (level) {\r\n case 'debug': return console.debug.bind(console);\r\n case 'info': return console.info.bind(console);\r\n case 'warn': return console.warn.bind(console);\r\n case 'error': return console.error.bind(console);\r\n case 'fatal': return console.error.bind(console);\r\n default: return console.log.bind(console);\r\n }\r\n}\r\n\r\n/** Janela de debounce do `track()` antes de drenar a queue. */\r\nconst TRACK_FLUSH_MS = 500;\r\n/** Limite de eventos na queue antes de flush forçado (defensivo). */\r\nconst TRACK_MAX_QUEUE = 50;\r\n\r\nexport function createTelemetryNamespace(config: ResolvedConfig) {\r\n // Queue local pra track() — fire-and-forget batchado.\r\n const queue: TelemetryEventInput[] = [];\r\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\r\n // bug: flush() precisava aguardar drain já em voo p/ não resolver antes do envio\r\n let _inflightDrain: Promise<void> | null = null;\r\n\r\n async function drainQueue(): Promise<void> {\r\n if (queue.length === 0) return;\r\n // (a) Capture the current batch BEFORE the async boundary so that any\r\n // track() call arriving during the await works on a clean queue.\r\n const batch = queue.splice(0, queue.length);\r\n // NOTE: flushTimer is intentionally NOT cleared here. Clearing it before\r\n // the await would let a concurrent track() schedule a second timer, fire\r\n // it while this flush is still in-flight, and produce duplicate concurrent\r\n // drainQueue calls. We clear it only after the await (see below).\r\n const work = Promise.allSettled(\r\n batch.map(async (ev) => {\r\n try {\r\n const body: Record<string, unknown> = { name: ev.name };\r\n if (ev.properties && typeof ev.properties === 'object') {\r\n body.properties = ev.properties;\r\n }\r\n if (ev.timestamp) body.timestamp = ev.timestamp;\r\n await httpRequest<RawTelemetryAck>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/telemetry/event',\r\n body,\r\n requireAuth: true,\r\n retries: 1,\r\n });\r\n } catch (err) {\r\n if (typeof console !== 'undefined') {\r\n console.warn('[neetru-sdk] telemetry.track flush failed for event', ev.name, err);\r\n }\r\n }\r\n }),\r\n );\r\n // Registra promise em voo para que flush() possa aguardar (bug finding 4)\r\n _inflightDrain = work.then(() => { _inflightDrain = null; });\r\n // (b) Release the timer slot AFTER the await so that any track() calls\r\n // that arrived during the flush and called scheduleFlush() were\r\n // correctly suppressed (flushTimer was still set). Now that the\r\n // in-flight requests are done we reset it and, if new events were\r\n // enqueued while we were awaiting, schedule the next flush.\r\n await work;\r\n flushTimer = null;\r\n // (c) If events arrived during the flush window, schedule the next drain.\r\n if (queue.length > 0) {\r\n scheduleFlush();\r\n }\r\n }\r\n\r\n function scheduleFlush(): void {\r\n if (flushTimer) return;\r\n flushTimer = setTimeout(() => {\r\n void drainQueue();\r\n }, TRACK_FLUSH_MS);\r\n }\r\n\r\n return {\r\n /**\r\n * Persiste um evento de uso. Lança `NeetruError` em qualquer falha\r\n * (incluindo rate-limit).\r\n *\r\n * @example\r\n * ```ts\r\n * await client.telemetry.event({\r\n * name: 'dashboard_opened',\r\n * properties: { plan: 'pro', tab: 'overview' },\r\n * });\r\n * ```\r\n */\r\n async event(input: TelemetryEventInput): Promise<TelemetryEventAck> {\r\n if (!input || typeof input !== 'object') {\r\n throw new NeetruError('validation_failed', 'event input is required');\r\n }\r\n if (typeof input.name !== 'string' || input.name.length === 0) {\r\n throw new NeetruError('validation_failed', 'event.name is required');\r\n }\r\n if (input.name.length > 128) {\r\n throw new NeetruError('validation_failed', 'event.name max 128 chars');\r\n }\r\n\r\n const body: Record<string, unknown> = { name: input.name };\r\n if (input.properties && typeof input.properties === 'object') {\r\n body.properties = input.properties;\r\n }\r\n if (input.timestamp) body.timestamp = input.timestamp;\r\n\r\n const raw = await httpRequest<RawTelemetryAck>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/telemetry/event',\r\n body,\r\n requireAuth: true,\r\n });\r\n\r\n if (!raw || raw.ok !== true || typeof raw.eventId !== 'string') {\r\n throw new NeetruError('invalid_response', 'Telemetry response missing eventId');\r\n }\r\n return { ok: true, eventId: raw.eventId };\r\n },\r\n\r\n /**\r\n * Fire-and-forget: enqueue + flush 500ms debounce. Não retorna `eventId`\r\n * — falhas são logadas como warning. Ideal pra alta frequência.\r\n *\r\n * @example\r\n * ```ts\r\n * client.telemetry.track({ name: 'page_view', properties: { path: '/' } });\r\n * // segue execução; flush async em background\r\n * ```\r\n */\r\n track(input: TelemetryEventInput): void {\r\n if (!input || typeof input !== 'object') return;\r\n if (typeof input.name !== 'string' || input.name.length === 0) return;\r\n if (input.name.length > 128) return;\r\n queue.push(input);\r\n if (queue.length >= TRACK_MAX_QUEUE) {\r\n // bug: timer pendente não era cancelado → dois drainQueue() concorrentes\r\n if (flushTimer) { clearTimeout(flushTimer); flushTimer = null; }\r\n void drainQueue();\r\n } else {\r\n scheduleFlush();\r\n }\r\n },\r\n\r\n /**\r\n * Força flush imediato da queue de `track()`. Resolva antes de\r\n * page unload / SSR boundary pra não perder eventos.\r\n */\r\n async flush(): Promise<void> {\r\n if (flushTimer) {\r\n clearTimeout(flushTimer);\r\n flushTimer = null;\r\n }\r\n // bug: flush() resolvia antes do drain já em voo terminar (finding 4)\r\n if (_inflightDrain) await _inflightDrain;\r\n await drainQueue();\r\n },\r\n\r\n /**\r\n * Registra um log estruturado per-product (Sprint 6).\r\n *\r\n * - `NEETRU_ENV=dev`: console.{level}, retorna ack mock.\r\n * - workspace/prod: HTTP POST com Bearer auth + correlationId no header.\r\n *\r\n * @example\r\n * ```ts\r\n * await client.telemetry.log({\r\n * level: 'error',\r\n * message: 'Falha ao calcular total',\r\n * metadata: { orderId: 'o-123' },\r\n * });\r\n * ```\r\n */\r\n async log(input: TelemetryLogInput): Promise<TelemetryLogAck> {\r\n if (!input || typeof input !== 'object') {\r\n throw new NeetruError('validation_failed', 'log input is required');\r\n }\r\n if (!VALID_LOG_LEVELS.includes(input.level)) {\r\n throw new NeetruError('validation_failed', `level must be one of ${VALID_LOG_LEVELS.join(', ')}`);\r\n }\r\n if (typeof input.message !== 'string' || input.message.length === 0) {\r\n throw new NeetruError('validation_failed', 'message is required');\r\n }\r\n if (input.message.length > 4_000) {\r\n throw new NeetruError('validation_failed', 'message max 4000 chars');\r\n }\r\n\r\n // Dev mode: console only, no network.\r\n if (config.env === 'dev') {\r\n const fn = consoleFor(input.level);\r\n fn(`[neetru-sdk] ${input.level}: ${input.message}`, input.metadata ?? {});\r\n return { ok: true, mode: 'mock' };\r\n }\r\n\r\n const body: Record<string, unknown> = {\r\n level: input.level,\r\n message: input.message,\r\n };\r\n if (input.metadata) body.metadata = input.metadata;\r\n // C4 (auditoria 2026-06-10): o Core exige productSlug fail-closed (400 sem\r\n // ele). Quando o consumer não passa explicito, default pro config.productId\r\n // (mesmo contrato de usage.report/support). O backend NÃO infere o slug.\r\n const productSlug = input.productSlug ?? config.productId;\r\n if (productSlug) body.productSlug = productSlug;\r\n\r\n // CorrelationId: explicit input wins; senão tenta lê de globalThis (set\r\n // por instrumentação do consumer).\r\n let cid = input.correlationId;\r\n if (!cid) {\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const g = (globalThis as any).NEETRU_CORRELATION_ID;\r\n if (typeof g === 'string' && g.length > 0) cid = g;\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n\r\n const headers: Record<string, string> = {};\r\n if (cid) headers['x-correlation-id'] = cid;\r\n\r\n const raw = await httpRequest<RawLogAck>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/telemetry/log',\r\n body,\r\n requireAuth: true,\r\n headers,\r\n });\r\n\r\n if (!raw || raw.ok !== true) {\r\n throw new NeetruError('invalid_response', 'Telemetry log response missing ok');\r\n }\r\n return {\r\n ok: true,\r\n logId: typeof raw.logId === 'string' ? raw.logId : undefined,\r\n mode: 'http',\r\n };\r\n },\r\n };\r\n}\r\n","/**\n * Usage namespace — meterar consumo e verificar entitlements (3.0 — breaking).\n *\n * **Mudanças 3.0:**\n * - Paths canônicos `/api/sdk/v1/*` (eram `/sdk/v1/*` errados).\n * - `track(event, props)` **REMOVIDO** — Core não aceita esse shape; era\n * vaporware testado contra mock fetch. Use `report(resource, qty, opts)`.\n * - `getQuota(metric)` **REMOVIDO** — endpoint `/usage/quota` nunca existiu\n * no Core. `report()` já devolve `{value, limit, remaining}` em todo POST.\n * - `report()` e `check()` **agora exigem** `productId` + `tenantId`\n * (no contexto do client OU passados nas options).\n * - `report()` envia `Idempotency-Key` automaticamente (anti dup de\n * incremento em retry transient — Core dedup TTL 24h).\n *\n * Endpoints consumidos:\n * - `POST /api/sdk/v1/usage/record` — `{productId, tenantId, resource, qty}`.\n * Incrementa `usage_counters/{tenantId}_{productId}_{resource}_{yyyymm}.value`.\n * - `GET /api/sdk/v1/entitlements?productId&tenantId&feature` — read-only\n * check de plano + remaining (cache HTTP 60s).\n *\n * Comportamento por env:\n * - `dev` → MockUsage (in-memory, retornado pelo factory).\n * - `workspace`/`prod` → HTTP real.\n */\nimport { NeetruError } from './errors';\nimport { httpRequest } from './http';\nimport { assertValidSdkId } from './validators';\nimport type { ResolvedConfig, UsageNamespace } from './types';\n\nexport function createUsageNamespace(config: ResolvedConfig): UsageNamespace {\n return {\n /**\n * Reporta consumo metered de um resource. Hit no endpoint canônico\n * `POST /api/sdk/v1/usage/record`. Idempotency-Key gerado por chamada;\n * Core dedup serverside TTL 24h.\n *\n * @example\n * ```ts\n * await client.usage.report('api_call', 1);\n * // ou explicit:\n * await client.usage.report('api_call', 5, { productId: 'gestovendas', tenantId: 't-acme' });\n * ```\n */\n async report(\n resource: string,\n qty: number = 1,\n options?: { productId?: string; tenantId?: string },\n ) {\n if (!resource || typeof resource !== 'string') {\n throw new NeetruError('validation_failed', 'resource is required');\n }\n if (!Number.isFinite(qty) || qty <= 0) {\n throw new NeetruError('validation_failed', 'qty must be positive integer');\n }\n const productId = options?.productId ?? config.productId;\n const tenantId = options?.tenantId ?? config.tenantId;\n if (!productId) {\n throw new NeetruError(\n 'validation_failed',\n 'productId required (pass to options or set on createNeetruClient)',\n );\n }\n if (!tenantId) {\n throw new NeetruError(\n 'validation_failed',\n 'tenantId required (pass to options or set on createNeetruClient)',\n );\n }\n // M-03: valida formato canonical (case-insensitive Core já rejeitaria com 400).\n assertValidSdkId('productId', productId);\n assertValidSdkId('tenantId', tenantId);\n\n const raw = await httpRequest<{\n ok?: boolean;\n counterId?: string;\n value?: number;\n limit?: number;\n remaining?: number;\n status?: string;\n }>(config, {\n method: 'POST',\n path: '/api/sdk/v1/usage/record',\n body: { productId, tenantId, resource, qty: Math.floor(qty) },\n requireAuth: true,\n idempotencyKey: true,\n });\n if (!raw || raw.ok !== true) {\n throw new NeetruError('invalid_response', 'usage.report response missing ok');\n }\n return {\n ok: true as const,\n counterId: raw.counterId,\n value: raw.value,\n limit: raw.limit,\n remaining: raw.remaining,\n status: raw.status,\n };\n },\n\n /**\n * Verifica entitlement de um resource via `GET /api/sdk/v1/entitlements`.\n * Resposta inclui `allowed`, `reason` ('granted' | 'not_subscribed' |\n * 'subscription_inactive' | 'feature_not_in_plan' | 'limit_exceeded'),\n * `remaining`, `limit`, `planId`, `planFeatures`.\n */\n async check(\n resource: string,\n options?: { productId?: string; tenantId?: string },\n ) {\n if (!resource || typeof resource !== 'string') {\n throw new NeetruError('validation_failed', 'resource is required');\n }\n const productId = options?.productId ?? config.productId;\n const tenantId = options?.tenantId ?? config.tenantId;\n if (!productId || !tenantId) {\n throw new NeetruError(\n 'validation_failed',\n 'productId and tenantId required (pass to options or set on createNeetruClient)',\n );\n }\n // M-03: valida formato canonical antes do fetch.\n assertValidSdkId('productId', productId);\n assertValidSdkId('tenantId', tenantId);\n\n const raw = await httpRequest<{\n allowed?: boolean;\n reason?: string;\n remaining?: number;\n limit?: number;\n planId?: string | null;\n planFeatures?: string[];\n behavior?: 'readonly' | null;\n }>(config, {\n method: 'GET',\n path: '/api/sdk/v1/entitlements',\n query: { productId, tenantId, feature: resource },\n requireAuth: true,\n });\n if (!raw || typeof raw.allowed !== 'boolean') {\n throw new NeetruError('invalid_response', 'usage.check response missing allowed');\n }\n // Infere behavior='readonly' quando reason='limit_exceeded' e Core\n // ainda não devolve o field explicitamente (vide CORE_CHANGES_REQUIRED §4).\n const behavior =\n raw.behavior ?? (raw.reason === 'limit_exceeded' ? 'readonly' : null);\n return {\n allowed: raw.allowed,\n reason: raw.reason,\n remaining: raw.remaining,\n limit: raw.limit,\n planId: raw.planId,\n planFeatures: raw.planFeatures,\n behavior,\n };\n },\n };\n}\n","/**\n * Validators centralizados pra inputs do SDK que precisam casar com\n * regex do Core.\n *\n * **M-03 fix (Opus review 2026-05-27):** o Core rejeita productId que\n * não bate `/^[a-z0-9][a-z0-9_-]{0,62}$/` com 400 `validation_failed`.\n * O SDK não pré-validava — consumer recebia erro só em runtime de\n * produção, depois do round-trip de rede. Agora SDK throws localmente\n * antes do fetch.\n */\nimport { NeetruError } from './errors';\n\n/**\n * Regex canonical de IDs no Neetru Core (productId, tenantId, etc).\n * Espelha `SDK_ID_RE` em `neetru_core/src/lib/schemas/sdk.ts`.\n */\nexport const SDK_ID_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/;\n\n/**\n * Throws `NeetruError('validation_failed')` se `value` não bater no\n * formato canonical.\n *\n * @example\n * ```ts\n * assertValidSdkId('productId', 'gestovendas'); // ok\n * assertValidSdkId('productId', 'GestoVendas'); // throws\n * ```\n */\nexport function assertValidSdkId(field: string, value: string): void {\n if (typeof value !== 'string' || !SDK_ID_RE.test(value)) {\n throw new NeetruError(\n 'validation_failed',\n `${field} must match ${SDK_ID_RE.source} (lowercase alphanumeric, _, -; first char must be alphanumeric; max 63 chars)`,\n );\n }\n}\n","/**\n * Support namespace — criar e listar tickets via SDK (3.0).\n *\n * **Breaking 3.0**:\n * - Endpoint mudou de `/api/v1/products/{slug}/tickets` (que **NUNCA existiu\n * no Core** — vaporware testado) para `/api/sdk/v1/support/tickets`\n * (canonical SDK path).\n * - `productId` agora é obrigatório no body/query (default resolve do\n * `config.productId`; throw `validation_failed` se ambos ausentes).\n * - `createTicket()` envia `Idempotency-Key` header (anti dup-create\n * em retry transient — Core dedup TTL 24h conforme CORE_CHANGES_REQUIRED §1).\n *\n * **Pré-requisito Core**: endpoint `/api/sdk/v1/support/tickets` (POST + GET)\n * precisa existir no Core antes do SDK 3.0 publish. Vide\n * `docs/CORE_CHANGES_REQUIRED.md` §1 para contrato esperado.\n *\n * Em dev (mocks ativos via factory) tudo é in-memory.\n */\nimport { NeetruError } from './errors';\nimport { httpRequest } from './http';\nimport { assertValidSdkId } from './validators';\nimport type {\n CreateTicketInput,\n ResolvedConfig,\n SupportNamespace,\n SupportSeverity,\n SupportStatus,\n SupportTicket,\n} from './types';\n\nconst VALID_SEVERITIES: readonly SupportSeverity[] = ['low', 'normal', 'high', 'urgent'];\nconst VALID_STATUSES: readonly SupportStatus[] = ['open', 'pending', 'resolved', 'closed'];\n\ninterface RawTicket {\n id?: string;\n productId?: string;\n subject?: string;\n message?: string;\n severity?: string;\n status?: string;\n createdAt?: string;\n updatedAt?: string;\n productSlug?: string;\n}\n\nfunction toTicket(raw: unknown): SupportTicket {\n if (!raw || typeof raw !== 'object') {\n throw new NeetruError('invalid_response', 'Ticket response is not an object');\n }\n const r = raw as RawTicket;\n if (typeof r.id !== 'string') {\n throw new NeetruError('invalid_response', 'Ticket missing id');\n }\n return {\n id: r.id,\n subject: typeof r.subject === 'string' ? r.subject : '',\n message: typeof r.message === 'string' ? r.message : '',\n severity: VALID_SEVERITIES.includes(r.severity as SupportSeverity)\n ? (r.severity as SupportSeverity)\n : 'normal',\n status: VALID_STATUSES.includes(r.status as SupportStatus)\n ? (r.status as SupportStatus)\n : 'open',\n createdAt: typeof r.createdAt === 'string' ? r.createdAt : new Date().toISOString(),\n updatedAt: typeof r.updatedAt === 'string' ? r.updatedAt : undefined,\n productSlug:\n typeof r.productId === 'string'\n ? r.productId\n : typeof r.productSlug === 'string'\n ? r.productSlug\n : undefined,\n };\n}\n\nfunction resolveProductId(\n config: ResolvedConfig,\n ...candidates: Array<string | undefined>\n): string {\n for (const c of candidates) {\n if (typeof c === 'string' && c.length > 0) {\n assertValidSdkId('productSlug', c); // M-03: pré-valida client-side\n return c;\n }\n }\n if (config.productId) {\n assertValidSdkId('productId', config.productId);\n return config.productId;\n }\n throw new NeetruError(\n 'validation_failed',\n 'productId required (pass to input.productSlug or set on createNeetruClient)',\n );\n}\n\nexport function createSupportNamespace(config: ResolvedConfig): SupportNamespace {\n return {\n /**\n * Cria um ticket de suporte. Requer Bearer auth. `productSlug` no input\n * (ou `config.productId` default) vai como `productId` no body do Core.\n *\n * Endpoint canonical: `POST /api/sdk/v1/support/tickets`.\n */\n async createTicket(input: CreateTicketInput): Promise<SupportTicket> {\n if (!input || typeof input !== 'object') {\n throw new NeetruError('validation_failed', 'input is required');\n }\n if (!input.subject || typeof input.subject !== 'string') {\n throw new NeetruError('validation_failed', 'subject is required');\n }\n if (input.subject.length > 200) {\n throw new NeetruError('validation_failed', 'subject max 200 chars');\n }\n if (!input.message || typeof input.message !== 'string') {\n throw new NeetruError('validation_failed', 'message is required');\n }\n if (input.message.length > 10_000) {\n throw new NeetruError('validation_failed', 'message max 10000 chars');\n }\n if (input.severity && !VALID_SEVERITIES.includes(input.severity)) {\n throw new NeetruError(\n 'validation_failed',\n `severity must be one of ${VALID_SEVERITIES.join(', ')}`,\n );\n }\n\n const productId = resolveProductId(config, input.productSlug);\n // M-03: validação acontece dentro de resolveProductId; aqui só usa.\n\n const body: Record<string, unknown> = {\n productId,\n subject: input.subject,\n message: input.message,\n severity: input.severity ?? 'normal',\n };\n\n // L-05 fix: propaga metadata quando consumer enviar.\n if (input.metadata && typeof input.metadata === 'object') {\n body.metadata = input.metadata;\n }\n\n const raw = await httpRequest<RawTicket | { ticket?: RawTicket }>(config, {\n method: 'POST',\n path: '/api/sdk/v1/support/tickets',\n body,\n requireAuth: true,\n idempotencyKey: true,\n });\n\n // Backend pode envelopar como { ticket: {...} } ou retornar direto.\n const candidate =\n raw && typeof raw === 'object' && 'ticket' in raw\n ? (raw as { ticket?: RawTicket }).ticket\n : raw;\n return toTicket(candidate);\n },\n\n /**\n * Lista tickets do customer no produto atual. `productSlug` no contexto.\n *\n * Endpoint canonical: `GET /api/sdk/v1/support/tickets?productId=...`.\n */\n async listMyTickets(options?: { productSlug?: string }): Promise<SupportTicket[]> {\n const productId = resolveProductId(config, options?.productSlug);\n const raw = await httpRequest<{ tickets?: unknown[] } | unknown[]>(config, {\n method: 'GET',\n path: '/api/sdk/v1/support/tickets',\n query: { productId },\n requireAuth: true,\n });\n const list = Array.isArray(raw)\n ? raw\n : raw && typeof raw === 'object' && 'tickets' in raw\n ? ((raw as { tickets?: unknown[] }).tickets ?? [])\n : [];\n return list.map(toTicket);\n },\n };\n}\n","/**\r\n * client-db.ts — Factory do namespace `client.db` (M2 capstone).\r\n *\r\n * Liga os building blocks construídos em M2 em uma superfície unificada\r\n * conforme 02-sdk.md §3.1:\r\n *\r\n * client.db.collection(name) → DbCollectionRef (offline-first, engine-aware)\r\n * client.db.sql(schema) → Promise<NeetruSqlClient>\r\n * client.db.syncState → NeetruSyncState\r\n * client.db.onSyncStateChanged(cb) / flush() / clearCache() / getConflicts()\r\n *\r\n * ## Transport detection\r\n *\r\n * O SDK lê o transport SDK↔Core via:\r\n * 1. Opção explícita `NeetruDbOptions.transport` (injetada pelo product scaffold\r\n * gerado por `neetru db init`, ou pelo `NeetruDbConfig` passado pra\r\n * `createNeetruClient`).\r\n * 2. Fallback legado: `NeetruDbOptions.engine` (depreciado em v2.3, remove em v3.0) —\r\n * emite `console.warn` e usa o valor como `transport`.\r\n * 3. Default: `'rest'` — transporte REST simples (sem realtime nativo;\r\n * compatível com todos os storage engines no MVP, idêntico ao comportamento v1.x).\r\n *\r\n * Transports reconhecidos:\r\n * - `'firestore'` → SyncEngine com FirestoreRealtimeSyncTransport\r\n * - `'nosql-vm'` → SyncEngine com NeetruRealtimeClient como fonte realtime\r\n * - `'rest'` → SyncEngine com FakeRestSyncTransport (REST puro, no-op realtime)\r\n * (default — funciona para cloud-sql-*, vm-postgres-*, etc.)\r\n *\r\n * ## Wiring SQL\r\n *\r\n * `client.db.sql(schema)` delega pra `createSqlClientFromConfig` (src/db/sql/).\r\n * Em dev (`NEETRU_ENV=dev`), retorna um `MockSqlClient` que não abre socket.\r\n *\r\n * ## Backward compatibility com v1.x DbNamespace\r\n *\r\n * O antigo `DbNamespace` (src/db.ts) expunha apenas `collection(name)` retornando\r\n * uma versão REST simples sem offline, sem realtime, sem cursor, sem batch.\r\n * A `NeetruDb` v2.0 É uma breaking change deliberada (major bump):\r\n * - `list()` agora retorna `DbListResult<T>` (com `fromCache`, `stale`, etc.)\r\n * em vez de `T[]`.\r\n * - `db_unavailable` semântica mudou: não significa mais \"sem rede\"\r\n * (offline é transparente), só lifecycle do banco.\r\n * - `batch()`, `onDoc()`, `onSnapshot()`, `doc()`, `sql()` são novos.\r\n *\r\n * Veja CHANGELOG.md §2.0.0 para a lista completa de breaking changes.\r\n *\r\n * @module\r\n */\r\n\r\nimport type { ResolvedConfig } from '../types';\r\nimport { NeetruDbError } from '../db-errors';\r\nimport {\r\n createOfflineDocumentsNamespace,\r\n type NeetruDbDocuments,\r\n type RealtimeTransport,\r\n} from './collection-ref';\r\n// bug_0f836014: createSqlClientFromConfig importa pg + drizzle-orm/node-postgres\r\n// que vazam pro bundle browser (Next.js webpack 'Module not found: fs'). Usamos\r\n// dynamic import dentro do método sql() — server-only contract. Browser bundle\r\n// faz split-chunk e nunca puxa pg em runtime.\r\nimport type { createSqlClientFromConfig as CreateSqlClientFromConfigFn } from './sql/sql-client';\r\nimport type { NeetruSqlClient, SqlOptions } from './sql/types';\r\nimport type { SyncState, ConflictRecord, Unsubscribe, Mutation } from './offline/types';\r\nimport type { PushMutationsResult, PullChangesResult, FullResyncResult } from './offline/sync-engine';\r\nimport { NeetruRealtimeClient } from './realtime/realtime-client';\r\nimport type { TicketProvider } from './realtime/types';\r\n\r\n// ─── Re-exports públicos do módulo db ────────────────────────────────────────\r\n\r\nexport type {\r\n DbCollectionRef,\r\n DbDocRef,\r\n DbQuery,\r\n DbWhereFilter,\r\n DbDoc,\r\n DbListResult,\r\n DbGetResult,\r\n DbBatchOp,\r\n DbChangeType,\r\n NeetruDbDocuments,\r\n RealtimeTransport,\r\n CreateOfflineDocumentsOptions,\r\n WithFieldSentinels,\r\n FieldSentinel,\r\n ServerTimestampSentinel,\r\n IncrementSentinel,\r\n} from './collection-ref';\r\n\r\n// ── Sentinels de escrita server-side (bug_05aedb8b) ──────────────────────────\r\n// `serverTimestamp()` e `increment()` permitem que o produto escreva timestamps\r\n// e contadores resolvidos pelo SERVIDOR — não pelo relógio (spoofável) do cliente.\r\nexport {\r\n serverTimestamp,\r\n increment,\r\n isFieldSentinel,\r\n isServerTimestampSentinel,\r\n isIncrementSentinel,\r\n NEETRU_SENTINEL_KEY,\r\n} from './field-value';\r\n\r\nexport type { NeetruSqlClient, DbSqlLease, SqlOptions } from './sql/types';\r\nexport { NeetruDbError } from '../db-errors';\r\nexport type { NeetruDbErrorCode } from '../db-errors';\r\nexport type { SyncState, ConflictRecord } from './offline/types';\r\n\r\n// ─── Tipos públicos de configuração de DB ────────────────────────────────────\r\n\r\n/**\r\n * Transporte SDK↔Core do banco lógico — determina o protocolo de realtime.\r\n *\r\n * - `'firestore'` — Firestore Web SDK como transporte (memoryLocalCache).\r\n * - `'nosql-vm'` — WebSocket via gateway `neetru-realtime`.\r\n * - `'rest'` — REST puro (default MVP; sem realtime nativo).\r\n *\r\n * Nota: \"transport\" descreve o protocolo SDK↔Core (REST / Firestore / WebSocket).\r\n * Não confundir com \"engine\" de armazenamento do admin database (firestore-instance,\r\n * cloud-sql-postgres, vm-postgres-single…), que é uma configuração do Core —\r\n * um storage engine pode ser acessado por vários SDK transports.\r\n *\r\n * O produto NUNCA vê a diferença de transporte — o comportamento offline\r\n * é idêntico nos dois transportes de Documentos (02-sdk.md §3.7).\r\n */\r\nexport type NeetruDbTransport = 'firestore' | 'nosql-vm' | 'rest';\r\n\r\n/**\r\n * @deprecated Use `NeetruDbTransport`. Este alias será removido em v3.0.\r\n *\r\n * O nome \"engine\" colide com o conceito de storage engine do admin database\r\n * (firestore-instance, cloud-sql-postgres, vm-postgres-single…).\r\n * No contexto do SDK, o campo configura o TRANSPORTE (REST/Firestore/WebSocket),\r\n * não o engine de armazenamento. Use `transport` em vez de `engine`.\r\n */\r\nexport type NeetruDbEngine = NeetruDbTransport;\r\n\r\n/**\r\n * Opções de configuração do banco lógico.\r\n *\r\n * Normalmente geradas pelo scaffold `neetru db init` em `db/client.ts`.\r\n * Em testes, injetar diretamente.\r\n */\r\nexport interface NeetruDbOptions {\r\n /**\r\n * ID opaco do banco lógico — emitido pelo Core em `POST /api/sdk/v1/db`.\r\n * Necessário para o lease SQL e para scoping das coleções.\r\n */\r\n dbId?: string;\r\n\r\n /**\r\n * Transporte SDK↔Core — determina o protocolo de realtime.\r\n * Default: `'rest'` (MVP — funciona para todos os storage engines SQL e Documentos).\r\n *\r\n * Valores:\r\n * - `'rest'` — REST puro (sem realtime nativo; compatível com todos os storage engines).\r\n * - `'firestore'` — Firestore Web SDK como transporte (memoryLocalCache).\r\n * - `'nosql-vm'` — WebSocket via gateway `neetru-realtime`.\r\n *\r\n * Não confundir com o storage engine do admin database (firestore-instance,\r\n * cloud-sql-postgres, vm-postgres-single…). Um storage engine pode ser acessado\r\n * por vários transports SDK (ex.: cloud-sql-postgres funciona com transport='rest').\r\n */\r\n transport?: NeetruDbTransport;\r\n\r\n /**\r\n * @deprecated Use `transport` em vez de `engine`. Será removido em v3.0.\r\n *\r\n * O nome \"engine\" colide com o conceito de storage engine do admin database\r\n * (firestore-instance, cloud-sql-postgres, vm-postgres-single…).\r\n * Se `transport` e `engine` forem passados simultaneamente, `transport` prevalece.\r\n */\r\n engine?: NeetruDbEngine;\r\n\r\n /**\r\n * Opções do transporte Firestore (somente quando `transport === 'firestore'`).\r\n * O `firestore` handle (inicializado com `memoryLocalCache`) é injetado aqui.\r\n *\r\n * Injeção explícita — o SDK não importa `firebase/firestore` diretamente\r\n * para não poluir o bundle de quem não usa este transporte.\r\n */\r\n firestoreTransport?: RealtimeTransport;\r\n\r\n /**\r\n * Opções do transporte WebSocket (somente quando `transport === 'nosql-vm'`).\r\n * URL do gateway `neetru-realtime`.\r\n */\r\n realtimeGatewayUrl?: string;\r\n\r\n /**\r\n * Coleções declaradas pelo produto — necessário para pullChanges/fullResync\r\n * com os transportes Firestore e nosql-vm.\r\n *\r\n * Default: `[]` (o SyncEngine sincroniza coleções conforme são acessadas).\r\n */\r\n collections?: string[];\r\n\r\n /**\r\n * Nome do banco IndexedDB. Convenção: `neetru-db__{productSlug}__{dbId}__{env}`.\r\n * Gerado automaticamente se ausente.\r\n */\r\n dbName?: string;\r\n\r\n /**\r\n * `true` = sem contenção multi-aba (sempre líder).\r\n * Padrão em SSR/testes; em produção usa Web Locks.\r\n */\r\n singleTab?: boolean;\r\n\r\n /**\r\n * Transporte de sync customizado (injetado em testes).\r\n * Se presente, sobrepõe a detecção por `transport`.\r\n */\r\n _transport?: RealtimeTransport;\r\n\r\n /**\r\n * Factory de WebSocket injetável (somente quando `transport === 'nosql-vm'`).\r\n * Default: `(url) => new WebSocket(url)`.\r\n * Injetar em testes para evitar rede real.\r\n */\r\n _wsFactory?: import('./realtime/types').WebSocketFactory;\r\n}\r\n\r\n// ─── NeetruDb — interface pública completa (02-sdk.md §3.1) ─────────────────\r\n\r\n/**\r\n * Superfície pública do namespace `client.db` — alinhada com 02-sdk.md §3.1.\r\n *\r\n * ```ts\r\n * const client = createNeetruClient({ ... });\r\n *\r\n * // Mundo Documentos (offline-first):\r\n * const orders = client.db.collection<Order>('orders');\r\n * await orders.add({ ... });\r\n * orders.onSnapshot(query, snap => renderOrders(snap.docs));\r\n *\r\n * // Mundo SQL (lease + pg.Pool + Drizzle):\r\n * const sql = await client.db.sql(schema);\r\n * const rows = await sql.orm.select().from(schema.orders);\r\n *\r\n * // Camada offline:\r\n * const state = client.db.syncState;\r\n * client.db.onSyncStateChanged(s => console.log(s.pendingWrites));\r\n * await client.db.flush(); // força sync\r\n * ```\r\n */\r\nexport interface NeetruDb {\r\n // ── Mundo Documentos ──────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna uma `DbCollectionRef` para a coleção `name`.\r\n *\r\n * Offline-first: reads vêm do cache local; writes são aplicados\r\n * otimisticamente e enfileirados para sync. Engine-aware: o transporte\r\n * realtime é selecionado automaticamente pelo `engine` configurado.\r\n */\r\n collection<T = Record<string, unknown>>(\r\n name: string,\r\n ): import('./collection-ref').DbCollectionRef<T>;\r\n\r\n // ── Mundo SQL ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Abre o handle SQL: busca o lease no Core, abre o `pg.Pool`, cria o\r\n * handle Drizzle tipado pelo `schema`. Operação async, 1x no startup.\r\n *\r\n * Em `NEETRU_ENV=dev`, retorna um `MockSqlClient` que não abre socket.\r\n *\r\n * @param schema — Schema Drizzle do produto (`pgTable(...)` em `db/schema.ts`).\r\n * @param options — Opções opcionais (contrato C-H).\r\n * `options.database` desambigua quando o produto tem N>1 bancos SQL.\r\n * Quando omitido, o Core resolve o banco padrão/homônimo do produto.\r\n *\r\n * @example\r\n * ```ts\r\n * import * as schema from './db/schema';\r\n * // banco padrão (único ou homônimo):\r\n * export const db = await client.db.sql(schema);\r\n * // banco específico entre N bancos SQL:\r\n * export const analytics = await client.db.sql(schema, { database: 'analytics' });\r\n * ```\r\n */\r\n sql<TSchema extends Record<string, unknown>>(\r\n schema: TSchema,\r\n options?: SqlOptions,\r\n ): Promise<NeetruSqlClient<TSchema>>;\r\n\r\n // ── Camada offline (Mundo Documentos) ────────────────────────────────────\r\n\r\n /** Estado atual de sincronização da camada offline. */\r\n readonly syncState: SyncState;\r\n\r\n /**\r\n * Subscreve a mudanças de `SyncState`.\r\n * Retorna função de unsubscribe.\r\n */\r\n onSyncStateChanged(cb: (s: SyncState) => void): Unsubscribe;\r\n\r\n /**\r\n * Força flush da fila de mutações pendentes.\r\n * Útil antes de um `beforeunload` ou shutdown do produto.\r\n */\r\n flush(): Promise<void>;\r\n\r\n /**\r\n * Limpa o cache local (IndexedDB) — operação destrutiva.\r\n * Use com cuidado: dados não sincronizados serão perdidos.\r\n */\r\n clearCache(): Promise<void>;\r\n\r\n /**\r\n * Retorna os registros de conflito LWW pendentes de entrega.\r\n * Permite ao produto inspecionar escritas perdidas.\r\n */\r\n getConflicts(): Promise<ConflictRecord[]>;\r\n}\r\n\r\n// ─── Endpoints do Core para o transporte REST ─────────────────────────────────\r\n\r\n/** Endpoint de push de mutações (criação de documento). */\r\nconst DATASTORE_COLLECTION_ENDPOINT = (collection: string) =>\r\n `/api/sdk/v1/datastore/${encodeURIComponent(collection)}`;\r\n\r\n/** Endpoint de mutação num documento específico (update/set/delete). */\r\nconst DATASTORE_DOC_ENDPOINT = (collection: string, docId: string) =>\r\n `/api/sdk/v1/datastore/${encodeURIComponent(collection)}/${encodeURIComponent(docId)}`;\r\n\r\n// Note: DATASTORE_COLLECTION_ENDPOINT is reused for both add (POST) and list (GET)\r\n\r\n// ─── Transport detection ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * Seleciona o `RealtimeTransport` com base no transport configurado.\r\n *\r\n * Implementa o seam de injeção de 02-sdk.md §3.7.\r\n *\r\n * Regras:\r\n * 1. Se `opts._transport` foi injetado explicitamente (testes) → usa.\r\n * 2. `transport === 'firestore'` e `opts.firestoreTransport` presente → usa.\r\n * 3. `transport === 'nosql-vm'` e `opts.realtimeGatewayUrl` presente →\r\n * cria adapter WebSocket com push/pull REST + RealtimeClient para subscriptions.\r\n * 4. Qualquer outro caso → `RestSyncTransport` (REST real com `config`).\r\n */\r\nfunction resolveTransport(\r\n transport: NeetruDbTransport,\r\n opts: NeetruDbOptions,\r\n config: ResolvedConfig,\r\n): RealtimeTransport {\r\n // 1. Injeção explícita (testes / mocks avançados)\r\n if (opts._transport) {\r\n return opts._transport;\r\n }\r\n\r\n // 2. Transport Firestore — transporte já montado pelo produto\r\n if (transport === 'firestore') {\r\n if (opts.firestoreTransport) {\r\n return opts.firestoreTransport;\r\n }\r\n // Firestore sem transporte injetado → cai para REST real\r\n }\r\n\r\n // 3. Transport nosql-vm — writes via REST real + realtime via NeetruRealtimeClient\r\n if (transport === 'nosql-vm' && opts.realtimeGatewayUrl) {\r\n return createWebSocketSyncTransport(opts.realtimeGatewayUrl, config, opts);\r\n }\r\n\r\n // 4. Default: REST real (funciona para SQL, Firestore sem injeção, nosql-vm sem URL)\r\n return createRestSyncTransport(config);\r\n}\r\n\r\n// ─── RestSyncTransport (default) ─────────────────────────────────────────────\r\n\r\n/**\r\n * Transporte REST puro — usa os endpoints `/api/sdk/v1/datastore/*` do Core.\r\n *\r\n * BL-2 fix: `pushMutations` agora chama o Core de verdade via `httpRequest`.\r\n * Sem `config`, lança `NeetruDbError('db_unavailable')` — NUNCA retorna\r\n * `confirmed` para uma escrita que não foi enviada.\r\n *\r\n * - `pushMutations` → POST/PATCH/PUT/DELETE `/api/sdk/v1/datastore/{coll}/{id}`\r\n * - `pullChanges` → GET `/api/sdk/v1/datastore/{coll}` (best-effort por coleção)\r\n * - `fullResync` → GET por coleção (lista completa)\r\n *\r\n * Exportado para testes.\r\n */\r\nexport function createRestSyncTransport(\r\n config?: ResolvedConfig,\r\n): RealtimeTransport {\r\n return {\r\n async pushMutations(mutations: Mutation[]): Promise<PushMutationsResult> {\r\n if (!config) {\r\n // BL-2: fail-closed — sem config não há como enviar ao Core.\r\n // Lançar em vez de retornar `confirmed` silenciosamente.\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n '[RestSyncTransport] config não disponível — não é possível enviar ao Core. ' +\r\n 'Inicialize o transporte via createNeetruDb.',\r\n );\r\n }\r\n\r\n const { httpRequest } = await import('../http');\r\n const results: PushMutationsResult['results'] = [];\r\n\r\n // HIGH-2: o datastore do Core requer x-neetru-tenant. O mundo Documentos\r\n // é scoped por produto, não por tenant. Quando tenantId está ausente mas\r\n // productId existe, usamos productId como tenant-scope — o Core namespeia\r\n // a coleção como `tenant_{id}_{collection}`, isolando dados por produto.\r\n // tenantId explícito sempre tem prioridade (cenários multi-tenant).\r\n const tenantScopeId = config.tenantId ?? config.productId;\r\n const tenantHeaders: Record<string, string> | undefined = tenantScopeId\r\n ? { 'x-neetru-tenant': tenantScopeId }\r\n : undefined;\r\n\r\n for (const m of mutations) {\r\n try {\r\n let raw: unknown;\r\n if (m.op === 'add') {\r\n // POST /datastore/{collection} → { ok, id }\r\n // MED-1: add é não-idempotente — NÃO retryar (retries: 0).\r\n // Uma resposta perdida após escrita bem-sucedida causaria doc duplicado.\r\n // Para idempotência futura, considere enviar m.docId como x-neetru-doc-id.\r\n raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: DATASTORE_COLLECTION_ENDPOINT(m.collection),\r\n body: { data: m.payload ?? {} },\r\n requireAuth: true,\r\n retries: 0,\r\n headers: tenantHeaders,\r\n });\r\n } else if (m.op === 'set') {\r\n // PUT /datastore/{collection}/{docId} → { ok, id }\r\n // set é idempotente por docId — retry seguro.\r\n raw = await httpRequest<unknown>(config, {\r\n method: 'PUT',\r\n path: DATASTORE_DOC_ENDPOINT(m.collection, m.docId),\r\n body: { data: m.payload ?? {} },\r\n requireAuth: true,\r\n retries: 2,\r\n headers: tenantHeaders,\r\n });\r\n } else if (m.op === 'update') {\r\n // PATCH /datastore/{collection}/{docId} → { ok, id }\r\n // update (merge) com mesmo payload é idempotente por docId — retry seguro.\r\n raw = await httpRequest<unknown>(config, {\r\n method: 'PATCH',\r\n path: DATASTORE_DOC_ENDPOINT(m.collection, m.docId),\r\n body: { data: m.payload ?? {} },\r\n requireAuth: true,\r\n retries: 2,\r\n headers: tenantHeaders,\r\n });\r\n } else {\r\n // remove — DELETE /datastore/{collection}/{docId}\r\n // delete é idempotente — retry seguro.\r\n raw = await httpRequest<unknown>(config, {\r\n method: 'DELETE',\r\n path: DATASTORE_DOC_ENDPOINT(m.collection, m.docId),\r\n requireAuth: true,\r\n retries: 2,\r\n headers: tenantHeaders,\r\n });\r\n }\r\n\r\n const resp = raw as { ok?: boolean; id?: string; serverVersion?: string } | undefined;\r\n results.push({\r\n mutationId: m.mutationId,\r\n outcome: 'confirmed',\r\n serverVersion: resp?.serverVersion ?? resp?.id ?? `rest_${Date.now()}`,\r\n serverTimestamp: Date.now(),\r\n });\r\n } catch (err) {\r\n // Muta para NeetruDbError para sinalizar falha persistente.\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new NeetruDbError('db_unavailable', `pushMutations falhou: ${msg}`);\r\n }\r\n }\r\n\r\n return { results };\r\n },\r\n\r\n async pullChanges(\r\n _watermark: number | null,\r\n _resumeToken: string | null,\r\n ): Promise<PullChangesResult> {\r\n if (!config) {\r\n // Sem config, não há como consultar o Core — retorna vazio sem crash.\r\n return { docs: [], newWatermark: Date.now(), resyncRequired: false };\r\n }\r\n // C3 (auditoria 2026-06-10): o endpoint REST do Core (`GET /datastore/{coll}`)\r\n // NÃO tem change-feed/delta server-side (sem `?since=<watermark>`). A única\r\n // estratégia correta é sinalizar resyncRequired → o SyncEngine chama\r\n // fullResync, que faz GET por coleção e reconcilia o estado completo.\r\n // Seguro: fullResync é idempotente e barato pro transporte REST (sem\r\n // listener Firestore). Antes: stub vazio → cliente novo NUNCA puxava dados.\r\n return { docs: [], newWatermark: Date.now(), resyncRequired: true };\r\n },\r\n\r\n async fullResync(collections: string[]): Promise<FullResyncResult> {\r\n if (!config) {\r\n return { docs: [], newWatermark: Date.now() };\r\n }\r\n\r\n const { httpRequest } = await import('../http');\r\n\r\n // Mesma convenção de pushMutations: tenantId tem prioridade sobre productId.\r\n const tenantScopeId = config.tenantId ?? config.productId;\r\n const tenantHeaders: Record<string, string> | undefined = tenantScopeId\r\n ? { 'x-neetru-tenant': tenantScopeId }\r\n : undefined;\r\n\r\n const now = Date.now();\r\n const docs: import('./offline/sync-engine').ServerDoc[] = [];\r\n\r\n for (const collection of collections) {\r\n let raw: unknown;\r\n try {\r\n raw = await httpRequest<unknown>(config, {\r\n method: 'GET',\r\n path: DATASTORE_COLLECTION_ENDPOINT(collection),\r\n requireAuth: true,\r\n retries: 2,\r\n headers: tenantHeaders,\r\n // Teto do Core é 200. Coleções > 200 docs truncam silenciosamente\r\n // aqui (paginação cursor é tarefa Core separada) — a detecção de\r\n // deleção-por-ausência do SyncEngine NÃO deve rodar sobre truncamento,\r\n // então mantemos o limite no máximo do servidor por ora.\r\n query: { limit: 200 },\r\n });\r\n } catch (err) {\r\n // Falha numa coleção aborta o resync inteiro; o SyncEngine captura e\r\n // re-tenta o ciclo (não corrompe o cache local).\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n `[RestSyncTransport] fullResync falhou na coleção \"${collection}\": ${msg}`,\r\n );\r\n }\r\n\r\n const resp = raw as { items?: unknown[] } | undefined;\r\n const items = Array.isArray(resp?.items) ? resp.items : [];\r\n\r\n for (const item of items) {\r\n if (!item || typeof item !== 'object') continue;\r\n const record = item as Record<string, unknown>;\r\n\r\n // O Core inlina `id` no objeto de dados; ServerDoc exige id separado.\r\n const id = typeof record['id'] === 'string' ? record['id'] : null;\r\n if (!id) continue;\r\n const { id: _inlinedId, ...data } = record;\r\n\r\n // serverTimestamp a partir de `_updatedAt` (Core carimba via\r\n // FieldValue.serverTimestamp()). Sobre REST chega como número, objeto\r\n // Firestore { _seconds, _nanoseconds } ou ISO — normaliza p/ epoch ms.\r\n // Fallback `now` é seguro pra LWW (todos tratados como atuais).\r\n let serverTimestamp = now;\r\n const updatedAt = data['_updatedAt'];\r\n if (typeof updatedAt === 'number') {\r\n serverTimestamp = updatedAt;\r\n } else if (\r\n updatedAt !== null &&\r\n typeof updatedAt === 'object' &&\r\n typeof (updatedAt as Record<string, unknown>)['_seconds'] === 'number'\r\n ) {\r\n serverTimestamp = (updatedAt as Record<string, number>)['_seconds'] * 1000;\r\n } else if (typeof updatedAt === 'string') {\r\n const parsed = Date.parse(updatedAt);\r\n if (!Number.isNaN(parsed)) serverTimestamp = parsed;\r\n }\r\n\r\n // O REST do Core não expõe ETag/versão — etag opaco determinístico.\r\n const serverVersion = `rest_${id}_${serverTimestamp}`;\r\n\r\n docs.push({\r\n collection,\r\n id,\r\n data: data as Record<string, unknown>,\r\n serverVersion,\r\n serverTimestamp,\r\n deleted: false,\r\n });\r\n }\r\n }\r\n\r\n return { docs, newWatermark: now };\r\n },\r\n };\r\n}\r\n\r\n// ─── WebSocket SyncTransport (nosql-vm) ──────────────────────────────────────\r\n\r\n/**\r\n * Adapter entre `NeetruRealtimeClient` (WebSocket) e `SyncTransport`.\r\n *\r\n * BL-2 fix: `pushMutations` agora delega ao REST real (via `createRestSyncTransport`)\r\n * — o gateway WS é somente para leitura/realtime.\r\n *\r\n * H-10 fix: `getWebSocketRealtimeClient` é chamado aqui com um `ticketProvider`\r\n * real que chama `POST /api/sdk/v1/db/realtime/ticket` via HTTP do SDK.\r\n *\r\n * HIGH-1 fix: implementa `subscribeCollection` para que `DbCollectionRefImpl.onSnapshot`\r\n * registre subscriptions realtime via `NeetruRealtimeClient.subscribe()`.\r\n * Frames `delta` do gateway são traduzidos para changes e entregues ao callback.\r\n * Frames `resync` sinalizam `needsResync: true` para que o SyncEngine recarregue.\r\n */\r\nfunction createWebSocketSyncTransport(\r\n gatewayUrl: string,\r\n config: ResolvedConfig,\r\n opts: NeetruDbOptions,\r\n): RealtimeTransport {\r\n // Writes vão pelo REST real — o gateway WS é somente realtime/read.\r\n const restTransport = createRestSyncTransport(config);\r\n\r\n // HIGH-1: cria e retém o NeetruRealtimeClient para reutilização nas subscriptions.\r\n const realtimeClient = new NeetruRealtimeClient({\r\n gatewayUrl,\r\n ticketProvider: buildTicketProvider(config, opts),\r\n dbId: opts.dbId,\r\n webSocketFactory: opts._wsFactory,\r\n });\r\n\r\n return {\r\n pushMutations: restTransport.pushMutations.bind(restTransport),\r\n pullChanges: restTransport.pullChanges.bind(restTransport),\r\n fullResync: restTransport.fullResync.bind(restTransport),\r\n\r\n // HIGH-1: subscribeCollection — chamado por DbCollectionRefImpl.onSnapshot\r\n // quando o engine é nosql-vm. Registra a subscription no NeetruRealtimeClient\r\n // e traduz os frames inbound para o contrato de `onChange`.\r\n subscribeCollection(\r\n collection: string,\r\n onChange: (\r\n changes: Array<{ type: 'added' | 'modified' | 'removed'; docId: string; data: Record<string, unknown> | null }>,\r\n needsResync: boolean,\r\n ) => void,\r\n ): () => void {\r\n const subId = realtimeClient.subscribe(collection, {}, (frame) => {\r\n if (frame.op === 'resync') {\r\n onChange([], true);\r\n return;\r\n }\r\n if (frame.op === 'stale') {\r\n // Sinaliza que o cache pode estar desatualizado — pede resync.\r\n onChange([], true);\r\n return;\r\n }\r\n if (frame.op === 'delta' && frame.changes) {\r\n const changes = frame.changes.map((c) => ({\r\n type: (\r\n c.type === 'insert' ? 'added'\r\n : c.type === 'delete' ? 'removed'\r\n : 'modified'\r\n ) as 'added' | 'modified' | 'removed',\r\n docId: c.documentId,\r\n data: c.data ?? null,\r\n }));\r\n if (changes.length > 0) {\r\n onChange(changes, false);\r\n }\r\n }\r\n // 'error' e 'pong' são ignorados aqui; pong é tratado pelo heartbeat interno.\r\n });\r\n\r\n return () => {\r\n realtimeClient.unsubscribe(subId);\r\n };\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Constrói o `TicketProvider` real para o engine `nosql-vm` (H-10 fix).\r\n *\r\n * Chama `POST /api/sdk/v1/db/realtime/ticket` via a camada HTTP do SDK com\r\n * o `productId` resolvido do config.\r\n */\r\nfunction buildTicketProvider(\r\n config: ResolvedConfig,\r\n opts: NeetruDbOptions,\r\n): TicketProvider {\r\n return async () => {\r\n const { httpRequest } = await import('../http');\r\n const ticket = await httpRequest<{\r\n ticketId: string;\r\n token: string;\r\n expiresAt: string;\r\n ttlMs: number;\r\n }>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/db/realtime/ticket',\r\n body: {\r\n productId: config.productId ?? '',\r\n collections: opts.collections ?? ['*'],\r\n },\r\n requireAuth: true,\r\n retries: 1,\r\n });\r\n return ticket;\r\n };\r\n}\r\n\r\n/**\r\n * Retorna o `NeetruRealtimeClient` para uso em `subscribeRealtime` fora do\r\n * `SyncTransport` (extensão nosql-vm — não faz parte do contrato base).\r\n *\r\n * H-10 fix: agora aceita um `dbId` opcional que é passado para o cliente\r\n * (BL-8 — o cliente embute `_dbId` nos frames de subscribe).\r\n *\r\n * @param gatewayUrl URL do gateway WebSocket.\r\n * @param ticketProvider Provedor de ticket obrigatório.\r\n * @param dbId ID do banco lógico (BL-8).\r\n * @param wsFactory Factory de WebSocket injetável (testes).\r\n */\r\nexport function getWebSocketRealtimeClient(\r\n gatewayUrl: string,\r\n ticketProvider: TicketProvider,\r\n dbId?: string,\r\n wsFactory?: import('./realtime/types').WebSocketFactory,\r\n) {\r\n return new NeetruRealtimeClient({ gatewayUrl, ticketProvider, dbId, webSocketFactory: wsFactory });\r\n}\r\n\r\n// ─── Factory pública ─────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Cria o namespace `client.db` completo.\r\n *\r\n * **Factory única** — `createNeetruDb` é a única factory pública.\r\n * O split sync/async é um detalhe de implementação interno: o `NeetruDb`\r\n * retornado inicializa a camada offline (IndexedDB) de forma lazy na\r\n * primeira operação real, portanto:\r\n *\r\n * - Pode ser chamado de contextos síncronos (como `createNeetruClient`).\r\n * - Pode ser chamado com `await` quando se deseja garantir que o store\r\n * esteja aquecido antes da primeira op (equivalente a chamar `flush()`).\r\n * - `client.db.flush()` garante que o IndexedDB está aberto.\r\n *\r\n * @param config — config resolvida do cliente (apiKey, baseUrl, env, etc.)\r\n * @param dbOpts — opções do banco lógico (engine, dbId, collections, etc.)\r\n *\r\n * @example\r\n * ```ts\r\n * // Uso síncrono (dentro de createNeetruClient):\r\n * const db = createNeetruDb(resolved, config.db);\r\n *\r\n * // Uso com await (quando se quer garantir warmup):\r\n * const db = await createNeetruDb(resolved, config.db);\r\n * await db.flush(); // opcional — já está aquecido\r\n *\r\n * // O produto usa:\r\n * const orders = db.collection<Order>('orders');\r\n * const sqlDb = await db.sql(schema);\r\n * ```\r\n */\r\nexport function createNeetruDb(\r\n config: ResolvedConfig,\r\n dbOpts: NeetruDbOptions = {},\r\n): NeetruDb {\r\n // Backwards compat: `transport` (v2.3+) takes precedence over deprecated `engine` (v2.x).\r\n // If only `engine` is supplied, emit a deprecation warning and use its value.\r\n let resolvedTransport: NeetruDbTransport;\r\n if (dbOpts.transport !== undefined) {\r\n resolvedTransport = dbOpts.transport;\r\n } else if (dbOpts.engine !== undefined) {\r\n console.warn(\r\n '[neetru/sdk] NeetruDbOptions.engine está depreciado e será removido em v3.0. ' +\r\n 'Use NeetruDbOptions.transport em vez de engine. ' +\r\n 'Valores válidos: \"rest\" | \"firestore\" | \"nosql-vm\". ' +\r\n 'Nota: \"engine\" no SDK configura o TRANSPORTE (REST/Firestore/WebSocket), ' +\r\n 'não o storage engine do admin database (firestore-instance, cloud-sql-postgres, …).',\r\n );\r\n resolvedTransport = dbOpts.engine;\r\n } else {\r\n resolvedTransport = 'rest';\r\n }\r\n const transport = resolveTransport(resolvedTransport, dbOpts, config);\r\n\r\n // Gera um dbName único por produto × dbId × env\r\n const dbId = dbOpts.dbId ?? 'default';\r\n const dbName =\r\n dbOpts.dbName ??\r\n `neetru-db__${config.productId ?? 'sdk'}__${dbId}__${config.env}`;\r\n\r\n // Promise de inicialização — lazy: só dispara na primeira operação real\r\n let _docsPromise: Promise<NeetruDbDocuments> | null = null;\r\n let _docsResolved: NeetruDbDocuments | null = null;\r\n\r\n function getDocsPromise(): Promise<NeetruDbDocuments> {\r\n if (!_docsPromise) {\r\n _docsPromise = createOfflineDocumentsNamespace({\r\n dbName,\r\n transport,\r\n singleTab: dbOpts.singleTab ?? (config.env !== 'prod'),\r\n }).then((docs) => {\r\n _docsResolved = docs;\r\n return docs;\r\n });\r\n }\r\n return _docsPromise;\r\n }\r\n\r\n // Namespace lazy — inicializa o store na primeira operação\r\n return {\r\n collection<T = Record<string, unknown>>(\r\n name: string,\r\n ): import('./collection-ref').DbCollectionRef<T> {\r\n // Se já resolvido, usa diretamente; caso contrário inicia\r\n if (_docsResolved) return _docsResolved.collection<T>(name);\r\n\r\n // Retorna um DbCollectionRef que awaita o namespace antes de cada op.\r\n // A inicialização do IndexedDB é lazy — só dispara na primeira operação\r\n // real (list/get/add/…), não na chamada a collection() em si.\r\n return createLazyCollectionRef<T>(name, getDocsPromise);\r\n },\r\n\r\n async sql<TSchema extends Record<string, unknown>>(\r\n schema: TSchema,\r\n options?: SqlOptions,\r\n ): Promise<NeetruSqlClient<TSchema>> {\r\n if (config.env === 'dev') {\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n '[SDK] db.sql() não disponível em NEETRU_ENV=dev. ' +\r\n 'Use `neetru dev` para subir o container Postgres local.',\r\n );\r\n }\r\n // bug_0f836014: dynamic import — browser bundle nunca puxa pg/drizzle node.\r\n // sql() é server-only por design (precisa pg.Pool TCP socket). Webpack\r\n // do consumer Next.js split-chunks esse import, mas só fetcha em runtime\r\n // quando .sql() é chamado — que nunca acontece em browser.\r\n const sqlClientMod: { createSqlClientFromConfig: typeof CreateSqlClientFromConfigFn } =\r\n await import('./sql/sql-client');\r\n return sqlClientMod.createSqlClientFromConfig(config, schema, options);\r\n },\r\n\r\n get syncState(): SyncState {\r\n return _docsResolved?.syncState ?? {\r\n status: 'idle',\r\n pendingWrites: 0,\r\n lastSyncedAt: null,\r\n isLeaderTab: false,\r\n };\r\n },\r\n\r\n onSyncStateChanged(cb: (s: SyncState) => void) {\r\n if (_docsResolved) return _docsResolved.onSyncStateChanged(cb);\r\n // Aguarda init e então subscreve\r\n let unsub: Unsubscribe | null = null;\r\n let cancelled = false;\r\n getDocsPromise().then((docs) => {\r\n if (!cancelled) {\r\n unsub = docs.onSyncStateChanged(cb);\r\n }\r\n });\r\n return () => {\r\n cancelled = true;\r\n unsub?.();\r\n };\r\n },\r\n\r\n async flush(): Promise<void> {\r\n const docs = await getDocsPromise();\r\n return docs.flush();\r\n },\r\n\r\n async clearCache(): Promise<void> {\r\n const docs = await getDocsPromise();\r\n return docs.clearCache();\r\n },\r\n\r\n async getConflicts(): Promise<ConflictRecord[]> {\r\n const docs = await getDocsPromise();\r\n return docs.getConflicts();\r\n },\r\n };\r\n}\r\n\r\n// ─── Lazy DbCollectionRef ─────────────────────────────────────────────────────\r\n\r\n/**\r\n * Cria um `DbCollectionRef` que aguarda a inicialização do namespace antes de\r\n * qualquer operação. Permite que `createNeetruDb` retorne um ref imediato\r\n * mesmo que o IndexedDB ainda não esteja aberto (lazy-init).\r\n */\r\nfunction createLazyCollectionRef<T = Record<string, unknown>>(\r\n name: string,\r\n getDocsPromise: () => Promise<NeetruDbDocuments>,\r\n): import('./collection-ref').DbCollectionRef<T> {\r\n async function getRef(): Promise<import('./collection-ref').DbCollectionRef<T>> {\r\n const docs = await getDocsPromise();\r\n return docs.collection<T>(name);\r\n }\r\n\r\n return {\r\n async get(id: string) {\r\n return (await getRef()).get(id);\r\n },\r\n async list(q) {\r\n return (await getRef()).list(q);\r\n },\r\n async add(data) {\r\n return (await getRef()).add(data);\r\n },\r\n async set(id, data) {\r\n return (await getRef()).set(id, data);\r\n },\r\n async update(id, data) {\r\n return (await getRef()).update(id, data);\r\n },\r\n async remove(id) {\r\n return (await getRef()).remove(id);\r\n },\r\n async batch(ops) {\r\n return (await getRef()).batch(ops);\r\n },\r\n onDoc(id, cb) {\r\n let unsub: Unsubscribe | null = null;\r\n let cancelled = false;\r\n getRef().then((ref) => {\r\n if (!cancelled) {\r\n unsub = ref.onDoc(id, cb);\r\n }\r\n });\r\n return () => {\r\n cancelled = true;\r\n unsub?.();\r\n };\r\n },\r\n onSnapshot(q, cb) {\r\n let unsub: Unsubscribe | null = null;\r\n let cancelled = false;\r\n getRef().then((ref) => {\r\n if (!cancelled) {\r\n unsub = ref.onSnapshot(q, cb);\r\n }\r\n });\r\n return () => {\r\n cancelled = true;\r\n unsub?.();\r\n };\r\n },\r\n doc(id) {\r\n // Lazy doc ref — expõe id/path/collection imediatamente (sem aguardar init)\r\n return {\r\n get id(): string { return id; },\r\n get path(): string { return `${name}/${id}`; },\r\n get collection(): string { return name; },\r\n async get() {\r\n return (await getRef()).doc(id).get();\r\n },\r\n async set(data) {\r\n return (await getRef()).doc(id).set(data);\r\n },\r\n async update(data) {\r\n return (await getRef()).doc(id).update(data);\r\n },\r\n async remove() {\r\n return (await getRef()).doc(id).remove();\r\n },\r\n onSnapshot(cb) {\r\n let unsub: Unsubscribe | null = null;\r\n let cancelled = false;\r\n getRef().then((ref) => {\r\n if (!cancelled) {\r\n unsub = ref.doc(id).onSnapshot(cb);\r\n }\r\n });\r\n return () => {\r\n cancelled = true;\r\n unsub?.();\r\n };\r\n },\r\n };\r\n },\r\n };\r\n}\r\n","/**\r\n * QueryEngine — avaliador de query offline, puro e determinístico.\r\n *\r\n * Aplica um `QueryDescriptor` (where / orderBy / limit / cursor) sobre um array\r\n * de documentos em memória. Equivale a um motor de query local para o cache do\r\n * IndexedDB, cobrindo o subconjunto definido em I3 §5.2.\r\n *\r\n * Design:\r\n * - ZERO dependências externas.\r\n * - PURO: mesma entrada → mesma saída. Sem side-effects, sem I/O.\r\n * - Semântica compatível com Firestore:\r\n * • campo ausente no doc → doc EXCLUÍDO pelo filtro.\r\n * • ordem canônica de tipos mistos: null < number < string < boolean.\r\n * • tie-break final sempre por docId (lexicográfico).\r\n */\r\n\r\nimport type {\r\n OfflineDoc,\r\n QueryDescriptor,\r\n WhereFilter,\r\n WhereOp,\r\n OrderBy,\r\n QueryCursor,\r\n} from './types';\r\n\r\n// ─── Ordem canônica de tipos mistos ──────────────────────────────────────────\r\n\r\n/**\r\n * Retorna um número de \"rank\" de tipo para garantir ordem estável entre\r\n * valores de tipos diferentes (I3 §5.3): null < number < string < boolean.\r\n */\r\nfunction typeRank(v: unknown): number {\r\n if (v === null || v === undefined) return 0;\r\n if (typeof v === 'number') return 1;\r\n if (typeof v === 'string') return 2;\r\n if (typeof v === 'boolean') return 3;\r\n return 4; // object/array — vai para o fim\r\n}\r\n\r\n/**\r\n * Compara dois valores usando a ordem canônica de tipos mistos.\r\n * Retorna negativo, 0, ou positivo (como `Array.sort` espera).\r\n */\r\nfunction compareValues(a: unknown, b: unknown): number {\r\n const ra = typeRank(a);\r\n const rb = typeRank(b);\r\n if (ra !== rb) return ra - rb;\r\n\r\n // Mesmo tipo\r\n if (a === null || a === undefined) return 0;\r\n if (typeof a === 'number' && typeof b === 'number') return a - b;\r\n if (typeof a === 'string' && typeof b === 'string') return a < b ? -1 : a > b ? 1 : 0;\r\n if (typeof a === 'boolean' && typeof b === 'boolean') return a === b ? 0 : a ? 1 : -1;\r\n // Fallback para outros tipos — converte para string\r\n const sa = String(a);\r\n const sb = String(b);\r\n return sa < sb ? -1 : sa > sb ? 1 : 0;\r\n}\r\n\r\n// ─── Acesso a campo aninhado ──────────────────────────────────────────────────\r\n\r\n/**\r\n * Lê o valor de um campo no doc (suporta paths simples como 'status' ou\r\n * 'address.city' com ponto). Retorna `undefined` se o campo não existir —\r\n * o QueryEngine trata `undefined` como campo ausente (doc excluído).\r\n */\r\nfunction getField(data: Record<string, unknown>, field: string): unknown {\r\n const parts = field.split('.');\r\n let current: unknown = data;\r\n for (const part of parts) {\r\n if (current === null || current === undefined || typeof current !== 'object') {\r\n return undefined;\r\n }\r\n current = (current as Record<string, unknown>)[part];\r\n }\r\n return current;\r\n}\r\n\r\n// ─── Avaliação de filtros ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * Avalia um único `WhereFilter` contra os dados de um documento.\r\n * Campo ausente → false (doc excluído, semântica Firestore).\r\n */\r\nfunction evaluateFilter(\r\n data: Record<string, unknown>,\r\n filter: WhereFilter,\r\n): boolean {\r\n const fieldValue = getField(data, filter.field);\r\n\r\n // Campo ausente — doc excluído\r\n if (fieldValue === undefined) return false;\r\n\r\n const { op, value } = filter;\r\n\r\n switch (op as WhereOp) {\r\n case '==':\r\n return fieldValue === value;\r\n case '!=':\r\n return fieldValue !== value;\r\n case '<':\r\n return compareValues(fieldValue, value) < 0;\r\n case '<=':\r\n return compareValues(fieldValue, value) <= 0;\r\n case '>':\r\n return compareValues(fieldValue, value) > 0;\r\n case '>=':\r\n return compareValues(fieldValue, value) >= 0;\r\n case 'array-contains':\r\n return Array.isArray(fieldValue) && fieldValue.includes(value);\r\n case 'in':\r\n if (!Array.isArray(value)) return false;\r\n return (value as unknown[]).includes(fieldValue);\r\n case 'not-in':\r\n if (!Array.isArray(value)) return true;\r\n return !(value as unknown[]).includes(fieldValue);\r\n default:\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Aplica todos os filtros `where` em AND sobre os dados de um documento.\r\n */\r\nfunction matchesAllFilters(\r\n data: Record<string, unknown>,\r\n filters: WhereFilter[],\r\n): boolean {\r\n return filters.every((f) => evaluateFilter(data, f));\r\n}\r\n\r\n// ─── Ordenação ────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Constrói uma função de comparação para `Array.sort` baseada em um\r\n * `OrderBy` + tie-break final por docId.\r\n */\r\nfunction buildComparator<T>(\r\n orderBy: OrderBy | undefined,\r\n): (a: OfflineDoc<T>, b: OfflineDoc<T>) => number {\r\n return (a, b) => {\r\n if (orderBy) {\r\n const aVal = getField(a.data as Record<string, unknown>, orderBy.field);\r\n const bVal = getField(b.data as Record<string, unknown>, orderBy.field);\r\n const cmp = compareValues(aVal, bVal);\r\n if (cmp !== 0) {\r\n return orderBy.direction === 'desc' ? -cmp : cmp;\r\n }\r\n }\r\n // Tie-break por docId (lexicográfico ascendente, sempre)\r\n return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;\r\n };\r\n}\r\n\r\n// ─── Cursor ───────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Aplica o cursor de paginação ao array **já ordenado**.\r\n *\r\n * - `startAfter`: descarta o doc-cursor e tudo antes dele (inclusive).\r\n * - `endBefore`: mantém apenas os docs antes do cursor (exclusive).\r\n *\r\n * Se o docId do cursor não for encontrado no array, a lista é retornada\r\n * integralmente (falha graceful — cache pode não ter o doc-cursor).\r\n */\r\nfunction applyCursor<T>(\r\n sorted: OfflineDoc<T>[],\r\n cursor: QueryCursor,\r\n): OfflineDoc<T>[] {\r\n const idx = sorted.findIndex((d) => d.id === cursor.docId);\r\n if (idx === -1) {\r\n // Cursor não encontrado — retorna tudo (comportamento conservador)\r\n return sorted;\r\n }\r\n if (cursor.type === 'startAfter') {\r\n return sorted.slice(idx + 1);\r\n } else {\r\n // endBefore\r\n return sorted.slice(0, idx);\r\n }\r\n}\r\n\r\n// ─── QueryEngine ──────────────────────────────────────────────────────────────\r\n\r\n/** Resultado da avaliação de uma query. */\r\nexport interface QueryResult<T = Record<string, unknown>> {\r\n /** Documentos que casaram com a query, na ordem correta, respeitando limit. */\r\n docs: Array<{ id: string; data: T }>;\r\n /**\r\n * Indica que o resultado pode estar incompleto — o cache pode não ter todos\r\n * os documentos da coleção (a query offline só vê o que foi cacheado).\r\n * O chamador deve setar `stale: true` quando `incomplete: true`.\r\n */\r\n incomplete: boolean;\r\n}\r\n\r\n/**\r\n * QueryEngine — avaliador puro de queries sobre documentos em memória.\r\n *\r\n * Uso:\r\n * ```ts\r\n * const engine = new QueryEngine();\r\n * const result = engine.evaluate(docs, query);\r\n * ```\r\n *\r\n * Ou via helper estático:\r\n * ```ts\r\n * const result = QueryEngine.evaluate(docs, query);\r\n * ```\r\n */\r\nexport class QueryEngine {\r\n /**\r\n * Avalia um `QueryDescriptor` contra um array de `OfflineDoc`.\r\n *\r\n * Pipeline (I3 §5.3):\r\n * 1. Filtra docs com `deleted:false`.\r\n * 2. Aplica `where` (AND de todos os filtros).\r\n * 3. Ordena por `orderBy` + tie-break por docId.\r\n * 4. Aplica cursor (`startAfter` / `endBefore`).\r\n * 5. Corta em `limit`.\r\n */\r\n evaluate<T = Record<string, unknown>>(\r\n docs: OfflineDoc<T>[],\r\n query: QueryDescriptor,\r\n ): QueryResult<T> {\r\n // 1. Excluir tombstones\r\n let filtered = docs.filter((d) => !d.meta.deleted);\r\n\r\n // 2. Aplicar filtros where (AND)\r\n const filters = query.where ?? [];\r\n if (filters.length > 0) {\r\n filtered = filtered.filter((d) =>\r\n matchesAllFilters(d.data as Record<string, unknown>, filters),\r\n );\r\n }\r\n\r\n // 3. Ordenar\r\n const comparator = buildComparator<T>(query.orderBy);\r\n const sorted = [...filtered].sort(comparator);\r\n\r\n // 4. Cursor\r\n const afterCursor = query.cursor ? applyCursor(sorted, query.cursor) : sorted;\r\n\r\n // 5. Limit\r\n const limitN = Math.min(query.limit ?? 20, 500);\r\n const limited = afterCursor.slice(0, limitN);\r\n\r\n return {\r\n docs: limited.map((d) => ({ id: d.id, data: d.data })),\r\n // `incomplete` é sempre true aqui — o QueryEngine não sabe se o cache\r\n // tem todos os docs da coleção. É responsabilidade do chamador (LocalStore)\r\n // injetar o flag de completude baseado nos metadados do query_cache.\r\n incomplete: true,\r\n };\r\n }\r\n\r\n // ─── Static helper ─────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Helper estático para uso sem instanciar a classe.\r\n * Equivalente a `new QueryEngine().evaluate(docs, query)`.\r\n */\r\n static evaluate<T = Record<string, unknown>>(\r\n docs: OfflineDoc<T>[],\r\n query: QueryDescriptor,\r\n ): QueryResult<T> {\r\n return new QueryEngine().evaluate(docs, query);\r\n }\r\n}\r\n\r\n// ─── Exports auxiliares (para testes e outros módulos internos) ───────────────\r\n\r\nexport { compareValues, evaluateFilter, matchesAllFilters, getField };\r\n","/**\r\n * LocalStore — cache IndexedDB durável da camada offline do @neetru/sdk.\r\n *\r\n * Implementa o esquema de 5 object stores definido em I3 §3.3:\r\n * - `documents` — espelho dos documentos por coleção (keyPath: [collection, id])\r\n * - `mutations` — fila de escritas pendentes (keyPath: mutationId, índice por seq)\r\n * - `query_cache` — resultados de query materializados (keyPath: queryHash)\r\n * - `sync_meta` — watermarks e estado de sincronização (keyPath: key)\r\n * - `conflict_log`— escritas perdedoras LWW (keyPath: id, autoIncrement)\r\n *\r\n * Wrapper sobre `idb` (Promise-based, ~1KB) — não usa IndexedDB cru.\r\n *\r\n * Design:\r\n * - Todas as escritas são duráveis (IndexedDB transactions).\r\n * - Leituras sempre do IndexedDB — sem camada de memória adicional.\r\n * - Expõe os acessores que MutationQueue usa (putMutation, getMutation,\r\n * listMutations, deleteMutation) mais os métodos de doc/meta/conflict/query_cache.\r\n */\r\n\r\nimport { openDB, type IDBPDatabase } from 'idb';\r\nimport type { OfflineDoc, Mutation, ConflictRecord, QueryDescriptor } from './types';\r\nimport { QueryEngine, type QueryResult } from './query-engine';\r\n\r\n// ─── Versão do schema IndexedDB ───────────────────────────────────────────────\r\n\r\nconst SCHEMA_VERSION = 1;\r\n\r\n// ─── Tipos internos (espelham I3 §3.3) ───────────────────────────────────────\r\n\r\n/** Entrada na store `query_cache`. */\r\nexport interface CachedQuery {\r\n queryHash: string;\r\n collection: string;\r\n resultIds: string[];\r\n nextCursor: string | null;\r\n syncedAt: number;\r\n resumeToken: string | null;\r\n complete: boolean;\r\n}\r\n\r\n/** Opções de filtro para listConflicts. */\r\nexport interface ListConflictsOptions {\r\n /** Se definido, filtra por `delivered`. */\r\n delivered?: boolean;\r\n}\r\n\r\n/** Opções de filtro para listMutations. */\r\nexport interface ListMutationsOptions {\r\n /** Filtra por status. */\r\n status?: Mutation['status'];\r\n /** Filtra por [collection, docId] combinados. */\r\n collection?: string;\r\n docId?: string;\r\n}\r\n\r\n// ─── Nome das stores ──────────────────────────────────────────────────────────\r\n\r\nconst STORE_DOCUMENTS = 'documents';\r\nconst STORE_MUTATIONS = 'mutations';\r\nconst STORE_QUERY_CACHE = 'query_cache';\r\nconst STORE_SYNC_META = 'sync_meta';\r\nconst STORE_CONFLICT_LOG = 'conflict_log';\r\n\r\n// ─── LocalStore ───────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * LocalStore — cache IndexedDB durável.\r\n *\r\n * Uso:\r\n * ```ts\r\n * const store = new LocalStore('neetru-db__my-product__db1__prod');\r\n * await store.open();\r\n * await store.putDoc(doc);\r\n * const doc = await store.getDoc('orders', 'order-1');\r\n * ```\r\n *\r\n * Nomeação do banco: `neetru-db__{productSlug}__{dbId}__{env}` (I3 §3.2).\r\n * O chamador é responsável por montar o nome correto.\r\n */\r\nexport class LocalStore {\r\n private db: IDBPDatabase | null = null;\r\n private readonly dbName: string;\r\n\r\n constructor(dbName: string) {\r\n this.dbName = dbName;\r\n }\r\n\r\n // ─── Ciclo de vida ──────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Abre (ou reabre) o banco IndexedDB e executa o upgrade de schema se necessário.\r\n * Idempotente — chamadas subsequentes são no-ops se o banco já está aberto.\r\n */\r\n async open(): Promise<void> {\r\n if (this.db !== null) return;\r\n\r\n this.db = await openDB(this.dbName, SCHEMA_VERSION, {\r\n upgrade(db) {\r\n // ── documents ────────────────────────────────────────────────────────\r\n if (!db.objectStoreNames.contains(STORE_DOCUMENTS)) {\r\n const docsStore = db.createObjectStore(STORE_DOCUMENTS, {\r\n keyPath: ['collection', 'id'],\r\n });\r\n // I3 §3.3: índices\r\n docsStore.createIndex('by_collection', 'collection');\r\n docsStore.createIndex('by_collection_state', ['collection', 'meta.state']);\r\n docsStore.createIndex('by_updatedAtServer', 'meta.updatedAtServer');\r\n }\r\n\r\n // ── mutations ────────────────────────────────────────────────────────\r\n if (!db.objectStoreNames.contains(STORE_MUTATIONS)) {\r\n const mutStore = db.createObjectStore(STORE_MUTATIONS, {\r\n keyPath: 'mutationId',\r\n });\r\n // seq: índice para listagem em ordem\r\n mutStore.createIndex('by_seq', 'seq');\r\n // I3 §3.3: índices\r\n mutStore.createIndex('by_status', 'status');\r\n mutStore.createIndex('by_doc', ['collection', 'docId']);\r\n mutStore.createIndex('by_batch', 'batchId');\r\n }\r\n\r\n // ── query_cache ──────────────────────────────────────────────────────\r\n if (!db.objectStoreNames.contains(STORE_QUERY_CACHE)) {\r\n db.createObjectStore(STORE_QUERY_CACHE, { keyPath: 'queryHash' });\r\n }\r\n\r\n // ── sync_meta ────────────────────────────────────────────────────────\r\n if (!db.objectStoreNames.contains(STORE_SYNC_META)) {\r\n db.createObjectStore(STORE_SYNC_META, { keyPath: 'key' });\r\n }\r\n\r\n // ── conflict_log ─────────────────────────────────────────────────────\r\n if (!db.objectStoreNames.contains(STORE_CONFLICT_LOG)) {\r\n const conflictStore = db.createObjectStore(STORE_CONFLICT_LOG, {\r\n keyPath: 'id',\r\n autoIncrement: true,\r\n });\r\n conflictStore.createIndex('by_delivered', 'delivered');\r\n conflictStore.createIndex('by_doc', ['collection', 'docId']);\r\n }\r\n },\r\n });\r\n }\r\n\r\n /** Fecha o banco IndexedDB. */\r\n async close(): Promise<void> {\r\n this.db?.close();\r\n this.db = null;\r\n }\r\n\r\n /**\r\n * Apaga completamente o banco IndexedDB e o recria do zero.\r\n *\r\n * Ao contrário de `close()` + `open()` (que reabre o banco existente sem\r\n * apagar dados), `clearAll()` chama `indexedDB.deleteDatabase(dbName)` e\r\n * só então chama `open()` — garantindo que nenhum documento, mutação ou\r\n * metadado sobrevive.\r\n *\r\n * BUG fix: `clearCache()` em `NeetruDbDocumentsImpl` chamava close+open,\r\n * que reabre o mesmo banco. `clearAll()` é o método correto.\r\n */\r\n async clearAll(): Promise<void> {\r\n // Fecha a conexão ativa antes de apagar (IndexedDB rejeita deleteDatabase\r\n // enquanto há conexões abertas sem requisição de \"versionchange\").\r\n if (this.db !== null) {\r\n this.db.close();\r\n this.db = null;\r\n }\r\n await new Promise<void>((resolve, reject) => {\r\n const req = indexedDB.deleteDatabase(this.dbName);\r\n req.onsuccess = () => resolve();\r\n req.onerror = () => reject(req.error);\r\n // onblocked: outro contexto ainda tem o banco aberto — fecha assim que possível.\r\n req.onblocked = () => {\r\n // Não rejeita: o deleteDatabase pode completar depois do blocked.\r\n // O resolve/reject acima cobre o resultado final.\r\n };\r\n });\r\n // Reabre o banco com schema limpo.\r\n await this.open();\r\n }\r\n\r\n private assertOpen(): IDBPDatabase {\r\n if (this.db === null) {\r\n throw new Error('LocalStore: banco não está aberto. Chame open() primeiro.');\r\n }\r\n return this.db;\r\n }\r\n\r\n // ─── Documents ──────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna um documento pelo [collection, id], ou `null` se não existir.\r\n * Retorna tombstones (deleted: true) — o chamador decide se deve mostrá-los.\r\n */\r\n async getDoc<T = Record<string, unknown>>(\r\n collection: string,\r\n id: string,\r\n ): Promise<OfflineDoc<T> | null> {\r\n const db = this.assertOpen();\r\n const result = await db.get(STORE_DOCUMENTS, [collection, id]);\r\n return (result as OfflineDoc<T> | undefined) ?? null;\r\n }\r\n\r\n /**\r\n * Insere ou atualiza um documento na store `documents`.\r\n * O documento é identificado pelo keyPath composto `[collection, id]`.\r\n */\r\n async putDoc<T = Record<string, unknown>>(doc: OfflineDoc<T>): Promise<void> {\r\n const db = this.assertOpen();\r\n await db.put(STORE_DOCUMENTS, doc);\r\n }\r\n\r\n /**\r\n * Marca um documento como tombstone (`deleted: true`).\r\n * Não remove fisicamente — o tombstone é necessário para reconciliação.\r\n * No-op se o documento não existir.\r\n */\r\n async deleteDoc(collection: string, id: string): Promise<void> {\r\n const db = this.assertOpen();\r\n const existing = await db.get(STORE_DOCUMENTS, [collection, id]);\r\n if (!existing) return;\r\n await db.put(STORE_DOCUMENTS, {\r\n ...existing,\r\n meta: {\r\n ...(existing as OfflineDoc).meta,\r\n deleted: true,\r\n updatedAtLocal: Date.now(),\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Lista documentos de uma coleção, aplicando o QueryDescriptor via QueryEngine.\r\n *\r\n * I3 §5.3: a listagem lê todos os docs da coleção pelo índice `by_collection`\r\n * e delega a filtragem/ordenação/paginação ao QueryEngine (que opera em memória).\r\n */\r\n async listDocs<T = Record<string, unknown>>(\r\n collection: string,\r\n query: QueryDescriptor,\r\n ): Promise<QueryResult<T>> {\r\n const db = this.assertOpen();\r\n const rawDocs = await db.getAllFromIndex(STORE_DOCUMENTS, 'by_collection', collection);\r\n return QueryEngine.evaluate<T>(rawDocs as OfflineDoc<T>[], query);\r\n }\r\n\r\n // ─── Sync meta (key-value) ──────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna o valor de uma chave da store `sync_meta`, ou `null` se não existir.\r\n *\r\n * Chaves conhecidas (I3 §3.3):\r\n * 'lastSyncWatermark', 'resumeToken:<col>', 'schemaVersion',\r\n * 'lastFullResyncAt', 'leaderTabId'.\r\n */\r\n async getMeta(key: string): Promise<unknown> {\r\n const db = this.assertOpen();\r\n const entry = await db.get(STORE_SYNC_META, key);\r\n if (!entry) return null;\r\n return (entry as { key: string; value: unknown }).value;\r\n }\r\n\r\n /**\r\n * Armazena ou atualiza um valor na store `sync_meta`.\r\n */\r\n async setMeta(key: string, value: unknown): Promise<void> {\r\n const db = this.assertOpen();\r\n await db.put(STORE_SYNC_META, { key, value });\r\n }\r\n\r\n // ─── Conflict log ───────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Adiciona um registro de conflito ao `conflict_log`.\r\n * O `id` é autoIncrement — não deve ser fornecido pelo chamador.\r\n */\r\n async appendConflict(record: Omit<ConflictRecord, 'id'>): Promise<ConflictRecord> {\r\n const db = this.assertOpen();\r\n const id = await db.add(STORE_CONFLICT_LOG, record);\r\n return { ...record, id: id as number };\r\n }\r\n\r\n /**\r\n * Lista registros do `conflict_log`.\r\n * Filtra por `delivered` se a opção for fornecida.\r\n */\r\n async listConflicts(options?: ListConflictsOptions): Promise<ConflictRecord[]> {\r\n const db = this.assertOpen();\r\n const all = await db.getAll(STORE_CONFLICT_LOG) as ConflictRecord[];\r\n\r\n if (options?.delivered !== undefined) {\r\n return all.filter((r) => r.delivered === options.delivered);\r\n }\r\n return all;\r\n }\r\n\r\n /**\r\n * Marca um registro do `conflict_log` como entregue ao produto.\r\n */\r\n async markConflictDelivered(id: number): Promise<void> {\r\n const db = this.assertOpen();\r\n const existing = await db.get(STORE_CONFLICT_LOG, id) as ConflictRecord | undefined;\r\n if (!existing) return;\r\n await db.put(STORE_CONFLICT_LOG, { ...existing, delivered: true });\r\n }\r\n\r\n // ─── Mutations (acessores usados pelo MutationQueue) ────────────────────────\r\n\r\n /**\r\n * Insere ou atualiza uma mutação na store `mutations`.\r\n * Key: `mutationId`.\r\n */\r\n async putMutation(mutation: Mutation): Promise<void> {\r\n const db = this.assertOpen();\r\n await db.put(STORE_MUTATIONS, mutation);\r\n }\r\n\r\n /**\r\n * Retorna uma mutação pelo `mutationId`, ou `null` se não existir.\r\n */\r\n async getMutation(mutationId: string): Promise<Mutation | null> {\r\n const db = this.assertOpen();\r\n const result = await db.get(STORE_MUTATIONS, mutationId);\r\n return (result as Mutation | undefined) ?? null;\r\n }\r\n\r\n /**\r\n * Lista mutações com filtros opcionais.\r\n * Resultado ordenado por `seq` crescente.\r\n */\r\n async listMutations(options?: ListMutationsOptions): Promise<Mutation[]> {\r\n const db = this.assertOpen();\r\n\r\n let mutations: Mutation[];\r\n\r\n if (options?.status !== undefined) {\r\n mutations = (await db.getAllFromIndex(STORE_MUTATIONS, 'by_status', options.status)) as Mutation[];\r\n } else if (options?.collection !== undefined && options.docId !== undefined) {\r\n mutations = (await db.getAllFromIndex(STORE_MUTATIONS, 'by_doc', [options.collection, options.docId])) as Mutation[];\r\n } else {\r\n // Lê tudo pelo índice by_seq para garantir ordem\r\n mutations = (await db.getAllFromIndex(STORE_MUTATIONS, 'by_seq')) as Mutation[];\r\n }\r\n\r\n // Ordena por seq crescente (defensivo — o índice by_seq já ordena, mas\r\n // leituras por outros índices podem não preservar a ordem)\r\n return mutations.sort((a, b) => a.seq - b.seq);\r\n }\r\n\r\n /**\r\n * Remove uma mutação pelo `mutationId`.\r\n * No-op se não existir.\r\n */\r\n async deleteMutation(mutationId: string): Promise<void> {\r\n const db = this.assertOpen();\r\n await db.delete(STORE_MUTATIONS, mutationId);\r\n }\r\n\r\n // ─── Collection discovery ────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna a lista de coleções únicas presentes na store `documents`.\r\n *\r\n * Usado pelo SyncEngine no full resync para descobrir coleções cujos docs\r\n * precisam ser verificados contra a resposta do servidor (tombstone detection).\r\n *\r\n * Implementação: itera o índice `by_collection` com `openKeyCursor` para\r\n * coletar os valores únicos de forma eficiente (sem carregar os docs completos).\r\n */\r\n async listCollections(): Promise<string[]> {\r\n const db = this.assertOpen();\r\n const allDocs = await db.getAllFromIndex(STORE_DOCUMENTS, 'by_collection') as OfflineDoc[];\r\n const collections = new Set<string>();\r\n for (const doc of allDocs) {\r\n collections.add(doc.collection);\r\n }\r\n return Array.from(collections);\r\n }\r\n\r\n // ─── Query cache ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna a entrada de `query_cache` para um hash de query, ou `null`.\r\n */\r\n async getQueryCache(queryHash: string): Promise<CachedQuery | null> {\r\n const db = this.assertOpen();\r\n const result = await db.get(STORE_QUERY_CACHE, queryHash);\r\n return (result as CachedQuery | undefined) ?? null;\r\n }\r\n\r\n /**\r\n * Insere ou atualiza uma entrada de `query_cache`.\r\n */\r\n async putQueryCache(entry: CachedQuery): Promise<void> {\r\n const db = this.assertOpen();\r\n await db.put(STORE_QUERY_CACHE, entry);\r\n }\r\n\r\n /**\r\n * Remove uma entrada de `query_cache` pelo queryHash.\r\n */\r\n async deleteQueryCache(queryHash: string): Promise<void> {\r\n const db = this.assertOpen();\r\n await db.delete(STORE_QUERY_CACHE, queryHash);\r\n }\r\n}\r\n","/**\n * MemoryStore — implementação em memória do contrato de LocalStore.\n *\n * Usada automaticamente quando IndexedDB não está disponível (Node.js, Workers\n * sem IDB, ambientes de teste sem fake-indexeddb). Implementa exatamente o\n * mesmo conjunto de métodos públicos que LocalStore, garantindo que o restante\n * da stack offline (MutationQueue, SyncEngine, DbCollectionRefImpl) funcione\n * sem qualquer alteração.\n *\n * Características:\n * - Totalmente síncrona internamente, mas expõe a mesma API async de LocalStore.\n * - Sem persistência entre reinicializações (in-process apenas).\n * - open()/close() são no-ops (sem recurso externo a abrir/fechar).\n * - listMutations() preserva a ordenação por `seq` exigida pelo MutationQueue.\n *\n * @internal Não exportado pela superfície pública do SDK — detalhe de implementação.\n */\n\nimport type { OfflineDoc, Mutation, ConflictRecord, QueryDescriptor } from './types';\nimport { QueryEngine, type QueryResult } from './query-engine';\nimport type {\n CachedQuery,\n ListConflictsOptions,\n ListMutationsOptions,\n} from './local-store';\n\n// ─── MemoryStore ──────────────────────────────────────────────────────────────\n\nexport class MemoryStore {\n // store `documents` — key: `${collection}\\0${id}`\n private readonly _docs = new Map<string, OfflineDoc>();\n\n // store `mutations` — key: mutationId\n private readonly _mutations = new Map<string, Mutation>();\n\n // store `sync_meta` — key: string\n private readonly _meta = new Map<string, unknown>();\n\n // store `conflict_log` — autoIncrement int key\n private readonly _conflicts: Array<ConflictRecord & { id: number }> = [];\n private _conflictSeq = 0;\n\n // store `query_cache` — key: queryHash\n private readonly _queryCache = new Map<string, CachedQuery>();\n\n // ─── Ciclo de vida (no-ops) ─────────────────────────────────────────────────\n\n async open(): Promise<void> {\n // Nada a abrir — já está \"aberto\" ao ser construído.\n }\n\n async close(): Promise<void> {\n // No-op: MemoryStore não tem recurso externo a fechar.\n // (Os dados são preservados: apenas LocalStore.close() limpa o handle IDB.)\n }\n\n /**\n * Apaga todos os dados em memória — equivalente ao `indexedDB.deleteDatabase`\n * que `LocalStore.clearAll()` executa em ambientes com IndexedDB.\n */\n async clearAll(): Promise<void> {\n this._docs.clear();\n this._mutations.clear();\n this._meta.clear();\n this._conflicts.splice(0);\n this._conflictSeq = 0;\n this._queryCache.clear();\n }\n\n // ─── Documents ─────────────────────────────────────────────────────────────\n\n async getDoc<T = Record<string, unknown>>(\n collection: string,\n id: string,\n ): Promise<OfflineDoc<T> | null> {\n const key = `${collection}\\0${id}`;\n return (this._docs.get(key) as OfflineDoc<T> | undefined) ?? null;\n }\n\n async putDoc<T = Record<string, unknown>>(doc: OfflineDoc<T>): Promise<void> {\n const key = `${doc.collection}\\0${doc.id}`;\n this._docs.set(key, doc as OfflineDoc);\n }\n\n async deleteDoc(collection: string, id: string): Promise<void> {\n const key = `${collection}\\0${id}`;\n const existing = this._docs.get(key);\n if (!existing) return;\n this._docs.set(key, {\n ...existing,\n meta: {\n ...existing.meta,\n deleted: true,\n updatedAtLocal: Date.now(),\n },\n });\n }\n\n async listDocs<T = Record<string, unknown>>(\n collection: string,\n query: QueryDescriptor,\n ): Promise<QueryResult<T>> {\n const rawDocs = Array.from(this._docs.values()).filter(\n (d) => d.collection === collection,\n ) as OfflineDoc<T>[];\n return QueryEngine.evaluate<T>(rawDocs, query);\n }\n\n // ─── Sync meta ──────────────────────────────────────────────────────────────\n\n async getMeta(key: string): Promise<unknown> {\n return this._meta.get(key) ?? null;\n }\n\n async setMeta(key: string, value: unknown): Promise<void> {\n this._meta.set(key, value);\n }\n\n // ─── Conflict log ────────────────────────────────────────────────────────────\n\n async appendConflict(record: Omit<ConflictRecord, 'id'>): Promise<ConflictRecord> {\n const id = ++this._conflictSeq;\n const full = { ...record, id } as ConflictRecord & { id: number };\n this._conflicts.push(full);\n return full;\n }\n\n async listConflicts(options?: ListConflictsOptions): Promise<ConflictRecord[]> {\n if (options?.delivered !== undefined) {\n return this._conflicts.filter((r) => r.delivered === options.delivered);\n }\n return [...this._conflicts];\n }\n\n async markConflictDelivered(id: number): Promise<void> {\n const entry = this._conflicts.find((r) => r.id === id);\n if (entry) entry.delivered = true;\n }\n\n // ─── Mutations ───────────────────────────────────────────────────────────────\n\n async putMutation(mutation: Mutation): Promise<void> {\n this._mutations.set(mutation.mutationId, { ...mutation });\n }\n\n async getMutation(mutationId: string): Promise<Mutation | null> {\n return this._mutations.get(mutationId) ?? null;\n }\n\n async listMutations(options?: ListMutationsOptions): Promise<Mutation[]> {\n let all = Array.from(this._mutations.values());\n\n if (options?.status !== undefined) {\n all = all.filter((m) => m.status === options.status);\n } else if (options?.collection !== undefined && options.docId !== undefined) {\n all = all.filter(\n (m) => m.collection === options.collection && m.docId === options.docId,\n );\n } else if (options?.collection !== undefined) {\n all = all.filter((m) => m.collection === options.collection);\n }\n\n return all.sort((a, b) => a.seq - b.seq);\n }\n\n async deleteMutation(mutationId: string): Promise<void> {\n this._mutations.delete(mutationId);\n }\n\n // ─── Collection discovery ────────────────────────────────────────────────────\n\n async listCollections(): Promise<string[]> {\n const collections = new Set<string>();\n for (const doc of this._docs.values()) {\n collections.add(doc.collection);\n }\n return Array.from(collections);\n }\n\n // ─── Query cache ─────────────────────────────────────────────────────────────\n\n async getQueryCache(queryHash: string): Promise<CachedQuery | null> {\n return this._queryCache.get(queryHash) ?? null;\n }\n\n async putQueryCache(entry: CachedQuery): Promise<void> {\n this._queryCache.set(entry.queryHash, { ...entry });\n }\n\n async deleteQueryCache(queryHash: string): Promise<void> {\n this._queryCache.delete(queryHash);\n }\n}\n","/**\r\n * MutationQueue — fila durável e atomicamente-ordenada de escritas pendentes.\r\n *\r\n * Implementa I3 §4 e §5 (integração com QueryEngine/LocalStore):\r\n *\r\n * - Enqueue atômico: aplica ao cache de documentos e grava na fila em uma\r\n * única transação IndexedDB — crash mid-enqueue nunca corrompe a ordenação.\r\n * - Seq monotônico: autoIncrement via geração local (não confia no IndexedDB\r\n * autoIncrement para seq para poder controlar coalescing antes da gravação).\r\n * - MutationId: UUID v4 client-generated (I3 §4.2) — idempotência no replay.\r\n * - Coalescing (I3 §4.4): mutações adjacentes do mesmo doc (sem batchId\r\n * diferente, sem inflight no meio) são colapsadas antes do enfileiramento.\r\n * - Drain: retorna mutações queued em ordem de seq (para o SyncEngine).\r\n * - markApplied / markFailed / markInflight: ciclo de vida de cada mutação.\r\n *\r\n * Persistência: totalmente via LocalStore (IndexedDB). Nenhum estado em RAM\r\n * além do ponteiro de seq atual (re-sync ao instanciar se necessário).\r\n */\r\n\r\nimport type { LocalStore } from './local-store';\r\nimport type { Mutation, MutationKind } from './types';\r\n\r\n// ─── Geração de UUID v4 ───────────────────────────────────────────────────────\r\n\r\n/**\r\n * Gera um UUID v4 aleatório (I3 §4.2).\r\n * Usa `crypto.randomUUID()` quando disponível (Node ≥19 / browsers modernos),\r\n * com fallback manual para ambientes mais antigos.\r\n */\r\nfunction generateUUIDv4(): string {\r\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\r\n return crypto.randomUUID();\r\n }\r\n // Fallback RFC 4122 v4\r\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\r\n const r = (Math.random() * 16) | 0;\r\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\r\n return v.toString(16);\r\n });\r\n}\r\n\r\n// ─── Tipos de entrada para enqueue ───────────────────────────────────────────\r\n\r\n/** Parâmetros para enfileirar uma nova mutação. */\r\nexport interface EnqueueParams {\r\n collection: string;\r\n /** Para `add`, pode ser omitido — um UUID v4 será gerado automaticamente. */\r\n docId?: string;\r\n op: MutationKind;\r\n payload: Record<string, unknown> | null;\r\n baseVersion: string | null;\r\n batchId: string | null;\r\n}\r\n\r\n/** Opções para drain(). */\r\nexport interface DrainOptions {\r\n /** Máximo de mutações a retornar. Default: sem limite. */\r\n maxBatch?: number;\r\n}\r\n\r\n// ─── MutationQueue ────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * MutationQueue — fila durável de escritas pendentes.\r\n *\r\n * Construída sobre LocalStore. Cada MutationQueue é ligada a um LocalStore\r\n * (e portanto a um banco IndexedDB). Uma instância por banco lógico Neetru.\r\n *\r\n * ```ts\r\n * const store = new LocalStore(dbName);\r\n * await store.open();\r\n * const queue = new MutationQueue(store);\r\n *\r\n * const mut = await queue.enqueue({\r\n * collection: 'orders',\r\n * op: 'add',\r\n * payload: { total: 100 },\r\n * baseVersion: null,\r\n * batchId: null,\r\n * });\r\n * // mut.id, mut.seq, mut.mutationId disponíveis imediatamente.\r\n * ```\r\n */\r\nexport class MutationQueue {\r\n private readonly store: LocalStore;\r\n /**\r\n * Ponteiro de sequência local.\r\n * Inicializado com 0 — o primeiro enqueue sincroniza o valor real do banco\r\n * (`_syncSeq`), garantindo que nunca sobreponha um seq existente.\r\n */\r\n private seqCounter = 0;\r\n private seqSynced = false;\r\n\r\n constructor(store: LocalStore) {\r\n this.store = store;\r\n }\r\n\r\n // ─── Seq management ─────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Sincroniza o ponteiro de seq com o maior seq existente no banco.\r\n * Chamado lazy no primeiro enqueue.\r\n */\r\n private async syncSeq(): Promise<void> {\r\n if (this.seqSynced) return;\r\n const all = await this.store.listMutations();\r\n if (all.length > 0) {\r\n const maxSeq = Math.max(...all.map((m) => m.seq));\r\n this.seqCounter = maxSeq;\r\n }\r\n this.seqSynced = true;\r\n }\r\n\r\n private nextSeq(): number {\r\n this.seqCounter += 1;\r\n return this.seqCounter;\r\n }\r\n\r\n // ─── Coalescing ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Tenta coalescir `newOp`/`newPayload` com a mutação existente `existing`.\r\n *\r\n * Regras de coalescing (I3 §4.4):\r\n * - update + update → update com merge dos campos (segundo vence nos conflitos)\r\n * - add + update → add com campos mesclados\r\n * - add + remove → nada (remove a mutação existente, retorna null para remove)\r\n * - set + update → set com campos mesclados\r\n * - any + remove (base servidor) → remove\r\n *\r\n * Retorna:\r\n * - `{ coalesced: Mutation }` — substitui a mutação existente (update in-place)\r\n * - `{ removed: true }` — a mutação existente deve ser deletada (add+remove)\r\n * - `null` — não é possível coalescir\r\n */\r\n private tryCoalesce(\r\n existing: Mutation,\r\n newOp: MutationKind,\r\n newPayload: Record<string, unknown> | null,\r\n newBatchId: string | null,\r\n ): { coalesced: Mutation } | { removed: true } | null {\r\n // Não coalesce se batchIds diferentes (um ou ambos definidos e diferentes)\r\n if (existing.batchId !== newBatchId) return null;\r\n\r\n // Não coalesce através de inflight\r\n if (existing.status === 'inflight') return null;\r\n\r\n const existingOp = existing.op;\r\n\r\n // add + remove → remove da fila inteira (doc nunca existiu no servidor)\r\n if (existingOp === 'add' && newOp === 'remove') {\r\n return { removed: true };\r\n }\r\n\r\n // update + update → merge dos campos\r\n if (existingOp === 'update' && newOp === 'update') {\r\n return {\r\n coalesced: {\r\n ...existing,\r\n payload: { ...(existing.payload ?? {}), ...(newPayload ?? {}) },\r\n },\r\n };\r\n }\r\n\r\n // add + update → add com campos mesclados\r\n if (existingOp === 'add' && newOp === 'update') {\r\n return {\r\n coalesced: {\r\n ...existing,\r\n op: 'add',\r\n payload: { ...(existing.payload ?? {}), ...(newPayload ?? {}) },\r\n },\r\n };\r\n }\r\n\r\n // set + update → set com campos mesclados\r\n if (existingOp === 'set' && newOp === 'update') {\r\n return {\r\n coalesced: {\r\n ...existing,\r\n op: 'set',\r\n payload: { ...(existing.payload ?? {}), ...(newPayload ?? {}) },\r\n },\r\n };\r\n }\r\n\r\n // update/set/add + remove (base servidor presente) → remove\r\n if (newOp === 'remove') {\r\n return {\r\n coalesced: {\r\n ...existing,\r\n op: 'remove',\r\n payload: null,\r\n },\r\n };\r\n }\r\n\r\n // Não coalesça nos demais casos (ex: remove + set — nova operação distinta)\r\n return null;\r\n }\r\n\r\n // ─── Enqueue ─────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Enfileira uma nova mutação.\r\n *\r\n * Processo (I3 §4.1):\r\n * 1. Gera docId se op=add e não fornecido.\r\n * 2. Sincroniza seq (lazy).\r\n * 3. Tenta coalescir com a última mutação queued do mesmo [collection, docId].\r\n * 4. Se coalescing:\r\n * - `removed` → deleta mutação existente; retorna sem enfileirar nova.\r\n * - `coalesced` → substitui a mutação existente (mesmo seq, mesmo mutationId).\r\n * 5. Se não coalesce → enfileira nova mutação (novo seq, novo mutationId).\r\n *\r\n * Atômico: a persistência final é uma única operação putMutation.\r\n */\r\n async enqueue(params: EnqueueParams): Promise<Mutation> {\r\n const { collection, op, payload, baseVersion, batchId } = params;\r\n\r\n // 1. docId\r\n const docId = params.docId ?? (op === 'add' ? generateUUIDv4() : '');\r\n\r\n // 2. Sincroniza seq se necessário\r\n await this.syncSeq();\r\n\r\n // 3. Tenta coalescir com mutação existente do mesmo [collection, docId]\r\n // Busca a última mutação queued para este doc (não inflight)\r\n const existingMutations = await this.store.listMutations({ collection, docId });\r\n const lastQueued = existingMutations\r\n .filter((m) => m.status === 'queued')\r\n .sort((a, b) => b.seq - a.seq)[0]; // o mais recente\r\n\r\n if (lastQueued !== undefined) {\r\n const coalesceResult = this.tryCoalesce(lastQueued, op, payload, batchId);\r\n\r\n if (coalesceResult !== null) {\r\n if ('removed' in coalesceResult) {\r\n // add + remove → remove da fila\r\n await this.store.deleteMutation(lastQueued.mutationId);\r\n // Retorna uma mutação \"fantasma\" representando o no-op\r\n // (o chamador recebe o resultado, mas a fila está vazia para este doc)\r\n const phantomMut: Mutation = {\r\n seq: lastQueued.seq,\r\n mutationId: generateUUIDv4(),\r\n collection,\r\n docId,\r\n op: 'remove',\r\n payload: null,\r\n baseVersion,\r\n enqueuedAt: Date.now(),\r\n attempts: 0,\r\n lastError: null,\r\n status: 'queued',\r\n batchId,\r\n };\r\n // Não persiste — este doc foi cancelado\r\n return phantomMut;\r\n }\r\n\r\n // coalesced → atualiza a mutação existente no banco\r\n const { coalesced } = coalesceResult;\r\n await this.store.putMutation(coalesced);\r\n return coalesced;\r\n }\r\n }\r\n\r\n // 4. Nova mutação\r\n const seq = this.nextSeq();\r\n const mutation: Mutation = {\r\n seq,\r\n mutationId: generateUUIDv4(),\r\n collection,\r\n docId,\r\n op,\r\n payload,\r\n baseVersion,\r\n enqueuedAt: Date.now(),\r\n attempts: 0,\r\n lastError: null,\r\n status: 'queued',\r\n batchId,\r\n };\r\n\r\n await this.store.putMutation(mutation);\r\n return mutation;\r\n }\r\n\r\n // ─── Leitura da fila ─────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna a primeira mutação com status `queued` (menor seq), ou `null`.\r\n */\r\n async peek(): Promise<Mutation | null> {\r\n const pending = await this.listPending();\r\n return pending[0] ?? null;\r\n }\r\n\r\n /**\r\n * Retorna todas as mutações com status `queued`, ordenadas por seq crescente.\r\n */\r\n async listPending(): Promise<Mutation[]> {\r\n return this.store.listMutations({ status: 'queued' });\r\n }\r\n\r\n /**\r\n * Retorna TODAS as mutações (qualquer status), ordenadas por seq crescente.\r\n * Útil para inspeção e testes.\r\n */\r\n async listAll(): Promise<Mutation[]> {\r\n return this.store.listMutations();\r\n }\r\n\r\n /**\r\n * Conta o número de mutações com status `queued`.\r\n */\r\n async countPending(): Promise<number> {\r\n const pending = await this.listPending();\r\n return pending.length;\r\n }\r\n\r\n /**\r\n * Retorna um lote de mutações `queued` para drenagem (I3 §6.2 FASE 1).\r\n * Ordena por seq crescente. O SyncEngine chama drain(), itera, e marca\r\n * cada mutação como applied/failed.\r\n */\r\n async drain(options?: DrainOptions): Promise<Mutation[]> {\r\n const pending = await this.listPending();\r\n if (options?.maxBatch !== undefined && options.maxBatch > 0) {\r\n return pending.slice(0, options.maxBatch);\r\n }\r\n return pending;\r\n }\r\n\r\n // ─── Ciclo de vida de mutações ────────────────────────────────────────────────\r\n\r\n /**\r\n * Marca uma mutação como `inflight` (está sendo enviada ao Core).\r\n * Chamado pelo SyncEngine antes de enviar o request.\r\n */\r\n async markInflight(mutationId: string): Promise<void> {\r\n const mut = await this.store.getMutation(mutationId);\r\n if (!mut) return;\r\n await this.store.putMutation({ ...mut, status: 'inflight' });\r\n }\r\n\r\n /**\r\n * Remove a mutação da fila (sucesso de replay).\r\n * Chamado pelo SyncEngine ao receber confirmação do Core.\r\n */\r\n async markApplied(mutationId: string): Promise<void> {\r\n await this.store.deleteMutation(mutationId);\r\n }\r\n\r\n /**\r\n * Marca uma mutação como `failed` e registra o erro.\r\n * Incrementa `attempts`. Chamado pelo SyncEngine em falha permanente.\r\n */\r\n async markFailed(mutationId: string, error: string): Promise<void> {\r\n const mut = await this.store.getMutation(mutationId);\r\n if (!mut) return;\r\n await this.store.putMutation({\r\n ...mut,\r\n status: 'failed',\r\n lastError: error,\r\n attempts: mut.attempts + 1,\r\n });\r\n }\r\n\r\n /**\r\n * Incrementa `attempts` e volta para `queued` (falha transiente com backoff).\r\n * Chamado pelo SyncEngine em falha transiente (5xx, timeout).\r\n */\r\n async markRetry(mutationId: string, error: string): Promise<void> {\r\n const mut = await this.store.getMutation(mutationId);\r\n if (!mut) return;\r\n await this.store.putMutation({\r\n ...mut,\r\n status: 'queued',\r\n lastError: error,\r\n attempts: mut.attempts + 1,\r\n });\r\n }\r\n}\r\n","/**\r\n * field-value.ts — Sentinels de escrita server-side para o Mundo Documentos.\r\n *\r\n * Resolve duas lacunas confirmadas (bug_05aedb8b) da superfície `client.db`:\r\n *\r\n * 1. **Timestamp resolvido no servidor** — antes deste módulo, o produto que\r\n * quisesse `createdAt`/`updatedAt` confiáveis tinha que usar `Date.now()`\r\n * no CLIENTE, que é spoofável e sofre clock-skew. Agora:\r\n *\r\n * await orders.add({ total: 99, createdAt: serverTimestamp() });\r\n *\r\n * O marcador atravessa o transporte REST como um objeto JSON namespaceado\r\n * e o Core o substitui por `FieldValue.serverTimestamp()` no momento da\r\n * escrita — relógio do SERVIDOR, não do cliente.\r\n *\r\n * 2. **Increment atômico** — antes, `update(id, { n: x+1 })` era read-modify-write\r\n * no cliente, sujeito a lost-update sob concorrência. Agora:\r\n *\r\n * await counters.update('global', { hits: increment(1) });\r\n *\r\n * O Core aplica `FieldValue.increment(1)` atomicamente no documento.\r\n *\r\n * ## Contrato de fio (wire format)\r\n *\r\n * Os sentinels são objetos JSON simples — sobrevivem `JSON.stringify` no\r\n * transporte REST e ao `IndexedDB structured clone` da camada offline:\r\n *\r\n * serverTimestamp() → `{ \"__neetru__\": \"serverTimestamp\" }`\r\n * increment(n) → `{ \"__neetru__\": \"increment\", \"operand\": n }`\r\n *\r\n * A chave-âncora `__neetru__` é deliberadamente improvável de colidir com\r\n * dados de produto. O Core valida e resolve esses marcadores; qualquer objeto\r\n * com `__neetru__` desconhecido é rejeitado server-side (fail-closed).\r\n *\r\n * ## Aplicação otimista (offline-first)\r\n *\r\n * A camada offline aplica uma APROXIMAÇÃO local imediata (para a UI não piscar):\r\n * - `serverTimestamp()` → `Date.now()` local (substituído pelo valor real no sync).\r\n * - `increment(n)` → soma `n` ao valor numérico atual do campo (0 se ausente).\r\n * O valor canônico vem sempre do servidor no pull/confirm subsequente.\r\n *\r\n * @module\r\n */\r\n\r\n/** Chave-âncora dos marcadores de sentinel no wire format. */\r\nexport const NEETRU_SENTINEL_KEY = '__neetru__' as const;\r\n\r\n/** Marcador de timestamp resolvido pelo servidor. */\r\nexport interface ServerTimestampSentinel {\r\n readonly __neetru__: 'serverTimestamp';\r\n}\r\n\r\n/** Marcador de incremento atômico aplicado pelo servidor. */\r\nexport interface IncrementSentinel {\r\n readonly __neetru__: 'increment';\r\n /** Delta a somar (pode ser negativo para decremento). */\r\n readonly operand: number;\r\n}\r\n\r\n/**\r\n * União de todos os sentinels de campo. Use `serverTimestamp()` / `increment()`\r\n * para construir — nunca monte o objeto à mão.\r\n */\r\nexport type FieldSentinel = ServerTimestampSentinel | IncrementSentinel;\r\n\r\n/**\r\n * Sentinel que instrui o servidor a gravar o timestamp do MOMENTO da escrita\r\n * usando o relógio do servidor (não do cliente).\r\n *\r\n * @example\r\n * ```ts\r\n * import { serverTimestamp } from '@neetru/sdk/db';\r\n * await orders.add({ total: 99, createdAt: serverTimestamp() });\r\n * ```\r\n */\r\nexport function serverTimestamp(): ServerTimestampSentinel {\r\n return { __neetru__: 'serverTimestamp' };\r\n}\r\n\r\n/**\r\n * Sentinel que instrui o servidor a incrementar atomicamente o campo numérico\r\n * por `n` (negativo decrementa). Se o campo não existir/não for numérico, o\r\n * servidor o trata como `0` antes de somar (semântica `FieldValue.increment`).\r\n *\r\n * @param n — delta inteiro ou fracionário a somar.\r\n * @example\r\n * ```ts\r\n * import { increment } from '@neetru/sdk/db';\r\n * await counters.update('global', { hits: increment(1) });\r\n * await wallet.update(uid, { balance: increment(-50) });\r\n * ```\r\n */\r\nexport function increment(n: number): IncrementSentinel {\r\n if (typeof n !== 'number' || !Number.isFinite(n)) {\r\n throw new TypeError(\r\n `increment(n): n deve ser um número finito (recebido: ${String(n)}).`,\r\n );\r\n }\r\n return { __neetru__: 'increment', operand: n };\r\n}\r\n\r\n// ─── Type guards ────────────────────────────────────────────────────────────\r\n\r\n/** `true` se `v` é qualquer sentinel de campo Neetru. */\r\nexport function isFieldSentinel(v: unknown): v is FieldSentinel {\r\n return (\r\n typeof v === 'object' &&\r\n v !== null &&\r\n NEETRU_SENTINEL_KEY in v &&\r\n typeof (v as Record<string, unknown>)[NEETRU_SENTINEL_KEY] === 'string'\r\n );\r\n}\r\n\r\n/** `true` se `v` é o sentinel `serverTimestamp()`. */\r\nexport function isServerTimestampSentinel(v: unknown): v is ServerTimestampSentinel {\r\n return isFieldSentinel(v) && v.__neetru__ === 'serverTimestamp';\r\n}\r\n\r\n/** `true` se `v` é o sentinel `increment(n)` com `operand` numérico válido. */\r\nexport function isIncrementSentinel(v: unknown): v is IncrementSentinel {\r\n return (\r\n isFieldSentinel(v) &&\r\n v.__neetru__ === 'increment' &&\r\n typeof (v as IncrementSentinel).operand === 'number' &&\r\n Number.isFinite((v as IncrementSentinel).operand)\r\n );\r\n}\r\n\r\n// ─── Aplicação otimista local (offline-first) ────────────────────────────────\r\n\r\n/**\r\n * Resolve sentinels para valores LOCAIS aproximados, para aplicação otimista\r\n * no cache offline. O valor canônico vem sempre do servidor no sync seguinte.\r\n *\r\n * - `serverTimestamp()` → `Date.now()` (epoch ms local).\r\n * - `increment(n)` → `baseValue` numérico atual (ou 0) + n.\r\n * - valores normais → retornados inalterados.\r\n *\r\n * @param value — o valor do campo (pode ser sentinel ou valor literal).\r\n * @param baseValue — valor atual do campo no doc existente (para increment).\r\n */\r\nexport function resolveSentinelLocally(value: unknown, baseValue: unknown): unknown {\r\n if (isServerTimestampSentinel(value)) {\r\n return Date.now();\r\n }\r\n if (isIncrementSentinel(value)) {\r\n const base = typeof baseValue === 'number' && Number.isFinite(baseValue) ? baseValue : 0;\r\n return base + value.operand;\r\n }\r\n return value;\r\n}\r\n\r\n/**\r\n * Aplica `resolveSentinelLocally` a cada campo top-level de `data`, usando\r\n * `existing` como base para increments. Não recursa em objetos aninhados\r\n * (sentinels só são suportados em campos top-level, espelhando a resolução\r\n * top-level do Core).\r\n *\r\n * @param data — payload da mutação (pode conter sentinels).\r\n * @param existing — dados atuais do documento (para base de increment).\r\n */\r\nexport function resolveSentinelsLocally(\r\n data: Record<string, unknown>,\r\n existing: Record<string, unknown> | undefined,\r\n): Record<string, unknown> {\r\n let touched = false;\r\n const out: Record<string, unknown> = {};\r\n for (const [k, v] of Object.entries(data)) {\r\n if (isFieldSentinel(v)) {\r\n touched = true;\r\n out[k] = resolveSentinelLocally(v, existing?.[k]);\r\n } else {\r\n out[k] = v;\r\n }\r\n }\r\n // Micro-opt: se nenhum sentinel, devolve o objeto original (evita realocar).\r\n return touched ? out : data;\r\n}\r\n\r\n/** `true` se algum campo top-level de `data` é um sentinel. */\r\nexport function hasFieldSentinel(data: Record<string, unknown>): boolean {\r\n for (const v of Object.values(data)) {\r\n if (isFieldSentinel(v)) return true;\r\n }\r\n return false;\r\n}\r\n","/**\r\n * SyncEngine — orquestrador da camada offline do @neetru/sdk.\r\n *\r\n * Implementa as 3 fases de sincronização definidas em I3 §6:\r\n *\r\n * FASE 1 — DRENAR A FILA (push)\r\n * Envia mutações pendentes ao Core via SyncTransport.\r\n * Cada mutação é marcada inflight, enviada e depois:\r\n * - CONFIRMADA → removida da fila (markApplied)\r\n * - SUPERADA (LWW)→ ConflictRecord gravado, cache atualizado\r\n * - REJEITADA → resolveRejected + ConflictRecord + removida\r\n * - FALHA TRANSIENTE → markRetry + PARA a drenagem (ordem preservada)\r\n *\r\n * FASE 2 — RECONCILIAR O CACHE (pull)\r\n * Busca mudanças do servidor desde o watermark ou resume token.\r\n * Cada documento passa pelo ConflictResolver (LWW) e é gravado no LocalStore.\r\n * Changes são emitidos pelo ChangeBus.\r\n * Se `resyncRequired` → aciona full resync em vez de pull incremental.\r\n *\r\n * FASE 3 — REABRIR LISTENERS (realtime)\r\n * Atualiza SyncState para refletir que o cache está reconciliado.\r\n * O ChangeBus já foi alimentado nas fases anteriores — os listeners\r\n * ativos na camada superior (onSnapshot/onDoc) recebem snapshots frescos.\r\n *\r\n * Garantias:\r\n * - SOMENTE a aba LÍDER executa o sync (TabCoordinator.isLeader()).\r\n * - Re-entrante-safe: um sync em progresso bloqueia novos disparos.\r\n * - Fail-closed: falha transiente retém a mutação; falha de pull não\r\n * corrompe o cache nem o watermark.\r\n * - Idempotente: o SyncTransport usa mutationId como chave de idempotência.\r\n *\r\n * O SyncTransport é INJETADO — a ligação real com o Core acontece na camada\r\n * de adaptação, não aqui. Isso torna o SyncEngine 100% testável com fake.\r\n */\r\n\r\nimport type { LocalStore } from './local-store';\r\nimport type { MutationQueue } from './mutation-queue';\r\nimport type { ConflictResolver } from './conflict-resolver';\r\nimport type { ChangeBus } from './change-bus';\r\nimport type { Mutation, SyncState, Change, Unsubscribe } from './types';\r\nimport { isFieldSentinel, hasFieldSentinel } from '../field-value';\r\n\r\n// ─── Helpers de sentinel (defesa do cache contra marcadores crus) ─────────────\r\n\r\n/** `true` se o payload da mutação contém ao menos um sentinel cru top-level. */\r\nfunction hasSentinels(payload: Record<string, unknown> | null): boolean {\r\n return payload !== null && hasFieldSentinel(payload);\r\n}\r\n\r\n/**\r\n * Remove campos-sentinel CRUS (`{__neetru__:...}`) de um payload de mutação,\r\n * devolvendo só os campos LITERAIS. Garante que um marcador cru nunca aterre no\r\n * LocalStore num confirm que não trouxe `serverData`.\r\n *\r\n * - `null` → `null` (passa direto; ex.: `remove`).\r\n * - sem sentinel → devolve o mesmo objeto (evita realocar).\r\n * - com sentinel → novo objeto só com os campos literais (sentinels DROPADOS;\r\n * a aproximação otimista deles já vive em `existing.data`).\r\n */\r\nfunction sanitizeSentinelPayload(\r\n payload: Record<string, unknown> | null,\r\n): Record<string, unknown> | null {\r\n if (payload === null) return null;\r\n if (!hasFieldSentinel(payload)) return payload;\r\n const out: Record<string, unknown> = {};\r\n for (const [k, v] of Object.entries(payload)) {\r\n if (!isFieldSentinel(v)) out[k] = v;\r\n }\r\n return out;\r\n}\r\n\r\n// ─── SyncTransport — interface injetável ──────────────────────────────────────\r\n\r\n/**\r\n * Documento retornado pelo servidor em push/pull/resync.\r\n */\r\nexport interface ServerDoc {\r\n collection: string;\r\n id: string;\r\n data: Record<string, unknown>;\r\n serverVersion: string;\r\n serverTimestamp: number;\r\n /** `true` se o doc foi deletado no servidor. */\r\n deleted: boolean;\r\n}\r\n\r\n/**\r\n * Resultado individual de uma mutação enviada ao Core (FASE 1).\r\n */\r\nexport type MutationResult =\r\n | {\r\n mutationId: string;\r\n outcome: 'confirmed';\r\n serverVersion: string;\r\n serverTimestamp: number;\r\n }\r\n | {\r\n mutationId: string;\r\n outcome: 'superseded';\r\n serverVersion: string;\r\n serverTimestamp: number;\r\n serverData: Record<string, unknown>;\r\n }\r\n | {\r\n mutationId: string;\r\n outcome: 'rejected';\r\n reason: 'rejected_permission' | 'rejected_validation';\r\n serverVersion: string | null;\r\n serverData: Record<string, unknown> | null;\r\n };\r\n\r\n/** Retorno de pushMutations. */\r\nexport interface PushMutationsResult {\r\n results: MutationResult[];\r\n}\r\n\r\n/** Retorno de pullChanges. */\r\nexport interface PullChangesResult {\r\n docs: ServerDoc[];\r\n newWatermark: number | null;\r\n /** `true` quando o resume token / watermark ficou inválido (gap grande). */\r\n resyncRequired: boolean;\r\n}\r\n\r\n/** Retorno de fullResync. */\r\nexport interface FullResyncResult {\r\n docs: ServerDoc[];\r\n newWatermark: number | null;\r\n}\r\n\r\n/**\r\n * Contrato do transporte de sync — injetado no SyncEngine.\r\n *\r\n * A implementação real usa os endpoints `/api/sdk/v1/db/*` do Core.\r\n * Em testes, usa-se um FakeSyncTransport.\r\n *\r\n * Per I3 §6:\r\n * - `pushMutations` → FASE 1: envia mutações em ordem de seq.\r\n * - `pullChanges` → FASE 2: busca delta desde o watermark/resumeToken.\r\n * - `fullResync` → FASE 2 (fallback): lista completa das coleções ativas.\r\n */\r\nexport interface SyncTransport {\r\n /**\r\n * Envia um lote de mutações ao Core.\r\n * O Core aplica, verifica conflito LWW e retorna um resultado por mutação.\r\n * A ordem do array deve ser preservada (seq crescente).\r\n */\r\n pushMutations(mutations: Mutation[]): Promise<PushMutationsResult>;\r\n\r\n /**\r\n * Busca documentos modificados no servidor desde `sinceWatermark`.\r\n * `sinceWatermark === null` indica primeiro sync (sem base conhecida).\r\n * `resumeToken` é o token de change stream (nosql-vm); pode ser null.\r\n *\r\n * Retorna `resyncRequired: true` se o gap é grande demais para pull incremental.\r\n */\r\n pullChanges(\r\n sinceWatermark: number | null,\r\n resumeToken: string | null,\r\n ): Promise<PullChangesResult>;\r\n\r\n /**\r\n * Faz um full resync das coleções informadas.\r\n * Retorna TODOS os documentos atuais (paginado internamente pelo transporte).\r\n * Docs ausentes na resposta foram deletados durante o gap.\r\n */\r\n fullResync(collections: string[]): Promise<FullResyncResult>;\r\n\r\n /**\r\n * (Opcional) Registra uma subscription realtime para uma coleção específica.\r\n *\r\n * Implementado pelo WebSocket transport (nosql-vm): chama\r\n * `NeetruRealtimeClient.subscribe()` e alimenta os frames delta/resync\r\n * no `ChangeBus` da camada offline.\r\n *\r\n * Transportes REST e Firestore não implementam este método (undefined).\r\n * O chamador (`DbCollectionRefImpl.onSnapshot`) verifica antes de invocar.\r\n *\r\n * @param collection - Nome da coleção a subscrever.\r\n * @param onChange - Callback que recebe changes quando um delta/resync chega.\r\n * `null` payload = resync full necessário.\r\n * @returns Função de unsubscribe.\r\n */\r\n subscribeCollection?: (\r\n collection: string,\r\n onChange: (\r\n changes: Array<{ type: 'added' | 'modified' | 'removed'; docId: string; data: Record<string, unknown> | null }>,\r\n needsResync: boolean,\r\n ) => void,\r\n ) => () => void;\r\n}\r\n\r\n// ─── Interface dos colaboradores (subset usado pelo SyncEngine) ───────────────\r\n\r\n/** Subset de TabCoordinator usado pelo SyncEngine. */\r\ninterface TabCoordinatorLike {\r\n isLeader(): boolean;\r\n onRoleChange(cb: (role: 'leader' | 'follower') => void): Unsubscribe;\r\n}\r\n\r\n/** Subset de ConnectivityMonitor usado pelo SyncEngine. */\r\ninterface ConnectivityMonitorLike {\r\n readonly isOnline: boolean;\r\n subscribe(cb: (state: 'online' | 'offline') => void): Unsubscribe;\r\n}\r\n\r\n// ─── Opções de configuração ───────────────────────────────────────────────────\r\n\r\nexport interface SyncEngineOptions {\r\n store: LocalStore;\r\n queue: MutationQueue;\r\n resolver: ConflictResolver;\r\n bus: ChangeBus;\r\n transport: SyncTransport;\r\n tabCoordinator: TabCoordinatorLike;\r\n connectivity: ConnectivityMonitorLike;\r\n /**\r\n * Intervalo do resync periódico em ms.\r\n * `0` desativa (útil em testes). Default: 5 * 60 * 1000 (5 min).\r\n */\r\n periodicSyncIntervalMs?: number;\r\n}\r\n\r\n// ─── SyncEngine ───────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * SyncEngine — orquestra as 3 fases de sincronização offline (I3 §6).\r\n *\r\n * ```ts\r\n * const engine = new SyncEngine({ store, queue, resolver, bus, transport,\r\n * tabCoordinator, connectivity });\r\n *\r\n * // Estado atual (snapshot síncrono)\r\n * const state = engine.getSyncState();\r\n *\r\n * // Observar mudanças de estado\r\n * const unsub = engine.onSyncStateChange((s) => console.log(s));\r\n *\r\n * // Forçar sync imediato (ex.: botão \"sincronizar agora\")\r\n * await engine.flush();\r\n *\r\n * // Teardown\r\n * engine.destroy();\r\n * ```\r\n *\r\n * O engine também é disparado automaticamente por:\r\n * - transição offline → online (ConnectivityMonitor)\r\n * - promoção a líder (TabCoordinator.onRoleChange)\r\n * - periodicSyncIntervalMs (resync de segurança)\r\n */\r\nexport class SyncEngine {\r\n private readonly _store: LocalStore;\r\n private readonly _queue: MutationQueue;\r\n private readonly _resolver: ConflictResolver;\r\n private readonly _bus: ChangeBus;\r\n private readonly _transport: SyncTransport;\r\n private readonly _tabCoordinator: TabCoordinatorLike;\r\n private readonly _connectivity: ConnectivityMonitorLike;\r\n\r\n /** `true` se um sync está atualmente em progresso — guarda re-entrância. */\r\n private _syncing = false;\r\n\r\n /** `true` se destroy() foi chamado. */\r\n private _destroyed = false;\r\n\r\n /**\r\n * Conjunto de coleções \"conhecidas\" pelo engine.\r\n * Populado ao aplicar docs do servidor (Fase 1 e 2) e ao ler do cache.\r\n * Persiste em sync_meta['activeCollections'] para sobreviver a reloads.\r\n */\r\n private _activeCollections = new Set<string>();\r\n\r\n /** Estado de sync atual (fonte de verdade em RAM). */\r\n private _state: SyncState;\r\n\r\n /** Listeners de mudança de SyncState. */\r\n private readonly _stateListeners = new Set<(state: SyncState) => void>();\r\n\r\n /** Cleanup functions dos listeners externos. */\r\n private readonly _cleanups: Unsubscribe[] = [];\r\n\r\n /** Timer de resync periódico. */\r\n private _periodicTimer: ReturnType<typeof setInterval> | null = null;\r\n\r\n constructor(opts: SyncEngineOptions) {\r\n this._store = opts.store;\r\n this._queue = opts.queue;\r\n this._resolver = opts.resolver;\r\n this._bus = opts.bus;\r\n this._transport = opts.transport;\r\n this._tabCoordinator = opts.tabCoordinator;\r\n this._connectivity = opts.connectivity;\r\n\r\n // Estado inicial\r\n this._state = this._buildInitialState();\r\n\r\n // Conecta os gatilhos externos\r\n this._wireListeners();\r\n\r\n // Timer periódico\r\n const intervalMs = opts.periodicSyncIntervalMs ?? 5 * 60 * 1000;\r\n if (intervalMs > 0) {\r\n this._periodicTimer = setInterval(() => {\r\n this._triggerSync('periodic');\r\n }, intervalMs);\r\n }\r\n }\r\n\r\n // ─── API pública ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Expõe o transporte de sync para acesso direto por `DbCollectionRefImpl`.\r\n * Necessário para que `onSnapshot` possa chamar `subscribeCollection` no\r\n * transport nosql-vm (HIGH-1 fix — realtime deltas).\r\n */\r\n get transport(): SyncTransport {\r\n return this._transport;\r\n }\r\n\r\n /**\r\n * Retorna o estado de sync atual (snapshot síncrono).\r\n * Equivale a `client.db.syncState` na API pública do SDK (I3 §10.3).\r\n *\r\n * `pendingWrites` reflete o valor mais recente calculado de forma assíncrona.\r\n * Para garantir o valor mais atualizado, aguarde `refreshPendingWrites()` antes.\r\n */\r\n getSyncState(): SyncState {\r\n return { ...this._state };\r\n }\r\n\r\n /**\r\n * Força a atualização de `pendingWrites` e retorna o estado atualizado.\r\n * Útil quando o chamador precisa do pendingWrites fresco sem aguardar um sync.\r\n */\r\n async refreshPendingWrites(): Promise<SyncState> {\r\n await this._refreshPendingWrites();\r\n return { ...this._state };\r\n }\r\n\r\n /**\r\n * Registra um listener de mudanças no SyncState.\r\n * Retorna uma função de unsubscribe.\r\n */\r\n onSyncStateChange(cb: (state: SyncState) => void): Unsubscribe {\r\n this._stateListeners.add(cb);\r\n return () => {\r\n this._stateListeners.delete(cb);\r\n };\r\n }\r\n\r\n /**\r\n * Força um sync imediato (I3 §10.3 `flush()`).\r\n * Resolve quando a fila esvazia OU rejeita se o engine estiver destruído.\r\n */\r\n async flush(): Promise<void> {\r\n if (this._destroyed) return;\r\n await this.sync();\r\n }\r\n\r\n /**\r\n * Executa as 3 fases de sincronização.\r\n *\r\n * Guarda re-entrância: se já está em progresso, retorna imediatamente.\r\n * NÃO executa se esta aba não é líder ou se está offline.\r\n */\r\n async sync(): Promise<void> {\r\n if (this._destroyed) return;\r\n\r\n // Somente o líder sincroniza (I3 §6.1)\r\n if (!this._tabCoordinator.isLeader()) return;\r\n\r\n // Offline — não tenta sincronizar\r\n if (!this._connectivity.isOnline) return;\r\n\r\n // Re-entrância: não double-run\r\n if (this._syncing) return;\r\n\r\n this._syncing = true;\r\n this._updateState({ status: 'syncing' });\r\n\r\n try {\r\n // ── FASE 1: DRENAR A FILA (push) ────────────────────────────────────────\r\n const phase1Ok = await this._phase1Push();\r\n if (!phase1Ok) {\r\n // Falha transiente na Fase 1 — aborta o ciclo (I3 §6.2: PARA a drenagem).\r\n // bug: sem refresh o pendingWrites ficava desatualizado após markRetry()\r\n this._updateState({ status: 'idle' });\r\n this._refreshPendingWrites().catch(() => {});\r\n this._syncing = false;\r\n return;\r\n }\r\n\r\n // ── FASE 2: RECONCILIAR O CACHE (pull) ──────────────────────────────────\r\n await this._phase2Pull();\r\n\r\n // ── FASE 3: REABRIR LISTENERS (realtime) ─────────────────────────────────\r\n this._phase3Realtime();\r\n\r\n // Atualiza lastSyncedAt\r\n this._updateState({ status: 'idle', lastSyncedAt: Date.now() });\r\n } catch (err) {\r\n // Erro inesperado nas fases — log silencioso, estado de erro\r\n this._updateState({ status: 'idle' });\r\n } finally {\r\n this._syncing = false;\r\n }\r\n }\r\n\r\n /**\r\n * Teardown: para timers, remove listeners, marca como destroyed.\r\n */\r\n destroy(): void {\r\n if (this._destroyed) return;\r\n this._destroyed = true;\r\n\r\n if (this._periodicTimer !== null) {\r\n clearInterval(this._periodicTimer);\r\n this._periodicTimer = null;\r\n }\r\n\r\n for (const cleanup of this._cleanups) {\r\n try { cleanup(); } catch { /* silencioso */ }\r\n }\r\n this._cleanups.length = 0;\r\n this._stateListeners.clear();\r\n }\r\n\r\n // ─── FASE 1 — push (drenar a fila) ───────────────────────────────────────────\r\n\r\n /**\r\n * Drena a MutationQueue, enviando mutações em ordem de seq.\r\n *\r\n * Retorna `true` se a fase completou sem falhas transientes.\r\n * Retorna `false` se houve falha transiente (ciclo deve ser abortado).\r\n */\r\n private async _phase1Push(): Promise<boolean> {\r\n const mutations = await this._queue.drain();\r\n if (mutations.length === 0) return true;\r\n\r\n // Marca todas como inflight\r\n for (const mut of mutations) {\r\n await this._queue.markInflight(mut.mutationId);\r\n }\r\n\r\n let result: PushMutationsResult;\r\n try {\r\n result = await this._transport.pushMutations(mutations);\r\n } catch (err) {\r\n // Falha transiente no transporte — volta todas para queued\r\n for (const mut of mutations) {\r\n const errMsg = err instanceof Error ? err.message : String(err);\r\n await this._queue.markRetry(mut.mutationId, errMsg);\r\n }\r\n return false; // aborta o ciclo\r\n }\r\n\r\n // Processa resultados\r\n const busChanges: Change[] = [];\r\n\r\n for (const res of result.results) {\r\n const mut = mutations.find((m) => m.mutationId === res.mutationId);\r\n if (!mut) continue;\r\n\r\n if (res.outcome === 'confirmed') {\r\n // Sucesso — remove da fila e atualiza doc no cache\r\n await this._queue.markApplied(mut.mutationId);\r\n await this._applySyncedDoc(\r\n mut.collection,\r\n mut.docId,\r\n res.serverVersion,\r\n res.serverTimestamp,\r\n mut,\r\n busChanges,\r\n );\r\n } else if (res.outcome === 'superseded') {\r\n // LWW: escrita local foi superada pelo servidor\r\n await this._queue.markApplied(mut.mutationId);\r\n await this._applySuperseded(mut, res, busChanges);\r\n } else if (res.outcome === 'rejected') {\r\n // Rejeição permanente\r\n await this._queue.markApplied(mut.mutationId); // remove da fila\r\n await this._applyRejected(mut, res, busChanges);\r\n }\r\n }\r\n\r\n if (busChanges.length > 0) {\r\n this._bus.emit(busChanges);\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /** Atualiza o cache após confirmação de escrita (outcome=confirmed). */\r\n private async _applySyncedDoc(\r\n collection: string,\r\n docId: string,\r\n serverVersion: string,\r\n serverTimestamp: number,\r\n mut: Mutation,\r\n busChanges: Change[],\r\n ): Promise<void> {\r\n const existing = await this._store.getDoc(collection, docId);\r\n\r\n if (mut.op === 'remove') {\r\n // Remoção confirmada → tombstone\r\n if (existing) {\r\n await this._store.putDoc({\r\n ...existing,\r\n meta: {\r\n ...existing.meta,\r\n serverVersion,\r\n updatedAtServer: serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced',\r\n deleted: true,\r\n pendingMutationIds: [],\r\n },\r\n });\r\n busChanges.push({ type: 'removed', collection, doc: { id: docId, data: existing.data } });\r\n }\r\n return;\r\n }\r\n\r\n // O payload da mutação carrega os sentinels CRUS (`serverTimestamp()` /\r\n // `increment()`) — eles existem só para o Core resolver no wire. Um outcome\r\n // 'confirmed' traz apenas serverVersion/serverTimestamp, NUNCA serverData, então\r\n // NÃO podemos gravar `mut.payload` cru no cache: isso vazaria `{__neetru__:...}`\r\n // para qualquer get()/onSnapshot() lido antes do próximo pull completo.\r\n //\r\n // O cache local JÁ contém a aproximação otimista escrita em add()/set()/update()\r\n // (números/timestamps, base de increment já somada). Quando o payload tem\r\n // sentinels, preservamos esse `existing.data` otimista em vez de re-resolver\r\n // (re-resolver contra `existing.data` somaria o increment de novo — double-count).\r\n // Só campos LITERAIS do payload são re-aplicados por cima (merge p/ update).\r\n const literalPayload = sanitizeSentinelPayload(mut.payload);\r\n const newData = literalPayload ?? (existing?.data ?? {});\r\n const updatedDoc = {\r\n collection,\r\n id: docId,\r\n data:\r\n mut.op === 'update'\r\n ? { ...(existing?.data ?? {}), ...newData }\r\n : // add/set: se o payload tinha sentinels, o cache otimista (existing.data)\r\n // é a fonte de verdade até o pull; senão usa o payload literal.\r\n hasSentinels(mut.payload)\r\n ? { ...(existing?.data ?? {}), ...newData }\r\n : newData,\r\n meta: {\r\n serverVersion,\r\n updatedAtServer: serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced' as const,\r\n pendingMutationIds: [],\r\n deleted: false,\r\n ownerId: existing?.meta.ownerId ?? null,\r\n },\r\n };\r\n\r\n await this._store.putDoc(updatedDoc);\r\n busChanges.push({\r\n type: existing ? 'modified' : 'added',\r\n collection,\r\n doc: { id: docId, data: updatedDoc.data },\r\n });\r\n }\r\n\r\n /** Processa resultado 'superseded' (LWW: servidor venceu). */\r\n private async _applySuperseded(\r\n mut: Mutation,\r\n res: Extract<MutationResult, { outcome: 'superseded' }>,\r\n busChanges: Change[],\r\n ): Promise<void> {\r\n const localDoc = await this._store.getDoc(mut.collection, mut.docId);\r\n\r\n // Constrói envelope do servidor com timestamp maior para forçar server_wins\r\n const serverDocEnvelope = {\r\n collection: mut.collection,\r\n id: mut.docId,\r\n data: res.serverData,\r\n meta: {\r\n serverVersion: res.serverVersion,\r\n updatedAtServer: res.serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced' as const,\r\n pendingMutationIds: [],\r\n deleted: false,\r\n ownerId: localDoc?.meta.ownerId ?? null,\r\n },\r\n };\r\n\r\n // Usa ConflictResolver para gerar o ConflictRecord\r\n // Cria um doc local com updatedAtServer anterior para garantir server_wins\r\n const localDocForResolver = localDoc ?? {\r\n collection: mut.collection,\r\n id: mut.docId,\r\n data: (mut.payload ?? {}) as Record<string, unknown>,\r\n meta: {\r\n serverVersion: mut.baseVersion,\r\n updatedAtServer: res.serverTimestamp - 1, // garante server é mais novo\r\n updatedAtLocal: mut.enqueuedAt,\r\n state: 'pending' as const,\r\n pendingMutationIds: [mut.mutationId],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n };\r\n\r\n const resolveResult = this._resolver.resolve(\r\n localDocForResolver,\r\n serverDocEnvelope,\r\n mut,\r\n );\r\n\r\n // Sempre grava ConflictRecord em superseded (independente do resultado do resolver)\r\n const conflictRecord = resolveResult.conflictRecord ?? {\r\n collection: mut.collection,\r\n docId: mut.docId,\r\n mutationId: mut.mutationId,\r\n losingData: (mut.payload ?? {}) as Record<string, unknown>,\r\n winningData: res.serverData,\r\n reason: 'lww_server_newer' as const,\r\n detectedAt: Date.now(),\r\n delivered: false,\r\n };\r\n await this._store.appendConflict(conflictRecord);\r\n\r\n // Atualiza cache com o dado do servidor\r\n const updatedDoc = {\r\n collection: mut.collection,\r\n id: mut.docId,\r\n data: res.serverData,\r\n meta: {\r\n serverVersion: res.serverVersion,\r\n updatedAtServer: res.serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced' as const,\r\n pendingMutationIds: [],\r\n deleted: false,\r\n ownerId: localDoc?.meta.ownerId ?? null,\r\n },\r\n };\r\n await this._store.putDoc(updatedDoc);\r\n busChanges.push({\r\n type: localDoc ? 'modified' : 'added',\r\n collection: mut.collection,\r\n doc: { id: mut.docId, data: res.serverData },\r\n });\r\n }\r\n\r\n /** Processa resultado 'rejected' (permissão/validação negada). */\r\n private async _applyRejected(\r\n mut: Mutation,\r\n res: Extract<MutationResult, { outcome: 'rejected' }>,\r\n busChanges: Change[],\r\n ): Promise<void> {\r\n // Obtém ou reconstrói o doc local para o resolver\r\n const storedDoc = await this._store.getDoc(mut.collection, mut.docId);\r\n const localDoc = storedDoc ?? {\r\n collection: mut.collection,\r\n id: mut.docId,\r\n data: (mut.payload ?? {}) as Record<string, unknown>,\r\n meta: {\r\n serverVersion: mut.baseVersion,\r\n updatedAtServer: null,\r\n updatedAtLocal: mut.enqueuedAt,\r\n state: 'pending' as const,\r\n pendingMutationIds: [mut.mutationId],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n };\r\n\r\n const serverDocEnvelope = res.serverData\r\n ? {\r\n ...localDoc,\r\n data: res.serverData,\r\n meta: {\r\n ...localDoc.meta,\r\n serverVersion: res.serverVersion ?? localDoc.meta.serverVersion,\r\n },\r\n }\r\n : null;\r\n\r\n const resolveResult = this._resolver.resolveRejected(\r\n localDoc,\r\n serverDocEnvelope,\r\n mut,\r\n res.reason,\r\n );\r\n\r\n // Sempre grava ConflictRecord em rejected\r\n const conflictRecord = resolveResult.conflictRecord ?? {\r\n collection: mut.collection,\r\n docId: mut.docId,\r\n mutationId: mut.mutationId,\r\n losingData: (mut.payload ?? {}) as Record<string, unknown>,\r\n winningData: (res.serverData ?? {}) as Record<string, unknown>,\r\n reason: res.reason,\r\n detectedAt: Date.now(),\r\n delivered: false,\r\n };\r\n await this._store.appendConflict(conflictRecord);\r\n\r\n // Reverte cache ao estado do servidor (ou mantém se não há serverData)\r\n if (res.serverData) {\r\n await this._store.putDoc({\r\n ...localDoc,\r\n data: res.serverData,\r\n meta: {\r\n ...localDoc.meta,\r\n state: 'synced',\r\n pendingMutationIds: [],\r\n },\r\n });\r\n busChanges.push({\r\n type: 'modified',\r\n collection: mut.collection,\r\n doc: { id: mut.docId, data: res.serverData },\r\n });\r\n } else {\r\n // Sem dado do servidor → mantém o que há, mas limpa pendências\r\n await this._store.putDoc({\r\n ...localDoc,\r\n meta: {\r\n ...localDoc.meta,\r\n state: 'synced',\r\n pendingMutationIds: [],\r\n },\r\n });\r\n }\r\n }\r\n\r\n // ─── FASE 2 — pull (reconciliar o cache) ─────────────────────────────────────\r\n\r\n /**\r\n * Busca mudanças do servidor e aplica ao cache via ConflictResolver.\r\n *\r\n * Se `resyncRequired === true`, faz full resync em vez de pull incremental.\r\n */\r\n private async _phase2Pull(): Promise<void> {\r\n const watermark = (await this._store.getMeta('lastSyncWatermark')) as number | null;\r\n const resumeToken = (await this._store.getMeta('lastResumeToken')) as string | null;\r\n\r\n let pullResult: PullChangesResult;\r\n try {\r\n pullResult = await this._transport.pullChanges(watermark, resumeToken);\r\n } catch {\r\n // Falha no pull — não corrompe cache nem watermark; tenta no próximo ciclo\r\n return;\r\n }\r\n\r\n if (pullResult.resyncRequired) {\r\n await this._phase2FullResync();\r\n return;\r\n }\r\n\r\n // Pull incremental bem-sucedido\r\n const busChanges: Change[] = [];\r\n await this._applyServerDocs(pullResult.docs, busChanges, false);\r\n\r\n if (pullResult.newWatermark !== null) {\r\n await this._store.setMeta('lastSyncWatermark', pullResult.newWatermark);\r\n }\r\n\r\n if (busChanges.length > 0) {\r\n this._bus.emit(busChanges);\r\n }\r\n }\r\n\r\n /** Full resync: lista completa + detecta deleções por ausência. */\r\n private async _phase2FullResync(): Promise<void> {\r\n // Coleta as coleções que têm documentos no cache local\r\n const collections = await this._getActiveCollections();\r\n\r\n let resyncResult: FullResyncResult;\r\n try {\r\n resyncResult = await this._transport.fullResync(collections);\r\n } catch {\r\n // Falha no resync — não corrompe cache; tenta no próximo ciclo\r\n return;\r\n }\r\n\r\n const busChanges: Change[] = [];\r\n\r\n // Aplica os docs retornados\r\n await this._applyServerDocs(resyncResult.docs, busChanges, true);\r\n\r\n // Detecta deleções: docs locais que não vieram no resync → tombstone (I3 §6.3)\r\n const returnedKeys = new Set(\r\n resyncResult.docs.map((d) => `${d.collection}::${d.id}`),\r\n );\r\n\r\n for (const col of collections) {\r\n // listDocs retorna { id, data } sem meta — precisamos dos docs completos\r\n const queryResult = await this._store.listDocs(col, {});\r\n for (const { id } of queryResult.docs) {\r\n const key = `${col}::${id}`;\r\n if (!returnedKeys.has(key)) {\r\n // Busca o doc completo com meta para verificar e atualizar\r\n const fullDoc = await this._store.getDoc(col, id);\r\n if (fullDoc && !fullDoc.meta.deleted) {\r\n // Doc sumiu do servidor → tombstone\r\n await this._store.putDoc({\r\n ...fullDoc,\r\n meta: {\r\n ...fullDoc.meta,\r\n deleted: true,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced',\r\n },\r\n });\r\n busChanges.push({\r\n type: 'removed',\r\n collection: col,\r\n doc: { id, data: fullDoc.data },\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (resyncResult.newWatermark !== null) {\r\n await this._store.setMeta('lastSyncWatermark', resyncResult.newWatermark);\r\n }\r\n await this._store.setMeta('lastFullResyncAt', Date.now());\r\n\r\n if (busChanges.length > 0) {\r\n this._bus.emit(busChanges);\r\n }\r\n }\r\n\r\n /**\r\n * Aplica uma lista de ServerDoc ao cache local via ConflictResolver.\r\n *\r\n * `isFullResync = true` indica que o conjunto é completo — usamos isso para\r\n * otimizar a path (sempre sobrescreve docs synced; pending passam pelo LWW).\r\n */\r\n private async _applyServerDocs(\r\n docs: ServerDoc[],\r\n busChanges: Change[],\r\n _isFullResync: boolean,\r\n ): Promise<void> {\r\n for (const serverDoc of docs) {\r\n const localDoc = await this._store.getDoc(serverDoc.collection, serverDoc.id);\r\n\r\n if (serverDoc.deleted) {\r\n // Doc deletado no servidor → tombstone\r\n if (localDoc && !localDoc.meta.deleted) {\r\n await this._store.putDoc({\r\n ...localDoc,\r\n meta: {\r\n ...localDoc.meta,\r\n deleted: true,\r\n serverVersion: serverDoc.serverVersion,\r\n updatedAtServer: serverDoc.serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced',\r\n },\r\n });\r\n busChanges.push({\r\n type: 'removed',\r\n collection: serverDoc.collection,\r\n doc: { id: serverDoc.id, data: localDoc.data },\r\n });\r\n }\r\n continue;\r\n }\r\n\r\n // Se o doc local está 'pending' (tem mutações não enviadas ainda),\r\n // passa pelo ConflictResolver (§6.2: não sobrescreve cegamente).\r\n // Na prática, após a Fase 1 a maioria dos pendentes já virou synced.\r\n if (localDoc && localDoc.meta.state === 'pending') {\r\n // Constrói envelope do servidor para o resolver\r\n const serverEnvelope = {\r\n collection: serverDoc.collection,\r\n id: serverDoc.id,\r\n data: serverDoc.data,\r\n meta: {\r\n serverVersion: serverDoc.serverVersion,\r\n updatedAtServer: serverDoc.serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced' as const,\r\n pendingMutationIds: [],\r\n deleted: false,\r\n ownerId: localDoc.meta.ownerId,\r\n },\r\n };\r\n\r\n // Busca a primeira mutação pendente para este doc (para o resolver).\r\n // bug: drain() retorna só 'queued', perdendo mutações 'inflight' — usar listAll()\r\n const pendingMuts = await this._queue.listAll();\r\n const docMut = pendingMuts.find(\r\n (m) => m.collection === serverDoc.collection && m.docId === serverDoc.id,\r\n );\r\n\r\n if (docMut) {\r\n const result = this._resolver.resolve(localDoc, serverEnvelope, docMut);\r\n if (result.conflictRecord) {\r\n await this._store.appendConflict(result.conflictRecord);\r\n }\r\n // Marca o doc como conflito para resolver na próxima Fase 1\r\n await this._store.putDoc({\r\n ...localDoc,\r\n meta: { ...localDoc.meta, state: 'conflict' },\r\n });\r\n continue;\r\n }\r\n }\r\n\r\n // Doc local synced ou não existente → sobrescreve com servidor\r\n const isNew = !localDoc;\r\n const newDoc = {\r\n collection: serverDoc.collection,\r\n id: serverDoc.id,\r\n data: serverDoc.data,\r\n meta: {\r\n serverVersion: serverDoc.serverVersion,\r\n updatedAtServer: serverDoc.serverTimestamp,\r\n updatedAtLocal: Date.now(),\r\n state: 'synced' as const,\r\n pendingMutationIds: [],\r\n deleted: false,\r\n ownerId: localDoc?.meta.ownerId ?? null,\r\n },\r\n };\r\n await this._store.putDoc(newDoc);\r\n busChanges.push({\r\n type: isNew ? 'added' : 'modified',\r\n collection: serverDoc.collection,\r\n doc: { id: serverDoc.id, data: serverDoc.data },\r\n });\r\n }\r\n }\r\n\r\n // ─── FASE 3 — reabre listeners (realtime) ─────────────────────────────────────\r\n\r\n /**\r\n * Fase 3: sinaliza que o cache está reconciliado.\r\n *\r\n * O transporte de tempo real (Firestore onSnapshot / WebSocket) é gerido\r\n * pela camada superior — aqui apenas garantimos que o SyncState reflita\r\n * o término do sync, o que notifica os listeners `onSyncStateChange` e\r\n * transitivamente os `onSnapshot` da UI.\r\n */\r\n private _phase3Realtime(): void {\r\n // O ChangeBus já foi alimentado nas Fases 1 e 2.\r\n // A Fase 3 garante que o estado de sync reflita \"cache fresco\".\r\n // Em implementação futura, reabre o WebSocket ou onSnapshot do Firestore.\r\n // Por ora, o sinal é a mudança de status para 'idle' + lastSyncedAt.\r\n }\r\n\r\n // ─── Helpers ──────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna a lista de coleções com documentos no cache local.\r\n * Usado pelo full resync para saber quais coleções checar.\r\n *\r\n * Combina:\r\n * 1. Set em memória `_activeCollections` (populado ao aplicar docs)\r\n * 2. Coleções de mutações pendentes\r\n * 3. Coleções de conflict_log\r\n * 4. Coleções persistas em sync_meta['activeCollections']\r\n */\r\n private async _getActiveCollections(): Promise<string[]> {\r\n const collectionSet = new Set<string>(this._activeCollections);\r\n\r\n // Coleções de mutações pendentes\r\n const mutations = await this._queue.listAll();\r\n for (const m of mutations) collectionSet.add(m.collection);\r\n\r\n // Coleções de conflict_log\r\n const conflicts = await this._store.listConflicts();\r\n for (const c of conflicts) collectionSet.add(c.collection);\r\n\r\n // Coleções persistidas em sync_meta (sobrevivem reload)\r\n const persistedRaw = (await this._store.getMeta('activeCollections')) as string[] | null;\r\n if (persistedRaw) {\r\n for (const col of persistedRaw) collectionSet.add(col);\r\n }\r\n\r\n // Coleções descobertas diretamente do IndexedDB (cobre docs pré-populados\r\n // externamente, ex.: pelo SyncTransport em sessões anteriores)\r\n const storedCollections = await this._store.listCollections();\r\n for (const col of storedCollections) collectionSet.add(col);\r\n\r\n return Array.from(collectionSet);\r\n }\r\n\r\n\r\n /** Constrói o estado inicial com base no estado atual dos colaboradores. */\r\n private _buildInitialState(): SyncState {\r\n const isOnline = this._connectivity.isOnline;\r\n return {\r\n status: isOnline ? 'idle' : 'offline',\r\n pendingWrites: 0,\r\n lastSyncedAt: null,\r\n isLeaderTab: this._tabCoordinator.isLeader(),\r\n };\r\n }\r\n\r\n /**\r\n * Atualiza o SyncState em RAM e notifica os listeners.\r\n * Só emite se algo realmente mudou.\r\n */\r\n private _updateState(partial: Partial<SyncState>): void {\r\n const prev = this._state;\r\n const next: SyncState = { ...prev, ...partial };\r\n\r\n // Garante que pendingWrites é sempre recalculado de forma assíncrona\r\n // Nota: não podemos tornar _updateState async aqui (breaking the sync chain),\r\n // então atualizamos o pendingWrites via side-effect lazy.\r\n\r\n const changed =\r\n prev.status !== next.status ||\r\n prev.pendingWrites !== next.pendingWrites ||\r\n prev.lastSyncedAt !== next.lastSyncedAt ||\r\n prev.isLeaderTab !== next.isLeaderTab;\r\n\r\n this._state = next;\r\n\r\n if (changed) {\r\n this._emitState(next);\r\n }\r\n }\r\n\r\n private _emitState(state: SyncState): void {\r\n for (const listener of this._stateListeners) {\r\n try {\r\n listener({ ...state });\r\n } catch { /* listener com erro não interrompe */ }\r\n }\r\n }\r\n\r\n /**\r\n * Atualiza `pendingWrites` no estado.\r\n * Chamado de forma assíncrona quando necessário.\r\n */\r\n private async _refreshPendingWrites(): Promise<void> {\r\n if (this._destroyed) return;\r\n try {\r\n const count = await this._queue.countPending();\r\n if (count !== this._state.pendingWrites) {\r\n this._updateState({ pendingWrites: count });\r\n }\r\n } catch { /* silencioso */ }\r\n }\r\n\r\n /** Dispara um sync de forma fire-and-forget (para gatilhos externos). */\r\n private _triggerSync(_reason: string): void {\r\n if (this._destroyed) return;\r\n this._refreshPendingWrites().catch(() => {});\r\n this.sync().catch(() => {});\r\n }\r\n\r\n /** Carrega activeCollections do sync_meta e popula o Set em memória. */\r\n private _loadActiveCollections(): void {\r\n // Assíncrono — chamado fire-and-forget no constructor\r\n this._store.getMeta('activeCollections')\r\n .then((raw) => {\r\n const cols = raw as string[] | null;\r\n if (cols) {\r\n for (const c of cols) this._activeCollections.add(c);\r\n }\r\n })\r\n .catch(() => {});\r\n }\r\n\r\n /** Conecta os listeners de ConnectivityMonitor e TabCoordinator. */\r\n private _wireListeners(): void {\r\n this._loadActiveCollections();\r\n // ConnectivityMonitor: offline → atualiza status; online → aciona sync\r\n const unsubConn = this._connectivity.subscribe((state) => {\r\n if (state === 'offline') {\r\n this._updateState({ status: 'offline' });\r\n } else {\r\n // Voltou online — atualiza estado e aciona sync\r\n if (this._state.status === 'offline') {\r\n this._updateState({ status: 'idle' });\r\n }\r\n this._triggerSync('connectivity:online');\r\n }\r\n });\r\n this._cleanups.push(unsubConn);\r\n\r\n // TabCoordinator: promoção → aciona sync; rebaixamento → para (status idle)\r\n const unsubRole = this._tabCoordinator.onRoleChange((role) => {\r\n const isLeader = role === 'leader';\r\n this._updateState({ isLeaderTab: isLeader });\r\n\r\n if (isLeader) {\r\n this._triggerSync('role:leader');\r\n }\r\n });\r\n this._cleanups.push(unsubRole);\r\n }\r\n}\r\n","/**\r\n * ConflictResolver — resolução de conflito Last-Write-Wins (LWW).\r\n *\r\n * Implementa a política LWW definida em I3 §7:\r\n * - **Documento-nível** (para `set` e `add`): o documento inteiro com o\r\n * `updatedAtServer` mais recente vence.\r\n * - **Campo-restrito** (para `update`): apenas os campos declarados na mutação\r\n * são comparados; campos não tocados pela mutação são preservados do estado\r\n * atual (server ou local).\r\n *\r\n * Design:\r\n * - ZERO dependências externas.\r\n * - PURO: mesma entrada → mesma saída. Sem side-effects, sem I/O.\r\n * - O timestamp autoritativo é o do SERVIDOR (`updatedAtServer`), não do\r\n * cliente (`enqueuedAt`) — I3 §7.3.\r\n * - A comparação de versão/timestamp acontece no CLIENTE apenas para leitura\r\n * otimista. A palavra final é do servidor (no replay o Core decide). Este\r\n * módulo implementa a lógica de resolução local (para preview otimista e para\r\n * o feedback ao produto).\r\n */\r\n\r\nimport type {\r\n OfflineDoc,\r\n Mutation,\r\n ConflictRecord,\r\n ConflictReason,\r\n} from './types';\r\n\r\n// ─── Tipos do resultado ───────────────────────────────────────────────────────\r\n\r\n/** Resultado da resolução de conflito para um par (local, server). */\r\nexport type ConflictOutcome =\r\n | 'local_wins' // a escrita local é mantida\r\n | 'server_wins' // o estado do servidor prevalece (escrita local descartada)\r\n | 'merged' // merge campo-restrito (update): campos do server + campos locais\r\n | 'no_conflict'; // sem conflito detectável (doc local === doc server, ou nenhum estava presente)\r\n\r\nexport interface ResolveResult<T = Record<string, unknown>> {\r\n outcome: ConflictOutcome;\r\n /** Documento resultante após resolução. */\r\n resolvedData: T;\r\n /**\r\n * `ConflictRecord` preenchido quando `outcome === 'server_wins'` ou\r\n * `outcome === 'merged'` (campos conflitantes perdedores).\r\n * `null` caso contrário.\r\n */\r\n conflictRecord: Omit<ConflictRecord, 'id'> | null;\r\n}\r\n\r\n// ─── Helpers ──────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Retorna true se o estado do servidor é \"mais novo\" do que o estado local,\r\n * baseando-se no timestamp do servidor (I3 §7.3).\r\n *\r\n * Quando `serverUpdatedAt` é null o servidor nunca confirmou — considera o local\r\n * como mais recente (o doc pode ser um `add` otimista ainda não sincronizado).\r\n * Quando ambos são null há empate → `false` (mantém local como default).\r\n */\r\nfunction isServerNewer(\r\n localUpdatedAtServer: number | null,\r\n remoteUpdatedAtServer: number | null,\r\n): boolean {\r\n if (remoteUpdatedAtServer === null) return false;\r\n if (localUpdatedAtServer === null) return true; // server tem timestamp, local não\r\n return remoteUpdatedAtServer > localUpdatedAtServer;\r\n}\r\n\r\n// ─── ConflictResolver ─────────────────────────────────────────────────────────\r\n\r\n/**\r\n * ConflictResolver — aplica LWW doc-nível ou campo-restrito.\r\n *\r\n * Uso:\r\n * ```ts\r\n * const resolver = new ConflictResolver();\r\n *\r\n * // LWW doc-nível (set/add):\r\n * const result = resolver.resolveDocLevel(localDoc, serverDoc, mutation);\r\n *\r\n * // LWW campo-restrito (update):\r\n * const result = resolver.resolveFieldRestricted(localDoc, serverDoc, mutation);\r\n *\r\n * // Auto-dispatch baseado na op da mutação:\r\n * const result = resolver.resolve(localDoc, serverDoc, mutation);\r\n * ```\r\n */\r\nexport class ConflictResolver {\r\n /**\r\n * Resolve um conflito com base na operação da mutação (auto-dispatch).\r\n *\r\n * - `add` / `set` → `resolveDocLevel`\r\n * - `update` → `resolveFieldRestricted`\r\n * - `remove` → a remoção sempre vence (LWW: operação mais recente é a destruição)\r\n */\r\n resolve<T = Record<string, unknown>>(\r\n localDoc: OfflineDoc<T> | null,\r\n serverDoc: OfflineDoc<T> | null,\r\n pendingMutation: Mutation,\r\n ): ResolveResult<T> {\r\n switch (pendingMutation.op) {\r\n case 'remove':\r\n return this.resolveRemove(localDoc, serverDoc, pendingMutation);\r\n case 'update':\r\n return this.resolveFieldRestricted(localDoc, serverDoc, pendingMutation);\r\n case 'add':\r\n case 'set':\r\n default:\r\n return this.resolveDocLevel(localDoc, serverDoc, pendingMutation);\r\n }\r\n }\r\n\r\n /**\r\n * LWW documento-nível (para `set` e `add`).\r\n *\r\n * O documento inteiro com o timestamp de servidor mais recente vence.\r\n * Se o servidor for mais novo, a escrita local é descartada e um\r\n * `ConflictRecord` é emitido.\r\n */\r\n resolveDocLevel<T = Record<string, unknown>>(\r\n localDoc: OfflineDoc<T> | null,\r\n serverDoc: OfflineDoc<T> | null,\r\n pendingMutation: Mutation,\r\n ): ResolveResult<T> {\r\n // Sem doc no servidor — escrita local não tem concorrente, sem conflito.\r\n if (serverDoc === null) {\r\n const data = (pendingMutation.payload ?? {}) as T;\r\n return { outcome: 'no_conflict', resolvedData: data, conflictRecord: null };\r\n }\r\n\r\n // Sem doc local (não deveria ocorrer, mas defesa de programação)\r\n if (localDoc === null) {\r\n return {\r\n outcome: 'server_wins',\r\n resolvedData: serverDoc.data,\r\n conflictRecord: null,\r\n };\r\n }\r\n\r\n const serverNewer = isServerNewer(\r\n localDoc.meta.updatedAtServer,\r\n serverDoc.meta.updatedAtServer,\r\n );\r\n\r\n if (!serverNewer) {\r\n // Escrita local é mais recente (ou empate → local vence por default)\r\n return {\r\n outcome: 'local_wins',\r\n resolvedData: localDoc.data,\r\n conflictRecord: null,\r\n };\r\n }\r\n\r\n // Servidor mais novo — LWW: servidor vence, escrita local descartada\r\n const conflictRecord: Omit<ConflictRecord, 'id'> = {\r\n collection: pendingMutation.collection,\r\n docId: pendingMutation.docId,\r\n mutationId: pendingMutation.mutationId,\r\n losingData: localDoc.data as Record<string, unknown>,\r\n winningData: serverDoc.data as Record<string, unknown>,\r\n reason: 'lww_server_newer' as ConflictReason,\r\n detectedAt: Date.now(),\r\n delivered: false,\r\n };\r\n\r\n return {\r\n outcome: 'server_wins',\r\n resolvedData: serverDoc.data,\r\n conflictRecord,\r\n };\r\n }\r\n\r\n /**\r\n * LWW campo-restrito (para `update`).\r\n *\r\n * Apenas os campos declarados no payload da mutação são comparados.\r\n * Campos não tocados pela mutação são preservados do estado do servidor\r\n * (se disponível) ou do estado local (I3 §7.2).\r\n *\r\n * Resultado:\r\n * - Se o servidor for mais novo nos campos conflitantes → `server_wins`\r\n * para esses campos; o doc resultante é uma mescla de server (campos\r\n * conflitantes) + estado antes da mutação para os demais.\r\n * - Se o local for mais recente → `local_wins`; os campos do update são\r\n * aplicados sobre o server.\r\n * - Campos do server não tocados pelo update sempre preservados → `merged`.\r\n */\r\n resolveFieldRestricted<T = Record<string, unknown>>(\r\n localDoc: OfflineDoc<T> | null,\r\n serverDoc: OfflineDoc<T> | null,\r\n pendingMutation: Mutation,\r\n ): ResolveResult<T> {\r\n const mutatedFields = Object.keys(pendingMutation.payload ?? {});\r\n\r\n // Sem doc no servidor — sem conflito, aplica o update sobre o local\r\n if (serverDoc === null) {\r\n const base = (localDoc?.data ?? {}) as Record<string, unknown>;\r\n const resolved = { ...base, ...(pendingMutation.payload ?? {}) } as T;\r\n return { outcome: 'no_conflict', resolvedData: resolved, conflictRecord: null };\r\n }\r\n\r\n // Base do documento no servidor (campos não tocados pelo update)\r\n const serverData = serverDoc.data as Record<string, unknown>;\r\n\r\n // Se não há doc local (doc nunca foi cacheado), sem conflito — aplica o update sobre o server\r\n if (localDoc === null) {\r\n const resolved = { ...serverData, ...(pendingMutation.payload ?? {}) } as T;\r\n return { outcome: 'no_conflict', resolvedData: resolved, conflictRecord: null };\r\n }\r\n\r\n const serverNewer = isServerNewer(\r\n localDoc.meta.updatedAtServer,\r\n serverDoc.meta.updatedAtServer,\r\n );\r\n\r\n if (!serverNewer) {\r\n // Update local é mais recente — aplica os campos do update sobre o server\r\n const resolved = { ...serverData, ...(pendingMutation.payload ?? {}) } as T;\r\n return { outcome: 'local_wins', resolvedData: resolved, conflictRecord: null };\r\n }\r\n\r\n // Servidor mais novo — campos conflitantes: server vence; campos do update\r\n // não existentes no server: server ainda vence (server é a fonte de verdade\r\n // pós-conflito, consistente com doc-level LWW).\r\n const losingFields: Record<string, unknown> = {};\r\n for (const field of mutatedFields) {\r\n losingFields[field] = (localDoc.data as Record<string, unknown>)[field];\r\n }\r\n\r\n const conflictRecord: Omit<ConflictRecord, 'id'> = {\r\n collection: pendingMutation.collection,\r\n docId: pendingMutation.docId,\r\n mutationId: pendingMutation.mutationId,\r\n losingData: losingFields,\r\n winningData: serverData,\r\n reason: 'lww_server_newer' as ConflictReason,\r\n detectedAt: Date.now(),\r\n delivered: false,\r\n };\r\n\r\n // Doc resultante: estado do servidor completo (o update perdeu todos os\r\n // campos conflitantes — comportamento conservador e auditável)\r\n return {\r\n outcome: 'server_wins',\r\n resolvedData: serverData as T,\r\n conflictRecord,\r\n };\r\n }\r\n\r\n /**\r\n * Resolve uma operação `remove`.\r\n *\r\n * A remoção sempre vence no LWW (I3 §7.4: \"a última operação é a destruição\").\r\n * Se o servidor modificou o doc depois que o cliente enfileirou o remove, a\r\n * remoção ainda prevalece — comportamento documentado.\r\n */\r\n resolveRemove<T = Record<string, unknown>>(\r\n _localDoc: OfflineDoc<T> | null,\r\n serverDoc: OfflineDoc<T> | null,\r\n _pendingMutation: Mutation,\r\n ): ResolveResult<T> {\r\n // A remoção vence — o doc resultante é um tombstone (dados vazios)\r\n // O chamador é responsável por marcar `deleted: true` no cache.\r\n const emptyDoc = {} as T;\r\n\r\n // Se o servidor tem um estado mais recente E foi modificado depois da\r\n // intenção de remoção, registra um conflito para audit trail (mas ainda remove)\r\n if (serverDoc !== null && serverDoc.meta.updatedAtServer !== null) {\r\n const conflictRecord: Omit<ConflictRecord, 'id'> = {\r\n collection: _pendingMutation.collection,\r\n docId: _pendingMutation.docId,\r\n mutationId: _pendingMutation.mutationId,\r\n losingData: serverDoc.data as Record<string, unknown>,\r\n winningData: {},\r\n reason: 'lww_server_newer' as ConflictReason,\r\n detectedAt: Date.now(),\r\n delivered: false,\r\n };\r\n // A remoção ainda vence, mas registra o conflito\r\n return { outcome: 'local_wins', resolvedData: emptyDoc, conflictRecord };\r\n }\r\n\r\n return { outcome: 'local_wins', resolvedData: emptyDoc, conflictRecord: null };\r\n }\r\n\r\n /**\r\n * Resolve conflito com razão de rejeição explícita (servidor retornou\r\n * `rejected_permission` ou `rejected_validation`).\r\n *\r\n * Usado pelo SyncEngine quando o Core rejeita o replay por motivo não-LWW.\r\n */\r\n resolveRejected<T = Record<string, unknown>>(\r\n localDoc: OfflineDoc<T>,\r\n serverDoc: OfflineDoc<T> | null,\r\n pendingMutation: Mutation,\r\n reason: 'rejected_permission' | 'rejected_validation',\r\n ): ResolveResult<T> {\r\n const winningData = (serverDoc?.data ?? {}) as Record<string, unknown>;\r\n\r\n const conflictRecord: Omit<ConflictRecord, 'id'> = {\r\n collection: pendingMutation.collection,\r\n docId: pendingMutation.docId,\r\n mutationId: pendingMutation.mutationId,\r\n losingData: localDoc.data as Record<string, unknown>,\r\n winningData,\r\n reason,\r\n detectedAt: Date.now(),\r\n delivered: false,\r\n };\r\n\r\n return {\r\n outcome: 'server_wins',\r\n resolvedData: (serverDoc?.data ?? localDoc.data),\r\n conflictRecord,\r\n };\r\n }\r\n\r\n // ─── Static helpers ─────────────────────────────────────────────────────────\r\n\r\n static resolve<T = Record<string, unknown>>(\r\n localDoc: OfflineDoc<T> | null,\r\n serverDoc: OfflineDoc<T> | null,\r\n pendingMutation: Mutation,\r\n ): ResolveResult<T> {\r\n return new ConflictResolver().resolve(localDoc, serverDoc, pendingMutation);\r\n }\r\n}\r\n","/**\r\n * ChangeBus — barramento in-process de eventos de mudança.\r\n *\r\n * Fan-out de eventos `Change` para todos os listeners registrados\r\n * (onSnapshot / onDoc). Cola o cache (LocalStore) ao tempo real.\r\n *\r\n * Design (I3 §2.2 / §6.5 / §9):\r\n * - ZERO dependências externas.\r\n * - Em memória por aba (não persiste).\r\n * - Sem memory leaks: `unsubscribe()` remove o listener imediatamente.\r\n * - Deduplicação básica por `[collection, id, serverVersion]` (I3 §6.5):\r\n * o bus não emite o mesmo evento duas vezes pra o mesmo listener no mesmo\r\n * tick (evita a Fase 1 + Fase 2 do SyncEngine gerando dois eventos para o\r\n * mesmo doc confirmado).\r\n * - Erro em um listener não propaga para os demais (isolamento).\r\n */\r\n\r\nimport type { Change, Unsubscribe } from './types';\r\n\r\n// ─── Tipos internos ───────────────────────────────────────────────────────────\r\n\r\n/** Função listener que recebe um array de Changes emitidos juntos. */\r\nexport type ChangeBusListener<T = Record<string, unknown>> = (\r\n changes: Change<T>[],\r\n) => void;\r\n\r\n/** Chave de deduplicação para um change event. */\r\nfunction dedupeKey<T>(c: Change<T>): string {\r\n // usa `serverVersion` se presente; fallback para 'local' (sem versão server)\r\n return `${c.collection}::${c.doc.id}`;\r\n}\r\n\r\n// ─── ChangeBus ────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * ChangeBus — pub/sub in-process para eventos de mudança de documento.\r\n *\r\n * ```ts\r\n * const bus = new ChangeBus();\r\n *\r\n * // Subscrever a uma coleção (filtra por collection automaticamente)\r\n * const unsub = bus.subscribe('orders', (changes) => {\r\n * console.log(changes);\r\n * });\r\n *\r\n * // Emitir events\r\n * bus.emit([{ type: 'modified', collection: 'orders', doc: { id: '1', data: {} } }]);\r\n *\r\n * // Cancelar subscrição — sem memory leak\r\n * unsub();\r\n * ```\r\n *\r\n * Listeners globais (sem filtro de coleção):\r\n * ```ts\r\n * const unsub = bus.subscribeAll((changes) => { ... });\r\n * ```\r\n */\r\nexport class ChangeBus<T = Record<string, unknown>> {\r\n /** Listeners filtrados por coleção. */\r\n private readonly _collectionListeners = new Map<\r\n string,\r\n Set<ChangeBusListener<T>>\r\n >();\r\n /** Listeners globais (todas as coleções). */\r\n private readonly _globalListeners = new Set<ChangeBusListener<T>>();\r\n\r\n /**\r\n * Subscreve a eventos de uma coleção específica.\r\n *\r\n * @param collection - Nome da coleção a filtrar.\r\n * @param listener - Callback que recebe os changes da coleção.\r\n * @returns Função de unsubscribe.\r\n */\r\n subscribe(collection: string, listener: ChangeBusListener<T>): Unsubscribe {\r\n if (!this._collectionListeners.has(collection)) {\r\n this._collectionListeners.set(collection, new Set());\r\n }\r\n this._collectionListeners.get(collection)!.add(listener);\r\n\r\n return () => {\r\n const set = this._collectionListeners.get(collection);\r\n if (set) {\r\n set.delete(listener);\r\n if (set.size === 0) {\r\n this._collectionListeners.delete(collection);\r\n }\r\n }\r\n };\r\n }\r\n\r\n /**\r\n * Subscreve a eventos de TODAS as coleções.\r\n *\r\n * @param listener - Callback que recebe todos os changes, de qualquer coleção.\r\n * @returns Função de unsubscribe.\r\n */\r\n subscribeAll(listener: ChangeBusListener<T>): Unsubscribe {\r\n this._globalListeners.add(listener);\r\n return () => {\r\n this._globalListeners.delete(listener);\r\n };\r\n }\r\n\r\n /**\r\n * Emite um array de `Change` events para todos os listeners relevantes.\r\n *\r\n * Agrupa os changes por coleção antes de despachar, para que cada listener\r\n * receba apenas os events da sua coleção.\r\n *\r\n * Deduplicação: events com o mesmo `[collection, id]` dentro do mesmo `emit()`\r\n * são compactados: apenas o último do array é mantido (o mais recente vence).\r\n * Isso cobre o caso Fase 1 + Fase 2 do SyncEngine emitindo o mesmo doc.\r\n *\r\n * Erros em listeners individuais são capturados e não interrompem os demais.\r\n */\r\n emit(changes: Change<T>[]): void {\r\n if (changes.length === 0) return;\r\n\r\n // Deduplica: mapa de dedupeKey → último change (o mais recente)\r\n const deduped = new Map<string, Change<T>>();\r\n for (const c of changes) {\r\n deduped.set(dedupeKey(c), c);\r\n }\r\n const uniqueChanges = Array.from(deduped.values());\r\n\r\n // Agrupa por coleção\r\n const byCollection = new Map<string, Change<T>[]>();\r\n for (const c of uniqueChanges) {\r\n if (!byCollection.has(c.collection)) {\r\n byCollection.set(c.collection, []);\r\n }\r\n byCollection.get(c.collection)!.push(c);\r\n }\r\n\r\n // Despacha para listeners de coleção\r\n for (const [collection, collChanges] of byCollection) {\r\n const listeners = this._collectionListeners.get(collection);\r\n if (listeners) {\r\n for (const listener of listeners) {\r\n this._safeCall(listener, collChanges);\r\n }\r\n }\r\n }\r\n\r\n // Despacha para listeners globais (com todos os changes únicos)\r\n for (const listener of this._globalListeners) {\r\n this._safeCall(listener, uniqueChanges);\r\n }\r\n }\r\n\r\n /**\r\n * Número de listeners ativos (útil em testes).\r\n */\r\n get listenerCount(): number {\r\n let count = this._globalListeners.size;\r\n for (const set of this._collectionListeners.values()) {\r\n count += set.size;\r\n }\r\n return count;\r\n }\r\n\r\n /**\r\n * Remove todos os listeners registrados.\r\n * Útil para teardown em testes ou no shutdown do SDK.\r\n */\r\n clear(): void {\r\n this._collectionListeners.clear();\r\n this._globalListeners.clear();\r\n }\r\n\r\n // ─── Privado ────────────────────────────────────────────────────────────────\r\n\r\n private _safeCall(listener: ChangeBusListener<T>, changes: Change<T>[]): void {\r\n try {\r\n listener(changes);\r\n } catch {\r\n // Listener com erro não interrompe os demais.\r\n // Em produção, o SyncEngine pode logar via telemetry.\r\n // Aqui silenciamos para manter o contrato de fan-out total.\r\n }\r\n }\r\n}\r\n","/**\r\n * ConnectivityMonitor — rastreia estado online/offline via `navigator.onLine`\r\n * e os eventos `online`/`offline` do window.\r\n *\r\n * Design (I3 §2.2):\r\n * - ZERO dependências externas.\r\n * - Injetável: aceita `navigator` e `EventTarget` como parâmetros para ser\r\n * totalmente testável sem DOM real.\r\n * - Debounce de flapping: transições rápidas online → offline → online dentro\r\n * de `debounceMs` (default 300ms) não disparam callbacks intermediários.\r\n * - Nota I3 §2.2: o ConnectivityMonitor base usa `navigator.onLine` + eventos\r\n * do window. Uma camada adicional (heartbeat real ao Core + sinal do\r\n * WebSocket) é responsabilidade do SyncEngine — este módulo é a base injetável.\r\n */\r\n\r\nimport type { Unsubscribe } from './types';\r\n\r\n// ─── Tipos ────────────────────────────────────────────────────────────────────\r\n\r\n/** Estado de conectividade. */\r\nexport type ConnectivityState = 'online' | 'offline';\r\n\r\n/** Listener de mudança de estado de conectividade. */\r\nexport type ConnectivityListener = (state: ConnectivityState) => void;\r\n\r\n/**\r\n * Contrato de injeção do `navigator` (subconjunto usado pelo monitor).\r\n * Permite testar sem um `navigator` real.\r\n */\r\nexport interface NavigatorLike {\r\n readonly onLine: boolean;\r\n}\r\n\r\n/**\r\n * Contrato de injeção do event target (subconjunto de `window` / `EventTarget`).\r\n */\r\nexport interface EventTargetLike {\r\n addEventListener(type: string, listener: EventListenerOrEventListenerObject): void;\r\n removeEventListener(type: string, listener: EventListenerOrEventListenerObject): void;\r\n}\r\n\r\n/** Opções de configuração do ConnectivityMonitor. */\r\nexport interface ConnectivityMonitorOptions {\r\n /**\r\n * `navigator`-like para leitura de `navigator.onLine`.\r\n * Default: `globalThis.navigator` (quando disponível).\r\n */\r\n navigator?: NavigatorLike;\r\n /**\r\n * EventTarget para subscrever os eventos `online` / `offline`.\r\n * Default: `globalThis.window` (quando disponível).\r\n */\r\n eventTarget?: EventTargetLike;\r\n /**\r\n * Debounce em ms para evitar flapping.\r\n * Default: 300ms.\r\n */\r\n debounceMs?: number;\r\n}\r\n\r\n// ─── ConnectivityMonitor ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * ConnectivityMonitor — monitora online/offline via `navigator.onLine` +\r\n * eventos `online`/`offline` do window, com debounce de flapping.\r\n *\r\n * ```ts\r\n * // Com injeção (testes):\r\n * const monitor = new ConnectivityMonitor({\r\n * navigator: { onLine: true },\r\n * eventTarget: myFakeTarget,\r\n * });\r\n *\r\n * // Em browser real:\r\n * const monitor = new ConnectivityMonitor();\r\n * monitor.start();\r\n *\r\n * const unsub = monitor.subscribe((state) => {\r\n * console.log('Conectividade:', state);\r\n * });\r\n *\r\n * monitor.destroy(); // cleanup\r\n * ```\r\n */\r\nexport class ConnectivityMonitor {\r\n private _state: ConnectivityState;\r\n private readonly _listeners = new Set<ConnectivityListener>();\r\n private readonly _nav: NavigatorLike | undefined;\r\n private readonly _target: EventTargetLike | undefined;\r\n private readonly _debounceMs: number;\r\n private _debounceTimer: ReturnType<typeof setTimeout> | null = null;\r\n private _started = false;\r\n\r\n // Handlers bound para remoção correta em removeEventListener\r\n private readonly _onOnline: () => void;\r\n private readonly _onOffline: () => void;\r\n\r\n constructor(options: ConnectivityMonitorOptions = {}) {\r\n this._nav = options.navigator ?? (typeof navigator !== 'undefined' ? navigator : undefined);\r\n this._target =\r\n options.eventTarget ??\r\n (typeof window !== 'undefined' ? window : undefined);\r\n this._debounceMs = options.debounceMs ?? 300;\r\n\r\n // Estado inicial: lê navigator.onLine; fallback = online\r\n this._state = this._nav?.onLine === false ? 'offline' : 'online';\r\n\r\n // Bind para poder remover depois\r\n this._onOnline = () => this._handleNativeEvent('online');\r\n this._onOffline = () => this._handleNativeEvent('offline');\r\n }\r\n\r\n // ─── Ciclo de vida ──────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Inicia a escuta de eventos. Deve ser chamado após instanciar.\r\n * Sem efeito se já foi iniciado.\r\n */\r\n start(): void {\r\n if (this._started) return;\r\n this._started = true;\r\n this._target?.addEventListener('online', this._onOnline);\r\n this._target?.addEventListener('offline', this._onOffline);\r\n }\r\n\r\n /**\r\n * Para a escuta e remove todos os listeners.\r\n * Deve ser chamado no shutdown para evitar memory leaks.\r\n */\r\n destroy(): void {\r\n this._started = false;\r\n this._target?.removeEventListener('online', this._onOnline);\r\n this._target?.removeEventListener('offline', this._onOffline);\r\n if (this._debounceTimer !== null) {\r\n clearTimeout(this._debounceTimer);\r\n this._debounceTimer = null;\r\n }\r\n this._listeners.clear();\r\n }\r\n\r\n // ─── Estado atual ───────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna o estado de conectividade atual.\r\n */\r\n getState(): ConnectivityState {\r\n return this._state;\r\n }\r\n\r\n /**\r\n * True se o estado atual é `'online'`.\r\n */\r\n get isOnline(): boolean {\r\n return this._state === 'online';\r\n }\r\n\r\n /**\r\n * True se o estado atual é `'offline'`.\r\n */\r\n get isOffline(): boolean {\r\n return this._state === 'offline';\r\n }\r\n\r\n // ─── Subscrições ────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Subscreve a mudanças de estado de conectividade.\r\n *\r\n * @param listener - Callback chamado ao mudar o estado.\r\n * @returns Função de unsubscribe (sem memory leak).\r\n */\r\n subscribe(listener: ConnectivityListener): Unsubscribe {\r\n this._listeners.add(listener);\r\n return () => {\r\n this._listeners.delete(listener);\r\n };\r\n }\r\n\r\n /**\r\n * Número de listeners ativos (útil em testes).\r\n */\r\n get listenerCount(): number {\r\n return this._listeners.size;\r\n }\r\n\r\n // ─── Força de estado (para testes e heartbeat externo) ─────────────────────\r\n\r\n /**\r\n * Força o estado para um valor específico, ignorando eventos nativos.\r\n * Útil para o SyncEngine injetar o resultado de um heartbeat real ao Core.\r\n * Respeita o debounce.\r\n */\r\n forceState(state: ConnectivityState): void {\r\n this._scheduleTransition(state);\r\n }\r\n\r\n // ─── Privado ────────────────────────────────────────────────────────────────\r\n\r\n private _handleNativeEvent(type: 'online' | 'offline'): void {\r\n const newState: ConnectivityState = type === 'online' ? 'online' : 'offline';\r\n this._scheduleTransition(newState);\r\n }\r\n\r\n private _scheduleTransition(newState: ConnectivityState): void {\r\n // Cancela transição pendente (debounce de flapping)\r\n if (this._debounceTimer !== null) {\r\n clearTimeout(this._debounceTimer);\r\n this._debounceTimer = null;\r\n }\r\n\r\n if (this._debounceMs <= 0) {\r\n // Sem debounce — aplica imediatamente\r\n this._applyTransition(newState);\r\n return;\r\n }\r\n\r\n this._debounceTimer = setTimeout(() => {\r\n this._debounceTimer = null;\r\n this._applyTransition(newState);\r\n }, this._debounceMs);\r\n }\r\n\r\n private _applyTransition(newState: ConnectivityState): void {\r\n if (newState === this._state) return; // sem mudança real\r\n this._state = newState;\r\n this._notifyListeners(newState);\r\n }\r\n\r\n private _notifyListeners(state: ConnectivityState): void {\r\n for (const listener of this._listeners) {\r\n try {\r\n listener(state);\r\n } catch {\r\n // Listener com erro não interrompe os demais\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * TabCoordinator — coordenação multi-aba via Web Locks API.\r\n *\r\n * Elege uma aba **líder** de forma exclusiva: apenas a aba líder roda o\r\n * SyncEngine e drena a MutationQueue. Abas seguidoras leem o LocalStore\r\n * compartilhado e recebem notificações via BroadcastChannel.\r\n *\r\n * Design (I3 §12.5 / §2.2):\r\n *\r\n * - **Eleição via Web Locks:** `navigator.locks.request(name, callback)` com\r\n * uma Promise interna que nunca resolve enquanto a aba estiver viva. O\r\n * processo que segura o lock é o líder. Ao destruir, a Promise interna\r\n * resolve → lock liberado → próxima aba na fila adquire o lock.\r\n *\r\n * - **BroadcastChannel:** o líder transmite `cache_updated` / `sync_state`\r\n * para que seguidores reavaliem suas queries; seguidores enviam\r\n * `mutation_request` ao líder quando querem que ele drene a fila.\r\n *\r\n * - **Fallback:** se `navigator.locks` não estiver disponível (SSR, ambiente\r\n * sem suporte), a aba assume liderança imediatamente sem contenção.\r\n *\r\n * - **Injetabilidade:** todas as APIs do browser (`navigator.locks`,\r\n * `BroadcastChannel`) são injetáveis via `TabCoordinatorOptions` — o\r\n * componente é totalmente testável sem DOM/browser real.\r\n *\r\n * - **Idempotência:** `start()` e `destroy()` são seguros de chamar\r\n * múltiplas vezes.\r\n */\r\n\r\nimport type { Unsubscribe } from './types';\r\n\r\n// ─── Protocolo de mensagens BroadcastChannel ──────────────────────────────────\r\n\r\n/**\r\n * O líder transmite que o cache foi atualizado.\r\n * Seguidores devem reavaliar queries afetadas pela `collection`.\r\n */\r\nexport interface CacheUpdatedMessage {\r\n type: 'cache_updated';\r\n /** Coleção que foi modificada. `*` = todas. */\r\n collection: string;\r\n}\r\n\r\n/**\r\n * O líder transmite seu estado de sync para que seguidores atualizem o\r\n * `isLeaderTab` em seus `NeetruSyncState`.\r\n */\r\nexport interface SyncStateMessage {\r\n type: 'sync_state';\r\n /** ID único da aba líder. */\r\n leaderTabId: string;\r\n /** Se `true`, o líder está sincronizando no momento. */\r\n syncing: boolean;\r\n /** Número de mutações pendentes na fila. */\r\n pendingWrites: number;\r\n}\r\n\r\n/**\r\n * Um seguidor solicita ao líder que drene a fila (ex.: após enfileirar\r\n * uma mutação localmente). O líder pode ignorar se já estiver drenando.\r\n */\r\nexport interface MutationRequestMessage {\r\n type: 'mutation_request';\r\n mutationId: string;\r\n collection: string;\r\n op: string;\r\n docId: string;\r\n payload: Record<string, unknown> | null;\r\n}\r\n\r\n/**\r\n * União discriminada de todas as mensagens do protocolo TabCoordinator.\r\n * Mensagens de tipo desconhecido devem ser ignoradas silenciosamente\r\n * (compatibilidade futura).\r\n */\r\nexport type TabMessage =\r\n | CacheUpdatedMessage\r\n | SyncStateMessage\r\n | MutationRequestMessage;\r\n\r\n// ─── Contratos de injeção de browser APIs ─────────────────────────────────────\r\n\r\n/**\r\n * Subconjunto de `Lock` usado pelo TabCoordinator.\r\n */\r\nexport interface LockLike {\r\n readonly name: string;\r\n}\r\n\r\n/**\r\n * Subconjunto de `LockManager` (`navigator.locks`).\r\n * Permite injeção de fake em testes sem o browser real.\r\n */\r\nexport interface LockManagerLike {\r\n request(\r\n name: string,\r\n callback: (lock: LockLike) => Promise<void>,\r\n ): Promise<void>;\r\n}\r\n\r\n/**\r\n * Subconjunto de `BroadcastChannel`.\r\n * Permite injeção de fake em testes sem o browser real.\r\n */\r\nexport interface BroadcastChannelLike {\r\n onmessage: ((msg: TabMessage) => void) | null;\r\n postMessage(msg: TabMessage): void;\r\n close(): void;\r\n}\r\n\r\n// ─── Papel da aba ──────────────────────────────────────────────────────────────\r\n\r\n/** Papel atual desta aba no protocolo multi-aba. */\r\nexport type TabRole = 'leader' | 'follower';\r\n\r\n/** Callback de mudança de papel. */\r\nexport type RoleChangeListener = (role: TabRole) => void;\r\n\r\n// ─── Opções ───────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Opções de configuração do TabCoordinator.\r\n * Todos os campos de browser API são opcionais para facilitar testes.\r\n */\r\nexport interface TabCoordinatorOptions {\r\n /**\r\n * Nome do lock Web Locks (deve ser único por banco lógico / origem).\r\n * Exemplo: `'neetru-offline:produto-slug:db-id'`.\r\n */\r\n lockName: string;\r\n\r\n /**\r\n * Nome do BroadcastChannel (geralmente igual ao lockName).\r\n */\r\n channelName: string;\r\n\r\n /**\r\n * `navigator.locks`-like. Quando `undefined`, o TabCoordinator usa o\r\n * `navigator.locks` global se disponível; caso contrário, usa fallback\r\n * (assume liderança imediatamente).\r\n */\r\n lockManager?: LockManagerLike;\r\n\r\n /**\r\n * Instância de `BroadcastChannel`-like pré-criada. Quando `undefined`,\r\n * o TabCoordinator tenta criar um `BroadcastChannel` real se disponível.\r\n */\r\n broadcastChannel?: BroadcastChannelLike;\r\n}\r\n\r\n// ─── TabCoordinator ───────────────────────────────────────────────────────────\r\n\r\n/**\r\n * TabCoordinator — coordenação multi-aba via Web Locks + BroadcastChannel.\r\n *\r\n * ```ts\r\n * // Com injeção (testes):\r\n * const coordinator = new TabCoordinator({\r\n * lockName: 'neetru-offline:mydb',\r\n * channelName: 'neetru-offline:mydb',\r\n * lockManager: fakeLockManager,\r\n * broadcastChannel: fakeBroadcastChannel,\r\n * });\r\n *\r\n * // Em browser real:\r\n * const coordinator = new TabCoordinator({\r\n * lockName: `neetru-offline:${productId}:${dbId}`,\r\n * channelName: `neetru-offline:${productId}:${dbId}`,\r\n * });\r\n *\r\n * coordinator.start();\r\n *\r\n * // Saber se esta aba é líder\r\n * coordinator.isLeader();\r\n *\r\n * // Reagir a mudança de papel\r\n * const unsub = coordinator.onRoleChange((role) => {\r\n * if (role === 'leader') syncEngine.start();\r\n * else syncEngine.stop();\r\n * });\r\n *\r\n * // Transmitir a seguidores\r\n * coordinator.broadcast({ type: 'cache_updated', collection: 'orders' });\r\n *\r\n * // Receber mensagens de outras abas\r\n * coordinator.onMessage((msg) => {\r\n * if (msg.type === 'mutation_request') syncEngine.drainQueue();\r\n * });\r\n *\r\n * // Cleanup\r\n * coordinator.destroy();\r\n * ```\r\n */\r\nexport class TabCoordinator {\r\n private readonly _lockName: string;\r\n private readonly _channelName: string;\r\n private readonly _lockManager: LockManagerLike | undefined;\r\n private _channel: BroadcastChannelLike | undefined;\r\n private readonly _channelFactory: (() => BroadcastChannelLike) | undefined;\r\n\r\n /** ID único desta aba (para debug e `sync_state`). */\r\n private readonly _tabId: string;\r\n\r\n /** Estado de papel atual. */\r\n private _role: TabRole = 'follower';\r\n\r\n /** Promise resolve que libera o lock perpétuo. */\r\n private _releaseLock: (() => void) | null = null;\r\n\r\n /** `true` se destroy() já foi chamado. */\r\n private _destroyed = false;\r\n\r\n /** `true` se start() já foi chamado. */\r\n private _started = false;\r\n\r\n /** Listeners de mudança de papel. */\r\n private readonly _roleListeners = new Set<RoleChangeListener>();\r\n\r\n /** Listeners de mensagem recebida. */\r\n private readonly _messageListeners = new Set<(msg: TabMessage) => void>();\r\n\r\n constructor(options: TabCoordinatorOptions) {\r\n this._lockName = options.lockName;\r\n this._channelName = options.channelName;\r\n this._tabId = `tab-${Math.random().toString(36).slice(2, 10)}-${Date.now()}`;\r\n\r\n // Resolve o lockManager: opção injetada > navigator.locks global > undefined\r\n this._lockManager =\r\n options.lockManager !== undefined\r\n ? options.lockManager\r\n : typeof navigator !== 'undefined' &&\r\n 'locks' in navigator &&\r\n navigator.locks != null\r\n ? (navigator.locks as unknown as LockManagerLike)\r\n : undefined;\r\n\r\n // Resolve o canal: opção injetada > factory para BroadcastChannel real\r\n if (options.broadcastChannel !== undefined) {\r\n this._channel = options.broadcastChannel;\r\n } else if (typeof BroadcastChannel !== 'undefined') {\r\n // No browser real, armazena uma factory para criação lazy\r\n const channelName = this._channelName;\r\n this._channelFactory = () => {\r\n const bc = new BroadcastChannel(channelName);\r\n const wrapper: BroadcastChannelLike = {\r\n get onmessage() {\r\n return (bc.onmessage as ((msg: TabMessage) => void) | null);\r\n },\r\n set onmessage(cb: ((msg: TabMessage) => void) | null) {\r\n bc.onmessage = cb\r\n ? (event: MessageEvent) => cb(event.data as TabMessage)\r\n : null;\r\n },\r\n postMessage: (msg: TabMessage) => bc.postMessage(msg),\r\n close: () => bc.close(),\r\n };\r\n return wrapper;\r\n };\r\n }\r\n }\r\n\r\n // ─── Ciclo de vida ───────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Inicia o processo de eleição de líder.\r\n * Idempotente: sem efeito se já foi chamado.\r\n */\r\n start(): void {\r\n if (this._started || this._destroyed) return;\r\n this._started = true;\r\n\r\n // Cria o canal se ainda não foi injetado\r\n if (!this._channel && this._channelFactory) {\r\n this._channel = this._channelFactory();\r\n }\r\n\r\n // Configura o handler de mensagens do BroadcastChannel\r\n if (this._channel) {\r\n this._channel.onmessage = (msg: TabMessage) => {\r\n this._handleIncomingMessage(msg);\r\n };\r\n }\r\n\r\n // Inicia eleição\r\n if (this._lockManager) {\r\n this._electWithLocks();\r\n } else {\r\n // Fallback: sem Web Locks → assume liderança imediatamente\r\n this._becomeLeader();\r\n }\r\n }\r\n\r\n /**\r\n * Para o TabCoordinator: libera o lock, fecha o canal.\r\n * Idempotente: pode ser chamado múltiplas vezes.\r\n */\r\n destroy(): void {\r\n if (this._destroyed) return;\r\n this._destroyed = true;\r\n this._started = false;\r\n\r\n // Libera o lock perpétuo (se líder)\r\n if (this._releaseLock) {\r\n this._releaseLock();\r\n this._releaseLock = null;\r\n }\r\n\r\n // Fecha o canal de broadcast\r\n if (this._channel) {\r\n this._channel.onmessage = null;\r\n this._channel.close();\r\n this._channel = undefined;\r\n }\r\n\r\n // Atualiza papel local (sem notificar — aba está sendo destruída)\r\n this._role = 'follower';\r\n\r\n // Limpa listeners\r\n this._roleListeners.clear();\r\n this._messageListeners.clear();\r\n }\r\n\r\n // ─── Estado ──────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Retorna `true` se esta aba é atualmente a líder.\r\n */\r\n isLeader(): boolean {\r\n return !this._destroyed && this._role === 'leader';\r\n }\r\n\r\n /**\r\n * Retorna o papel atual desta aba.\r\n */\r\n getRole(): TabRole {\r\n return this._destroyed ? 'follower' : this._role;\r\n }\r\n\r\n /**\r\n * ID único desta aba (para diagnóstico).\r\n */\r\n get tabId(): string {\r\n return this._tabId;\r\n }\r\n\r\n // ─── Subscrições ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Registra um listener para mudanças de papel (`'leader'` | `'follower'`).\r\n *\r\n * @returns Função de unsubscribe.\r\n */\r\n onRoleChange(listener: RoleChangeListener): Unsubscribe {\r\n this._roleListeners.add(listener);\r\n return () => {\r\n this._roleListeners.delete(listener);\r\n };\r\n }\r\n\r\n /**\r\n * Registra um listener para mensagens recebidas de outras abas via\r\n * BroadcastChannel. O remetente NÃO recebe suas próprias mensagens.\r\n *\r\n * @returns Função de unsubscribe.\r\n */\r\n onMessage(listener: (msg: TabMessage) => void): Unsubscribe {\r\n this._messageListeners.add(listener);\r\n return () => {\r\n this._messageListeners.delete(listener);\r\n };\r\n }\r\n\r\n // ─── Comunicação ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Transmite uma mensagem para todas as outras abas via BroadcastChannel.\r\n * Sem efeito se o canal não estiver disponível ou o coordinator foi destroyed.\r\n */\r\n broadcast(msg: TabMessage): void {\r\n if (this._destroyed) return;\r\n try {\r\n this._channel?.postMessage(msg);\r\n } catch {\r\n // BroadcastChannel pode estar fechado — ignora silenciosamente\r\n }\r\n }\r\n\r\n // ─── Privado — eleição ───────────────────────────────────────────────────────\r\n\r\n /**\r\n * Inicia a disputa pelo lock Web Locks.\r\n *\r\n * `navigator.locks.request` com uma Promise-interna que nunca resolve:\r\n * enquanto a aba vive e o lock está ativo, a callback não retorna.\r\n * Ao chamar `destroy()` a Promise interna resolve → lock liberado.\r\n */\r\n private _electWithLocks(): void {\r\n const lockPromise = new Promise<void>((resolve) => {\r\n this._releaseLock = resolve;\r\n });\r\n\r\n // Notifica que esta aba está aguardando o lock (papel follower).\r\n // Feito de forma assíncrona para garantir que o chamador já registrou\r\n // seus listeners via onRoleChange() antes do primeiro disparo.\r\n Promise.resolve().then(() => {\r\n if (!this._destroyed && this._role === 'follower') {\r\n this._notifyRoleChange('follower');\r\n }\r\n });\r\n\r\n // `request` retorna uma Promise que resolve quando o lock é adquirido\r\n // e a callback retorna. Enquanto a callback não retornar, o lock é mantido.\r\n this._lockManager!.request(this._lockName, (_lock: LockLike) => {\r\n if (this._destroyed) {\r\n // Se foi destroyed antes de adquirir o lock, libera imediatamente\r\n return Promise.resolve();\r\n }\r\n this._becomeLeader();\r\n return lockPromise;\r\n }).catch(() => {\r\n // request rejeitado (ex.: lock request abortado) — sem crash\r\n });\r\n }\r\n\r\n /**\r\n * Transição para o papel de líder.\r\n */\r\n private _becomeLeader(): void {\r\n if (this._destroyed) return;\r\n this._setRole('leader');\r\n // Anuncia liderança para seguidores após o tick atual, garantindo que\r\n // todos os seguidores já registraram seus handlers de onmessage.\r\n Promise.resolve().then(() => {\r\n if (!this._destroyed) this._broadcastSyncState();\r\n });\r\n }\r\n\r\n /**\r\n * Muda o papel e notifica os listeners.\r\n */\r\n private _setRole(role: TabRole): void {\r\n const previous = this._role;\r\n this._role = role;\r\n if (previous !== role) {\r\n this._notifyRoleChange(role);\r\n }\r\n }\r\n\r\n /**\r\n * Transmite o estado de sync atual (chamado ao se tornar líder).\r\n */\r\n private _broadcastSyncState(): void {\r\n this.broadcast({\r\n type: 'sync_state',\r\n leaderTabId: this._tabId,\r\n syncing: false,\r\n pendingWrites: 0,\r\n });\r\n }\r\n\r\n // ─── Privado — mensagens ─────────────────────────────────────────────────────\r\n\r\n /**\r\n * Processa mensagem recebida de outra aba.\r\n * Mensagens de tipo desconhecido são ignoradas silenciosamente.\r\n */\r\n private _handleIncomingMessage(msg: TabMessage): void {\r\n if (this._destroyed) return;\r\n if (!msg || typeof msg.type !== 'string') return;\r\n\r\n // Entrega a todos os listeners registrados\r\n for (const listener of this._messageListeners) {\r\n try {\r\n listener(msg);\r\n } catch {\r\n // Listener com erro não interrompe os demais\r\n }\r\n }\r\n }\r\n\r\n // ─── Privado — notificações ───────────────────────────────────────────────────\r\n\r\n private _notifyRoleChange(role: TabRole): void {\r\n for (const listener of this._roleListeners) {\r\n try {\r\n listener(role);\r\n } catch {\r\n // Listener com erro não interrompe os demais\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * DbCollectionRef — superfície de Documentos offline-first do @neetru/sdk (M2).\r\n *\r\n * Implementa a API pública conforme especificada em:\r\n * - 02-sdk.md §3.2 (contrato TypeScript DbCollectionRef)\r\n * - I2-mundo-documentos.md §3.2 (superfície dupla CRUD + realtime)\r\n * - I3-sdk-offline.md §10 (camada offline, lifecycle, SyncState)\r\n *\r\n * ### Semântica de Promise de escrita (02-sdk.md §3.2 nota negrito)\r\n * `add/set/update/remove` resolvem quando a escrita está **durável localmente**\r\n * (cache + fila), NÃO quando o servidor confirma. Isso é offline-first por design:\r\n * sem rede, `add()` resolve imediatamente. Para saber quando sincronizou, o produto\r\n * observa `onWriteResult` (future / SyncEngine). A Promise só rejeita por:\r\n * - validação síncrona (nome de coleção inválido, id vazio)\r\n * - `offline_quota_exceeded` (IndexedDB cheio)\r\n *\r\n * ### Injeção do transporte realtime\r\n * O `RealtimeTransport` é injetado via `createOfflineDocumentsNamespace({ transport })`.\r\n * A implementação atual usa o `SyncEngine` para push/pull (sync offline ↔ servidor).\r\n * Transportes futuros (Firestore Web SDK / WebSocket gateway) são injetados aqui —\r\n * sem alterar a superfície pública.\r\n */\r\n\r\nimport { LocalStore } from './offline/local-store';\r\nimport { MemoryStore } from './offline/memory-store';\r\nimport { MutationQueue } from './offline/mutation-queue';\r\nimport { SyncEngine, type SyncTransport } from './offline/sync-engine';\r\nimport { ConflictResolver } from './offline/conflict-resolver';\r\nimport { ChangeBus } from './offline/change-bus';\r\nimport { ConnectivityMonitor } from './offline/connectivity-monitor';\r\nimport { TabCoordinator } from './offline/tab-coordinator';\r\nimport { NeetruDbError } from '../db-errors';\r\nimport { resolveSentinelsLocally } from './field-value';\r\nimport type { FieldSentinel } from './field-value';\r\nimport type {\r\n QueryDescriptor,\r\n Change,\r\n Unsubscribe,\r\n SyncState,\r\n ConflictRecord,\r\n} from './offline/types';\r\n\r\n// ─── Runtime detection ────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Retorna `true` quando o runtime NÃO tem IndexedDB — i.e., Node.js, Bun,\r\n * Edge Workers sem IDB (Cloudflare Workers base, Vercel Edge Runtime).\r\n *\r\n * A heurística combinada é mais robusta do que checar apenas `typeof window`:\r\n * - `typeof indexedDB === 'undefined'` → ausente no runtime atual\r\n * - `typeof window === 'undefined'` → contexto não-browser\r\n *\r\n * Qualquer uma das condições sendo verdadeira sinaliza que IndexedDB não está\r\n * disponível e o fallback MemoryStore deve ser usado.\r\n */\r\nfunction isIndexedDBUnavailable(): boolean {\r\n return (\r\n typeof indexedDB === 'undefined' ||\r\n typeof window === 'undefined'\r\n );\r\n}\r\n\r\n// ─── Re-exportar tipos públicos ───────────────────────────────────────────────\r\n\r\nexport type { DbSnapshot } from './offline/types';\r\nexport { NeetruDbError } from '../db-errors';\r\nexport {\r\n serverTimestamp,\r\n increment,\r\n isFieldSentinel,\r\n isServerTimestampSentinel,\r\n isIncrementSentinel,\r\n NEETRU_SENTINEL_KEY,\r\n} from './field-value';\r\nexport type {\r\n FieldSentinel,\r\n ServerTimestampSentinel,\r\n IncrementSentinel,\r\n} from './field-value';\r\n\r\n// ─── Tipos de escrita com sentinels ───────────────────────────────────────────\r\n\r\n/**\r\n * Permite que cada campo de `T` aceite, além do seu tipo declarado, um sentinel\r\n * de escrita server-side (`serverTimestamp()` / `increment()`).\r\n *\r\n * Sem isso, um produto que tipa `createdAt: number` veria erro de tipo ao passar\r\n * `serverTimestamp()`. Esta projeção mantém o autocomplete dos campos do produto\r\n * e ainda autoriza os sentinels onde fizer sentido.\r\n *\r\n * @example\r\n * ```ts\r\n * interface Order { total: number; createdAt: number; hits: number }\r\n * orders.add({ total: 10, createdAt: serverTimestamp(), hits: increment(1) });\r\n * ```\r\n */\r\nexport type WithFieldSentinels<T> = {\r\n [K in keyof T]: T[K] | FieldSentinel;\r\n};\r\n\r\n// ─── Tipos públicos da superfície de Documentos ───────────────────────────────\r\n\r\nexport interface DbWhereFilter {\r\n field: string;\r\n op: '==' | '!=' | '<' | '<=' | '>' | '>=' | 'array-contains' | 'in' | 'not-in';\r\n value: unknown;\r\n}\r\n\r\nexport interface DbQuery {\r\n where?: DbWhereFilter[];\r\n orderBy?: { field: string; direction?: 'asc' | 'desc' };\r\n /** Máximo de documentos. Default 20, max 500. */\r\n limit?: number;\r\n /** Cursor opaco — devolvido em `DbListResult.nextCursor`. */\r\n cursor?: string;\r\n}\r\n\r\nexport interface DbDoc<T = Record<string, unknown>> {\r\n id: string;\r\n data: T;\r\n}\r\n\r\nexport interface DbListResult<T = Record<string, unknown>> {\r\n docs: DbDoc<T>[];\r\n nextCursor: string | null;\r\n fromCache: boolean;\r\n stale: boolean;\r\n hasPendingWrites: boolean;\r\n changes: Array<{ type: 'added' | 'modified' | 'removed'; doc: DbDoc<T> }>;\r\n}\r\n\r\nexport interface DbGetResult<T = Record<string, unknown>> {\r\n docs: Array<DbDoc<T>>;\r\n fromCache: boolean;\r\n stale: boolean;\r\n hasPendingWrites: boolean;\r\n changes: Array<{ type: 'added' | 'modified' | 'removed'; doc: DbDoc<T> }>;\r\n}\r\n\r\nexport type DbChangeType = 'added' | 'modified' | 'removed';\r\n\r\n/**\r\n * Operação atômica para uso em `DbCollectionRef.batch()`.\r\n *\r\n * Discriminated union pelo campo `kind` — cada variante deixa claro\r\n * quais campos são obrigatórios:\r\n *\r\n * - `add` — insere com id gerado pelo cliente; `data` obrigatório.\r\n * - `set` — cria ou sobrescreve pelo `id`; `data` obrigatório.\r\n * - `update` — mescla campos em doc existente pelo `id`; `data` obrigatório.\r\n * - `remove` — tombstone pelo `id`; sem `data`.\r\n *\r\n * @example\r\n * ```ts\r\n * const ops: DbBatchOp[] = [\r\n * { kind: 'add', data: { name: 'produto A', price: 10 } },\r\n * { kind: 'set', id: 'sku-1', data: { name: 'produto B', price: 20 } },\r\n * { kind: 'update', id: 'sku-2', data: { price: 25 } },\r\n * { kind: 'remove', id: 'sku-3' },\r\n * ];\r\n * await col.batch(ops);\r\n * ```\r\n */\r\nexport type DbBatchOp<T = Record<string, unknown>> =\r\n | { kind: 'add'; data: WithFieldSentinels<Omit<T, 'id'>> }\r\n | { kind: 'set'; id: string; data: WithFieldSentinels<Omit<T, 'id'>> }\r\n | { kind: 'update'; id: string; data: Partial<WithFieldSentinels<Omit<T, 'id'>>> }\r\n | { kind: 'remove'; id: string };\r\n\r\n/**\r\n * Contrato do transporte de realtime — injetado no namespace.\r\n *\r\n * A implementação real usa os endpoints `/api/sdk/v1/db/*` do Core.\r\n * Em testes, usa-se um fake in-memory.\r\n *\r\n * Este é o **seam de injeção** que conecta a camada offline ao servidor real.\r\n * Transportes futuros (Firestore Web SDK direto / WebSocket gateway) são\r\n * implementados aqui, sem modificar a superfície pública `DbCollectionRef`.\r\n */\r\nexport type RealtimeTransport = SyncTransport;\r\n\r\n// ─── Validação de nome de coleção ─────────────────────────────────────────────\r\n\r\nconst COLL_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/;\r\n\r\nfunction assertValidCollection(name: string): void {\r\n if (!COLL_RE.test(name)) {\r\n throw new NeetruDbError(\r\n 'db_invalid_query',\r\n `Nome de coleção inválido: \"${name}\". Deve seguir o padrão ${COLL_RE}.`,\r\n );\r\n }\r\n}\r\n\r\nfunction assertValidId(id: string, label = 'id'): void {\r\n if (!id || typeof id !== 'string' || id.trim() === '') {\r\n throw new NeetruDbError(\r\n 'db_invalid_query',\r\n `${label} é obrigatório e deve ser uma string não-vazia.`,\r\n );\r\n }\r\n}\r\n\r\n// ─── Serialização de DbQuery → QueryDescriptor ────────────────────────────────\r\n\r\nfunction toQueryDescriptor(query?: DbQuery): QueryDescriptor {\r\n const desc: QueryDescriptor = {};\r\n\r\n if (query?.where) {\r\n desc.where = query.where.map((f) => ({\r\n field: f.field,\r\n op: f.op as import('./offline/types').WhereOp,\r\n value: f.value,\r\n }));\r\n }\r\n\r\n if (query?.orderBy) {\r\n desc.orderBy = {\r\n field: query.orderBy.field,\r\n direction: query.orderBy.direction,\r\n };\r\n }\r\n\r\n if (query?.limit !== undefined) {\r\n desc.limit = query.limit;\r\n }\r\n\r\n if (query?.cursor) {\r\n // O cursor é o docId serializado em base64\r\n try {\r\n const cursorObj = JSON.parse(atob(query.cursor)) as { docId: string; type: 'startAfter' };\r\n desc.cursor = { type: cursorObj.type ?? 'startAfter', docId: cursorObj.docId };\r\n } catch {\r\n // cursor inválido — ignora\r\n }\r\n }\r\n\r\n return desc;\r\n}\r\n\r\n/** Serializa o último doc de uma lista como cursor opaco. */\r\nfunction buildNextCursor(docs: Array<{ id: string }>, limit: number): string | null {\r\n if (docs.length < limit) return null;\r\n const lastDoc = docs[docs.length - 1];\r\n if (!lastDoc) return null;\r\n return btoa(JSON.stringify({ type: 'startAfter', docId: lastDoc.id }));\r\n}\r\n\r\n// ─── DbDocRef ─────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Referência a um documento específico.\r\n * Parte da superfície `DbCollectionRef.doc(id)`.\r\n *\r\n * Expõe as propriedades de identidade do documento de forma análoga ao\r\n * `DocumentReference` do Firestore SDK, evitando a necessidade de adaptadores\r\n * externos que reattachavam `collection` + `id` manualmente.\r\n *\r\n * @example\r\n * ```ts\r\n * const ref = orders.doc('order-123');\r\n * console.log(ref.id); // \"order-123\"\r\n * console.log(ref.collection); // \"orders\"\r\n * console.log(ref.path); // \"orders/order-123\"\r\n * ```\r\n */\r\nexport interface DbDocRef<T = Record<string, unknown>> {\r\n /** ID do documento dentro da coleção. */\r\n readonly id: string;\r\n /** Caminho completo no formato \"collection/docId\". */\r\n readonly path: string;\r\n /** Nome da coleção parent. */\r\n readonly collection: string;\r\n\r\n get(): Promise<DbGetResult<T> | null>;\r\n set(data: WithFieldSentinels<Omit<T, 'id'>>): Promise<{ ok: true }>;\r\n update(data: Partial<WithFieldSentinels<Omit<T, 'id'>>>): Promise<{ ok: true }>;\r\n remove(): Promise<{ ok: true }>;\r\n onSnapshot(cb: (snap: DbGetResult<T> | null) => void): Unsubscribe;\r\n}\r\n\r\n// ─── DbCollectionRef ──────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Referência a uma coleção — superfície dupla CRUD + realtime.\r\n *\r\n * Conforme 02-sdk.md §3.2 / I2 §3.2.\r\n */\r\nexport interface DbCollectionRef<T = Record<string, unknown>> {\r\n // ── CRUD (request/resposta offline-transparente) ──────────────────────────\r\n /** Retorna snapshot de um documento. `null` se não existir (nem no cache). */\r\n get(id: string): Promise<DbGetResult<T> | null>;\r\n /** Lista documentos com query opcional. */\r\n list(q?: DbQuery): Promise<DbListResult<T>>;\r\n /** Adiciona doc com id gerado pelo cliente (UUID v4). Durável localmente. */\r\n add(data: WithFieldSentinels<Omit<T, 'id'>>): Promise<{ ok: true; id: string }>;\r\n /** Cria ou sobrescreve um doc pelo id. Durável localmente. */\r\n set(id: string, data: WithFieldSentinels<Omit<T, 'id'>>): Promise<{ ok: true }>;\r\n /** Atualiza campos de um doc (merge). Durável localmente. */\r\n update(id: string, data: Partial<WithFieldSentinels<Omit<T, 'id'>>>): Promise<{ ok: true }>;\r\n /** Remove um doc (tombstone local). Durável localmente. */\r\n remove(id: string): Promise<{ ok: true }>;\r\n /** Aplica múltiplas operações atomicamente na fila. */\r\n batch(ops: DbBatchOp<T>[]): Promise<{ ok: true }>;\r\n\r\n // ── Realtime (listeners ao vivo) ──────────────────────────────────────────\r\n /** Escuta um documento específico. */\r\n onDoc(id: string, cb: (doc: T | null) => void): Unsubscribe;\r\n /** Escuta a coleção inteira (ou subconjunto via query). */\r\n onSnapshot(q: DbQuery | undefined, cb: (snap: DbListResult<T>) => void): Unsubscribe;\r\n\r\n // ── DbDocRef ──────────────────────────────────────────────────────────────\r\n /** Retorna uma referência ao documento `id`. */\r\n doc(id: string): DbDocRef<T>;\r\n}\r\n\r\n// ─── NeetruDbDocuments namespace ─────────────────────────────────────────────\r\n\r\n/**\r\n * Namespace `db.documents` — ponto de entrada para coleções de documentos.\r\n *\r\n * Analogia a `NeetruDb` de 02-sdk.md §3.1 mas escoped para o Mundo Documentos.\r\n */\r\nexport interface NeetruDbDocuments {\r\n collection<T = Record<string, unknown>>(name: string): DbCollectionRef<T>;\r\n /** Estado atual de sincronização (offline/online/syncing). */\r\n readonly syncState: SyncState;\r\n onSyncStateChanged(cb: (s: SyncState) => void): Unsubscribe;\r\n /** Força flush da fila de mutações pendentes. */\r\n flush(): Promise<void>;\r\n /** Limpa o cache local (IndexedDB) — operação destrutiva. */\r\n clearCache(): Promise<void>;\r\n /**\r\n * Retorna os registros do log de conflitos LWW gravados pelo SyncEngine.\r\n * Um conflito ocorre quando a mutação local é descartada porque o servidor\r\n * já avançou a versão do documento (Last-Write-Wins).\r\n */\r\n getConflicts(): Promise<ConflictRecord[]>;\r\n}\r\n\r\n// ─── Opções de criação do namespace ──────────────────────────────────────────\r\n\r\nexport interface CreateOfflineDocumentsOptions {\r\n /**\r\n * Nome do banco IndexedDB — deve ser único por produto × dbId × env.\r\n * Convenção: `neetru-db__{productSlug}__{dbId}__{env}`.\r\n */\r\n dbName: string;\r\n\r\n /**\r\n * Transporte de sync — implementa `SyncTransport` do SyncEngine.\r\n * Este é o **seam de injeção** do transporte real.\r\n *\r\n * Implementações possíveis:\r\n * - `RestSyncTransport` — REST → Core (padrão em staging/prod)\r\n * - `FirestoreRealtimeTransport` — Firestore Web SDK direto (engine=firestore)\r\n * - `WebSocketTransport` — WebSocket → gateway (engine=nosql-vm)\r\n * - `FakeRealtimeTransport` — in-memory (testes)\r\n */\r\n transport: RealtimeTransport;\r\n\r\n /**\r\n * Estado inicial de conectividade.\r\n * Default: `navigator.onLine` se disponível, senão `true`.\r\n */\r\n startOnline?: boolean;\r\n\r\n /**\r\n * `true` = sem contenção multi-aba (sempre líder).\r\n * Padrão em testes; em produção usa Web Locks.\r\n */\r\n singleTab?: boolean;\r\n\r\n /**\r\n * Intervalo do sync periódico em ms. `0` desativa.\r\n * Default: 5 * 60 * 1000 (5min).\r\n */\r\n periodicSyncIntervalMs?: number;\r\n}\r\n\r\n// ─── Implementação interna ────────────────────────────────────────────────────\r\n\r\n/**\r\n * Implementação de `DbCollectionRef` que usa a camada offline real.\r\n */\r\nclass DbCollectionRefImpl<T = Record<string, unknown>> implements DbCollectionRef<T> {\r\n constructor(\r\n private readonly _collection: string,\r\n private readonly _store: LocalStore,\r\n private readonly _queue: MutationQueue,\r\n private readonly _bus: ChangeBus,\r\n private readonly _engine: SyncEngine,\r\n private readonly _connectivity: ConnectivityMonitor,\r\n ) {}\r\n\r\n // ── helpers ────────────────────────────────────────────────────────────────\r\n\r\n /** Verifica se há mutações pendentes para esta coleção. */\r\n private async _hasPendingWrites(): Promise<boolean> {\r\n const pending = await this._queue.listPending();\r\n return pending.some((m) => m.collection === this._collection);\r\n }\r\n\r\n /** Verifica se há mutações pendentes para um doc específico. */\r\n private async _docHasPendingWrites(id: string): Promise<boolean> {\r\n const pending = await this._queue.listPending();\r\n return pending.some((m) => m.collection === this._collection && m.docId === id);\r\n }\r\n\r\n private _isOnline(): boolean {\r\n return this._connectivity.isOnline;\r\n }\r\n\r\n /** Constrói um DbGetResult para um doc específico, ou null se tombstoned/ausente. */\r\n private async _buildGetResult(id: string): Promise<DbGetResult<T> | null> {\r\n const doc = await this._store.getDoc<T>(this._collection, id);\r\n if (!doc || doc.meta.deleted) return null;\r\n\r\n const hasPending = await this._docHasPendingWrites(id);\r\n const isOnline = this._isOnline();\r\n const syncState = this._engine.getSyncState();\r\n\r\n const staleGet = !isOnline || syncState.status === 'offline';\r\n const fromCacheGet = hasPending || syncState.lastSyncedAt === null || staleGet;\r\n\r\n return {\r\n docs: [{ id: doc.id, data: doc.data }],\r\n fromCache: fromCacheGet,\r\n stale: staleGet,\r\n hasPendingWrites: hasPending,\r\n changes: [],\r\n };\r\n }\r\n\r\n /** Constrói um DbListResult para a coleção com query opcional. */\r\n private async _buildListResult(q?: DbQuery): Promise<DbListResult<T>> {\r\n const desc = toQueryDescriptor(q);\r\n const effectiveLimit = desc.limit ?? 20;\r\n const result = await this._store.listDocs<T>(this._collection, desc);\r\n\r\n const hasPending = await this._hasPendingWrites();\r\n const isOnline = this._isOnline();\r\n const syncState = this._engine.getSyncState();\r\n\r\n const nextCursor = buildNextCursor(result.docs, effectiveLimit);\r\n\r\n // fromCache: false quando há um lastSyncedAt confirmado e sem pending writes.\r\n // offline-first: antes do primeiro sync bem-sucedido é sempre fromCache:true.\r\n const stale = !isOnline || syncState.status === 'offline';\r\n const fromCache = hasPending || syncState.lastSyncedAt === null || stale;\r\n\r\n return {\r\n docs: result.docs.map((d) => ({ id: d.id, data: d.data })),\r\n nextCursor,\r\n fromCache,\r\n stale,\r\n hasPendingWrites: hasPending,\r\n changes: [],\r\n };\r\n }\r\n\r\n // ── CRUD ────────────────────────────────────────────────────────────────────\r\n\r\n async get(id: string): Promise<DbGetResult<T> | null> {\r\n assertValidId(id);\r\n return this._buildGetResult(id);\r\n }\r\n\r\n async list(q?: DbQuery): Promise<DbListResult<T>> {\r\n return this._buildListResult(q);\r\n }\r\n\r\n async add(data: WithFieldSentinels<Omit<T, 'id'>>): Promise<{ ok: true; id: string }> {\r\n // O payload da mutação carrega os sentinels CRUS (serverTimestamp/increment)\r\n // — o Core os resolve canonicamente na escrita. O cache local recebe uma\r\n // aproximação otimista (Date.now() / soma local) para a UI não piscar.\r\n const rawData = data as Record<string, unknown>;\r\n const localData = resolveSentinelsLocally(rawData, undefined);\r\n\r\n const mutation = await this._queue.enqueue({\r\n collection: this._collection,\r\n op: 'add',\r\n payload: rawData,\r\n baseVersion: null,\r\n batchId: null,\r\n });\r\n\r\n const docId = mutation.docId;\r\n\r\n // Aplica otimisticamente no LocalStore\r\n await this._store.putDoc({\r\n collection: this._collection,\r\n id: docId,\r\n data: localData,\r\n meta: {\r\n serverVersion: null,\r\n updatedAtServer: null,\r\n updatedAtLocal: Date.now(),\r\n state: 'pending',\r\n pendingMutationIds: [mutation.mutationId],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n });\r\n\r\n // Notifica listeners\r\n this._bus.emit([{\r\n type: 'added',\r\n collection: this._collection,\r\n doc: { id: docId, data: localData },\r\n }]);\r\n\r\n return { ok: true, id: docId };\r\n }\r\n\r\n async set(id: string, data: WithFieldSentinels<Omit<T, 'id'>>): Promise<{ ok: true }> {\r\n assertValidId(id);\r\n\r\n const existing = await this._store.getDoc(this._collection, id);\r\n const rawData = data as Record<string, unknown>;\r\n // set substitui o doc inteiro — increment usa base 0 (não o doc anterior),\r\n // espelhando a semântica do Core (`ref.set(...)` sem merge).\r\n const localData = resolveSentinelsLocally(rawData, undefined);\r\n\r\n const mutation = await this._queue.enqueue({\r\n collection: this._collection,\r\n docId: id,\r\n op: 'set',\r\n payload: rawData,\r\n baseVersion: existing?.meta.serverVersion ?? null,\r\n batchId: null,\r\n });\r\n\r\n // Aplica otimisticamente\r\n await this._store.putDoc({\r\n collection: this._collection,\r\n id,\r\n data: localData,\r\n meta: {\r\n serverVersion: existing?.meta.serverVersion ?? null,\r\n updatedAtServer: existing?.meta.updatedAtServer ?? null,\r\n updatedAtLocal: Date.now(),\r\n state: 'pending',\r\n pendingMutationIds: [mutation.mutationId],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n });\r\n\r\n this._bus.emit([{\r\n type: existing && !existing.meta.deleted ? 'modified' : 'added',\r\n collection: this._collection,\r\n doc: { id, data: localData },\r\n }]);\r\n\r\n return { ok: true };\r\n }\r\n\r\n async update(id: string, data: Partial<WithFieldSentinels<Omit<T, 'id'>>>): Promise<{ ok: true }> {\r\n assertValidId(id);\r\n\r\n const existing = await this._store.getDoc(this._collection, id);\r\n const rawData = data as Record<string, unknown>;\r\n // Resolve sentinels otimisticamente contra o doc atual (base de increment).\r\n // Em doc deletado, increment parte de 0 (não há valor anterior válido).\r\n const existingBase = existing?.meta.deleted ? undefined : existing?.data;\r\n const localData = resolveSentinelsLocally(rawData, existingBase);\r\n const mergedData = existing?.meta.deleted\r\n ? { ...localData }\r\n : { ...(existing?.data ?? {}), ...localData };\r\n\r\n const mutation = await this._queue.enqueue({\r\n collection: this._collection,\r\n docId: id,\r\n op: 'update',\r\n payload: rawData,\r\n baseVersion: existing?.meta.serverVersion ?? null,\r\n batchId: null,\r\n });\r\n\r\n await this._store.putDoc({\r\n collection: this._collection,\r\n id,\r\n data: mergedData,\r\n meta: {\r\n serverVersion: existing?.meta.serverVersion ?? null,\r\n updatedAtServer: existing?.meta.updatedAtServer ?? null,\r\n updatedAtLocal: Date.now(),\r\n state: 'pending',\r\n pendingMutationIds: [\r\n ...(existing?.meta.pendingMutationIds ?? []),\r\n mutation.mutationId,\r\n ],\r\n deleted: false,\r\n ownerId: existing?.meta.ownerId ?? null,\r\n },\r\n });\r\n\r\n this._bus.emit([{\r\n type: 'modified',\r\n collection: this._collection,\r\n doc: { id, data: mergedData },\r\n }]);\r\n\r\n return { ok: true };\r\n }\r\n\r\n async remove(id: string): Promise<{ ok: true }> {\r\n assertValidId(id);\r\n\r\n const existing = await this._store.getDoc(this._collection, id);\r\n if (!existing || existing.meta.deleted) {\r\n // Se era um doc add-only ainda na fila, o coalescing no MutationQueue vai lidar\r\n }\r\n\r\n await this._queue.enqueue({\r\n collection: this._collection,\r\n docId: id,\r\n op: 'remove',\r\n payload: null,\r\n baseVersion: existing?.meta.serverVersion ?? null,\r\n batchId: null,\r\n });\r\n\r\n // Tombstone otimístico\r\n await this._store.deleteDoc(this._collection, id);\r\n\r\n if (existing && !existing.meta.deleted) {\r\n this._bus.emit([{\r\n type: 'removed',\r\n collection: this._collection,\r\n doc: { id, data: existing.data },\r\n }]);\r\n }\r\n\r\n return { ok: true };\r\n }\r\n\r\n async batch(ops: DbBatchOp<T>[]): Promise<{ ok: true }> {\r\n const batchId = `batch-${Date.now()}-${Math.random().toString(36).slice(2)}`;\r\n const busChanges: Change[] = [];\r\n\r\n for (const op of ops) {\r\n const collection = this._collection;\r\n\r\n if (op.kind === 'add') {\r\n const data = op.data as Record<string, unknown>;\r\n const localData = resolveSentinelsLocally(data, undefined);\r\n const mutation = await this._queue.enqueue({\r\n collection,\r\n op: 'add',\r\n payload: data,\r\n baseVersion: null,\r\n batchId,\r\n });\r\n const docId = mutation.docId;\r\n await this._store.putDoc({\r\n collection,\r\n id: docId,\r\n data: localData,\r\n meta: {\r\n serverVersion: null,\r\n updatedAtServer: null,\r\n updatedAtLocal: Date.now(),\r\n state: 'pending',\r\n pendingMutationIds: [mutation.mutationId],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n });\r\n busChanges.push({ type: 'added', collection, doc: { id: docId, data: localData } });\r\n } else if (op.kind === 'set') {\r\n const id = op.id;\r\n const data = op.data as Record<string, unknown>;\r\n const existing = await this._store.getDoc(collection, id);\r\n const localData = resolveSentinelsLocally(data, undefined);\r\n const mutation = await this._queue.enqueue({\r\n collection,\r\n docId: id,\r\n op: 'set',\r\n payload: data,\r\n baseVersion: existing?.meta.serverVersion ?? null,\r\n batchId,\r\n });\r\n await this._store.putDoc({\r\n collection,\r\n id,\r\n data: localData,\r\n meta: {\r\n serverVersion: existing?.meta.serverVersion ?? null,\r\n updatedAtServer: existing?.meta.updatedAtServer ?? null,\r\n updatedAtLocal: Date.now(),\r\n state: 'pending',\r\n pendingMutationIds: [mutation.mutationId],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n });\r\n busChanges.push({\r\n type: existing && !existing.meta.deleted ? 'modified' : 'added',\r\n collection,\r\n doc: { id, data: localData },\r\n });\r\n } else if (op.kind === 'update') {\r\n const id = op.id;\r\n const data = op.data as Record<string, unknown>;\r\n const existing = await this._store.getDoc(collection, id);\r\n const existingBase = existing?.meta.deleted ? undefined : existing?.data;\r\n const localData = resolveSentinelsLocally(data, existingBase);\r\n const merged = { ...(existing?.data ?? {}), ...localData };\r\n const mutation = await this._queue.enqueue({\r\n collection,\r\n docId: id,\r\n op: 'update',\r\n payload: data,\r\n baseVersion: existing?.meta.serverVersion ?? null,\r\n batchId,\r\n });\r\n await this._store.putDoc({\r\n collection,\r\n id,\r\n data: merged,\r\n meta: {\r\n serverVersion: existing?.meta.serverVersion ?? null,\r\n updatedAtServer: existing?.meta.updatedAtServer ?? null,\r\n updatedAtLocal: Date.now(),\r\n state: 'pending',\r\n pendingMutationIds: [\r\n ...(existing?.meta.pendingMutationIds ?? []),\r\n mutation.mutationId,\r\n ],\r\n deleted: false,\r\n ownerId: existing?.meta.ownerId ?? null,\r\n },\r\n });\r\n busChanges.push({ type: 'modified', collection, doc: { id, data: merged } });\r\n } else if (op.kind === 'remove') {\r\n const id = op.id;\r\n const existing = await this._store.getDoc(collection, id);\r\n await this._queue.enqueue({\r\n collection,\r\n docId: id,\r\n op: 'remove',\r\n payload: null,\r\n baseVersion: existing?.meta.serverVersion ?? null,\r\n batchId,\r\n });\r\n await this._store.deleteDoc(collection, id);\r\n if (existing && !existing.meta.deleted) {\r\n busChanges.push({ type: 'removed', collection, doc: { id, data: existing.data } });\r\n }\r\n }\r\n }\r\n\r\n if (busChanges.length > 0) {\r\n this._bus.emit(busChanges);\r\n }\r\n\r\n return { ok: true };\r\n }\r\n\r\n // ── Realtime ─────────────────────────────────────────────────────────────────\r\n\r\n onDoc(id: string, cb: (doc: T | null) => void): Unsubscribe {\r\n assertValidId(id);\r\n\r\n // Entrega inicial imediata\r\n this._buildGetResult(id)\r\n .then((r) => {\r\n cb(r ? (r.docs[0]?.data ?? null) as T | null : null);\r\n })\r\n .catch(() => cb(null));\r\n\r\n // Subscreve ao bus da coleção para receber mudanças\r\n return this._bus.subscribe(this._collection, (changes) => {\r\n const relevant = changes.find((c) => c.doc.id === id);\r\n if (!relevant) return;\r\n\r\n if (relevant.type === 'removed') {\r\n cb(null);\r\n } else {\r\n cb(relevant.doc.data as T);\r\n }\r\n });\r\n }\r\n\r\n onSnapshot(q: DbQuery | undefined, cb: (snap: DbListResult<T>) => void): Unsubscribe {\r\n // Entrega inicial imediata (estado atual do cache)\r\n this._buildListResult(q).then((snap) => cb(snap)).catch(() => {});\r\n\r\n // Listener de mudanças do bus (local + server-pushed)\r\n const unsubBus = this._bus.subscribe(this._collection, async (_changes) => {\r\n try {\r\n // Reconstrói o snapshot completo com o estado atual + changes delta\r\n const snap = await this._buildListResult(q);\r\n\r\n // Injeta delta de changes (apenas os relevantes para a query)\r\n const delta = _changes.map((c) => ({\r\n type: c.type as DbChangeType,\r\n doc: { id: c.doc.id, data: c.doc.data as T },\r\n }));\r\n cb({ ...snap, changes: delta });\r\n } catch {\r\n // silencioso\r\n }\r\n });\r\n\r\n // Listener de mudanças de SyncState (para atualizar stale/fromCache)\r\n const unsubSync = this._engine.onSyncStateChange(async () => {\r\n try {\r\n const snap = await this._buildListResult(q);\r\n cb(snap);\r\n } catch {\r\n // silencioso\r\n }\r\n });\r\n\r\n // HIGH-1: se o transporte expõe subscribeCollection (nosql-vm/realtime),\r\n // registra a subscription e alimenta os deltas no ChangeBus local.\r\n let unsubRealtime: (() => void) | undefined;\r\n if (typeof (this._engine.transport as SyncTransport).subscribeCollection === 'function') {\r\n unsubRealtime = (this._engine.transport as SyncTransport).subscribeCollection!(\r\n this._collection,\r\n async (remoteChanges, needsResync) => {\r\n if (needsResync) {\r\n // Marca sincronização necessária via SyncState — o SyncEngine\r\n // disparará um fullResync no próximo ciclo.\r\n return;\r\n }\r\n // Converte as mudanças remotas para Change[] e aplica no LocalStore\r\n for (const rc of remoteChanges) {\r\n if (rc.type === 'removed' || rc.data === null) {\r\n await this._store.deleteDoc(this._collection, rc.docId);\r\n this._bus.emit([{\r\n type: 'removed',\r\n collection: this._collection,\r\n doc: { id: rc.docId, data: {} as Record<string, unknown> },\r\n }]);\r\n } else {\r\n await this._store.putDoc({\r\n collection: this._collection,\r\n id: rc.docId,\r\n data: rc.data,\r\n meta: {\r\n serverVersion: `rt_${Date.now()}`,\r\n updatedAtServer: Date.now(),\r\n updatedAtLocal: Date.now(),\r\n state: 'synced',\r\n pendingMutationIds: [],\r\n deleted: false,\r\n ownerId: null,\r\n },\r\n });\r\n this._bus.emit([{\r\n type: rc.type,\r\n collection: this._collection,\r\n doc: { id: rc.docId, data: rc.data },\r\n }]);\r\n }\r\n }\r\n },\r\n );\r\n }\r\n\r\n return () => {\r\n unsubBus();\r\n unsubSync();\r\n unsubRealtime?.();\r\n };\r\n }\r\n\r\n doc(id: string): DbDocRef<T> {\r\n assertValidId(id);\r\n const self = this;\r\n\r\n return {\r\n get id(): string { return id; },\r\n get path(): string { return `${self._collection}/${id}`; },\r\n get collection(): string { return self._collection; },\r\n\r\n async get(): Promise<DbGetResult<T> | null> {\r\n return self._buildGetResult(id);\r\n },\r\n async set(data: WithFieldSentinels<Omit<T, 'id'>>): Promise<{ ok: true }> {\r\n return self.set(id, data);\r\n },\r\n async update(data: Partial<WithFieldSentinels<Omit<T, 'id'>>>): Promise<{ ok: true }> {\r\n return self.update(id, data);\r\n },\r\n async remove(): Promise<{ ok: true }> {\r\n return self.remove(id);\r\n },\r\n onSnapshot(cb: (snap: DbGetResult<T> | null) => void): Unsubscribe {\r\n // Entrega inicial\r\n self._buildGetResult(id).then((r) => cb(r)).catch(() => cb(null));\r\n\r\n const unsubBus = self._bus.subscribe(self._collection, async (changes) => {\r\n const relevant = changes.find((c) => c.doc.id === id);\r\n if (!relevant) return;\r\n try {\r\n if (relevant.type === 'removed') {\r\n cb(null);\r\n } else {\r\n const result = await self._buildGetResult(id);\r\n cb(result);\r\n }\r\n } catch {\r\n cb(null);\r\n }\r\n });\r\n\r\n const unsubSync = self._engine.onSyncStateChange(async () => {\r\n try {\r\n const result = await self._buildGetResult(id);\r\n cb(result);\r\n } catch {\r\n cb(null);\r\n }\r\n });\r\n\r\n return () => {\r\n unsubBus();\r\n unsubSync();\r\n };\r\n },\r\n };\r\n }\r\n}\r\n\r\n// ─── Implementação de NeetruDbDocuments ──────────────────────────────────────\r\n\r\nclass NeetruDbDocumentsImpl implements NeetruDbDocuments {\r\n private readonly _store: LocalStore;\r\n private readonly _queue: MutationQueue;\r\n private readonly _bus: ChangeBus;\r\n private readonly _engine: SyncEngine;\r\n private readonly _connectivity: ConnectivityMonitor;\r\n\r\n constructor(opts: {\r\n store: LocalStore;\r\n queue: MutationQueue;\r\n bus: ChangeBus;\r\n engine: SyncEngine;\r\n connectivity: ConnectivityMonitor;\r\n }) {\r\n this._store = opts.store;\r\n this._queue = opts.queue;\r\n this._bus = opts.bus;\r\n this._engine = opts.engine;\r\n this._connectivity = opts.connectivity;\r\n }\r\n\r\n collection<T = Record<string, unknown>>(name: string): DbCollectionRef<T> {\r\n assertValidCollection(name);\r\n return new DbCollectionRefImpl<T>(\r\n name,\r\n this._store,\r\n this._queue,\r\n this._bus,\r\n this._engine,\r\n this._connectivity,\r\n );\r\n }\r\n\r\n get syncState(): SyncState {\r\n return this._engine.getSyncState();\r\n }\r\n\r\n onSyncStateChanged(cb: (s: SyncState) => void): Unsubscribe {\r\n return this._engine.onSyncStateChange(cb);\r\n }\r\n\r\n async flush(): Promise<void> {\r\n return this._engine.flush();\r\n }\r\n\r\n async clearCache(): Promise<void> {\r\n // BUG fix: `close()` + `open()` apenas reabre o mesmo banco IndexedDB sem\r\n // apagar os dados. `clearAll()` chama `indexedDB.deleteDatabase()` (LocalStore)\r\n // ou limpa os Maps internos (MemoryStore) antes de reabrir — dados realmente\r\n // descartados. Cast necessário porque `store` é tipado como `LocalStore` mas\r\n // em runtime pode ser `MemoryStore` (fallback para Node/Edge sem IndexedDB).\r\n const storeWithClear = this._store as unknown as { clearAll?: () => Promise<void> };\r\n if (typeof storeWithClear.clearAll === 'function') {\r\n await storeWithClear.clearAll();\r\n } else {\r\n // Fallback defensivo para stores customizadas sem clearAll.\r\n await this._store.close();\r\n await this._store.open();\r\n }\r\n }\r\n\r\n async getConflicts(): Promise<ConflictRecord[]> {\r\n return this._store.listConflicts();\r\n }\r\n}\r\n\r\n// ─── Factory pública ─────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Cria e inicializa o namespace de documentos offline-first.\r\n *\r\n * Configura todos os 8 componentes da camada offline (LocalStore, MutationQueue,\r\n * QueryEngine, SyncEngine, ConflictResolver, ConnectivityMonitor, TabCoordinator,\r\n * ChangeBus) e os liga ao `RealtimeTransport` injetado.\r\n *\r\n * @example\r\n * ```ts\r\n * // Em produção (transport real injetado pelo resolver do Core):\r\n * const ns = await createOfflineDocumentsNamespace({\r\n * dbName: 'neetru-db__my-product__db1__production',\r\n * transport: new RestSyncTransport(config),\r\n * });\r\n * const orders = ns.collection<Order>('orders');\r\n *\r\n * // Realtime:\r\n * const unsub = orders.onSnapshot({ where: [{ field: 'status', op: '==', value: 'open' }] }, snap => {\r\n * renderOrders(snap.docs);\r\n * });\r\n * ```\r\n */\r\nexport async function createOfflineDocumentsNamespace(\r\n opts: CreateOfflineDocumentsOptions,\r\n): Promise<NeetruDbDocuments> {\r\n // bug_ba287a — fallback para MemoryStore quando IndexedDB não está disponível\r\n // (Node.js, Bun, Edge Workers sem IDB). Sem necessidade de flag explícita:\r\n // a detecção é automática via presença de `indexedDB` e `window` no runtime.\r\n //\r\n // MemoryStore implementa exatamente o mesmo contrato público de LocalStore —\r\n // o cast é seguro e evita modificar os tipos de SyncEngine/MutationQueue.\r\n const store = (\r\n isIndexedDBUnavailable()\r\n ? new MemoryStore()\r\n : new LocalStore(opts.dbName)\r\n ) as unknown as LocalStore;\r\n await store.open();\r\n\r\n const queue = new MutationQueue(store);\r\n const resolver = new ConflictResolver();\r\n const bus = new ChangeBus();\r\n\r\n const connectivity = new ConnectivityMonitor({\r\n // Se startOnline=false, injeta um navigator falso\r\n navigator: opts.startOnline === false\r\n ? { onLine: false }\r\n : (typeof navigator !== 'undefined' ? navigator : undefined),\r\n });\r\n\r\n // TabCoordinator — singleTab = sem eleição (sempre líder)\r\n const tabCoordinatorLike = opts.singleTab\r\n ? // Fake tab coordinator para single-tab mode (sempre líder)\r\n {\r\n isLeader: () => true,\r\n onRoleChange: (_cb: (role: 'leader' | 'follower') => void): Unsubscribe => {\r\n return () => {};\r\n },\r\n }\r\n : new TabCoordinator({\r\n lockName: `neetru-offline:${opts.dbName}`,\r\n channelName: `neetru-offline:${opts.dbName}`,\r\n });\r\n\r\n const engine = new SyncEngine({\r\n store,\r\n queue,\r\n resolver,\r\n bus,\r\n transport: opts.transport,\r\n tabCoordinator: tabCoordinatorLike,\r\n connectivity,\r\n periodicSyncIntervalMs: opts.periodicSyncIntervalMs ?? 5 * 60 * 1000,\r\n });\r\n\r\n return new NeetruDbDocumentsImpl({\r\n store,\r\n queue,\r\n bus,\r\n engine,\r\n connectivity,\r\n });\r\n}\r\n","/**\r\n * NeetruRealtimeClient — cliente WebSocket multiplexado do gateway (M3).\r\n *\r\n * Componente #18 do relatório central do Conselho Neetru Core DB.\r\n * Par cliente do serviço `neetru-realtime` (componente #19,\r\n * `@neetru/realtime-transport`).\r\n *\r\n * Responsabilidades:\r\n * - Manter EXATAMENTE UMA conexão WebSocket ao gateway.\r\n * - Multiplexar N subscriptions independentes sobre ela.\r\n * - Reconectar com backoff exponencial + jitter em caso de queda.\r\n * - Em reconexão, reenviar todos os frames `subscribe` ativos.\r\n * - Responder / enviar heartbeat ping/pong por protocolo.\r\n * - Rotear frames inbound para o callback correto por `subscriptionId`.\r\n * - Emitir mudanças de `ConnectionState` para observadores externos.\r\n *\r\n * Protocolo de frames (contrato inlined em `./types.ts` — MASTER-CRIT-038):\r\n * ENVIA → `subscribe` | `unsubscribe` | `ping`\r\n * RECEBE ← `delta` | `resync` | `stale` | `error` | `pong` | `drain`\r\n *\r\n * Deps: ZERO externas. Apenas WebSocket nativo (injetável).\r\n *\r\n * Nota: a integração de `NeetruRealtimeClient` na superfície pública\r\n * `client.db` é um follow-up deliberado — ver seção de pendências no\r\n * relatório de entrega.\r\n */\r\n\r\nimport type {\r\n RealtimeClientOptions,\r\n WebSocketLike,\r\n WebSocketFactory,\r\n OutboundFrame,\r\n InboundFrame,\r\n ConnectionState,\r\n ConnectionStateListener,\r\n SubscriptionCallback,\r\n SubscriptionEntry,\r\n RealtimeQuery,\r\n TicketProvider,\r\n RealtimeTicket,\r\n} from './types';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constantes\r\n// ---------------------------------------------------------------------------\r\n\r\n/** readyState WebSocket conforme especificação WHATWG. */\r\nconst WS_OPEN = 1;\r\n// const WS_CLOSING = 2; // não usado diretamente\r\nconst WS_CLOSED = 3;\r\n\r\n/** Fator multiplicador do jitter. O delay efetivo = base * jitter, onde\r\n * jitter ∈ [0.5, 1.5] (±50%). */\r\nconst JITTER_MIN = 0.5;\r\nconst JITTER_MAX = 1.5;\r\n\r\n/** Defaults */\r\nconst DEFAULT_BACKOFF_BASE_MS = 1_000;\r\nconst DEFAULT_BACKOFF_MAX_MS = 30_000;\r\nconst DEFAULT_HEARTBEAT_INTERVAL_MS = 25_000;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Geração de IDs\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Gera um ID de subscription único por instância.\r\n * Usa `crypto.randomUUID()` quando disponível (browser/Node 20+);\r\n * fallback para contador + Math.random() em ambientes sem crypto.\r\n */\r\nlet _idCounter = 0;\r\nfunction generateId(): string {\r\n if (typeof globalThis.crypto?.randomUUID === 'function') {\r\n return globalThis.crypto.randomUUID();\r\n }\r\n return `nrt-sub-${Date.now()}-${++_idCounter}-${Math.random().toString(36).slice(2)}`;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// NeetruRealtimeClient\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Cliente WebSocket multiplexado do gateway `neetru-realtime`.\r\n *\r\n * @example\r\n * ```ts\r\n * const rt = new NeetruRealtimeClient({\r\n * gatewayUrl: 'wss://realtime.neetru.com/ws',\r\n * });\r\n *\r\n * const subId = rt.subscribe('orders', { filter: { status: 'open' } }, (frame) => {\r\n * if (frame.op === 'delta') applyChanges(frame.changes);\r\n * if (frame.op === 'resync') fullReload();\r\n * });\r\n *\r\n * rt.onConnectionState((state) => console.log('connection:', state));\r\n *\r\n * // Para parar:\r\n * rt.unsubscribe(subId);\r\n * rt.close();\r\n * ```\r\n */\r\nexport class NeetruRealtimeClient {\r\n // ── configuração ──────────────────────────────────────────────────────────\r\n private readonly _gatewayUrl: string;\r\n private readonly _wsFactory: WebSocketFactory;\r\n private readonly _setTimeout: typeof setTimeout;\r\n private readonly _clearTimeout: typeof clearTimeout;\r\n private readonly _backoffBaseMs: number;\r\n private readonly _backoffMaxMs: number;\r\n private readonly _heartbeatIntervalMs: number;\r\n private readonly _ticketProvider: TicketProvider;\r\n /** ID do banco lógico (BL-8) — embutido em query.filter._dbId de cada subscribe. */\r\n private readonly _dbId: string | undefined;\r\n\r\n /** Ticket atual — obtido antes de cada abertura de WS e embutido nos frames. */\r\n private _currentTicket: RealtimeTicket | null = null;\r\n\r\n // ── estado interno ────────────────────────────────────────────────────────\r\n\r\n /** Subscriptions ativas: id → entry */\r\n private _subscriptions = new Map<string, SubscriptionEntry>();\r\n\r\n /** Listeners do estado da conexão. */\r\n private _stateListeners: Array<ConnectionStateListener> = [];\r\n\r\n /** Estado atual da conexão. */\r\n private _connectionState: ConnectionState = 'connecting';\r\n\r\n /** Socket atual (pode ser null entre tentativas). */\r\n private _ws: WebSocketLike | null = null;\r\n\r\n /** Número da tentativa de reconexão corrente (reseta após conexão bem-sucedida). */\r\n private _reconnectAttempt = 0;\r\n\r\n /** Handle do timer de backoff pendente. */\r\n private _reconnectTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n /** Handle do timer de heartbeat. */\r\n private _heartbeatTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n /** Indica que o cliente foi encerrado via `close()`. Não reconecta mais. */\r\n private _closed = false;\r\n\r\n /**\r\n * Frames de subscribe que precisam ser enviados mas a socket ainda não\r\n * está aberta (estado CONNECTING). Drenados no onopen.\r\n */\r\n private _pendingFrames: OutboundFrame[] = [];\r\n\r\n // ── construtor ────────────────────────────────────────────────────────────\r\n\r\n constructor(options: RealtimeClientOptions) {\r\n this._gatewayUrl = options.gatewayUrl;\r\n\r\n this._wsFactory = options.webSocketFactory ?? defaultWebSocketFactory;\r\n\r\n this._setTimeout = options.setTimeoutFn ?? globalThis.setTimeout.bind(globalThis);\r\n this._clearTimeout = options.clearTimeoutFn ?? globalThis.clearTimeout.bind(globalThis);\r\n\r\n this._backoffBaseMs = options.backoffBaseMs ?? DEFAULT_BACKOFF_BASE_MS;\r\n this._backoffMaxMs = options.backoffMaxMs ?? DEFAULT_BACKOFF_MAX_MS;\r\n this._heartbeatIntervalMs =\r\n options.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;\r\n\r\n this._ticketProvider = options.ticketProvider;\r\n this._dbId = options.dbId;\r\n\r\n // Inicia a conexão imediatamente (busca ticket antes de abrir o WS).\r\n this._connect();\r\n }\r\n\r\n // ── API pública ───────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Registra uma subscription em `collection` com `query` opcional.\r\n *\r\n * Envia um frame `subscribe` ao gateway (ou enfileira se o socket ainda\r\n * não está aberto). O `callback` é invocado com cada frame `delta`,\r\n * `resync`, `stale` ou `error` roteado para esta subscription.\r\n *\r\n * @returns O `subscriptionId` opaco — usar para cancelar via `unsubscribe()`.\r\n */\r\n subscribe(\r\n collection: string,\r\n query: RealtimeQuery,\r\n callback: SubscriptionCallback,\r\n ): string {\r\n if (this._closed) {\r\n // Cliente encerrado — retorna um id fictício sem efeito.\r\n return generateId();\r\n }\r\n\r\n const subscriptionId = generateId();\r\n this._subscriptions.set(subscriptionId, {\r\n subscriptionId,\r\n collection,\r\n query: Object.keys(query).length > 0 ? query : undefined,\r\n callback,\r\n });\r\n\r\n const frame: OutboundFrame = {\r\n op: 'subscribe',\r\n subscriptionId,\r\n collection,\r\n query: this._buildSubscribeQuery(query),\r\n };\r\n\r\n this._sendOrBuffer(frame);\r\n return subscriptionId;\r\n }\r\n\r\n /**\r\n * Cancela uma subscription.\r\n *\r\n * Envia um frame `unsubscribe` ao gateway e remove o listener local.\r\n * Frames subsequentes com este `subscriptionId` são silenciosamente descartados.\r\n */\r\n unsubscribe(subscriptionId: string): void {\r\n if (!this._subscriptions.has(subscriptionId)) {\r\n // id desconhecido — sem efeito (não lança erro).\r\n return;\r\n }\r\n\r\n this._subscriptions.delete(subscriptionId);\r\n\r\n const frame: OutboundFrame = { op: 'unsubscribe', subscriptionId };\r\n this._sendOrBuffer(frame);\r\n }\r\n\r\n /**\r\n * Registra um listener de mudanças no estado da conexão.\r\n *\r\n * O listener é invocado imediatamente com o estado atual e depois a cada\r\n * transição. Retorna uma função `unsubscribe`.\r\n */\r\n onConnectionState(listener: ConnectionStateListener): () => void {\r\n this._stateListeners.push(listener);\r\n // entrega o estado atual imediatamente\r\n listener(this._connectionState);\r\n return () => {\r\n this._stateListeners = this._stateListeners.filter(l => l !== listener);\r\n };\r\n }\r\n\r\n /**\r\n * Encerra o cliente definitivamente.\r\n *\r\n * Fecha o socket ativo, cancela timers pendentes e marca o cliente como\r\n * encerrado (sem mais reconexões).\r\n */\r\n close(): void {\r\n this._closed = true;\r\n this._cancelReconnectTimer();\r\n this._cancelHeartbeatTimer();\r\n if (this._ws) {\r\n // desvincula handlers para não disparar onclose→reconnect\r\n this._detachHandlers(this._ws);\r\n if (this._ws.readyState !== WS_CLOSED) {\r\n this._ws.close(1000, 'client closed');\r\n }\r\n this._ws = null;\r\n }\r\n this._setState('disconnected');\r\n }\r\n\r\n // ── Conexão ───────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Busca um ticket de autenticação e, em seguida, cria um novo WebSocket e\r\n * instala os handlers de evento.\r\n *\r\n * A busca de ticket é obrigatória antes de abrir qualquer WS (primeira\r\n * conexão e reconexões). Se a busca falhar, a conexão é abortada com\r\n * estado `'connecting'` e o backoff reconectará em seguida.\r\n *\r\n * Fail-closed: o WebSocket NUNCA é aberto sem um ticket válido.\r\n */\r\n private _connect(): void {\r\n if (this._closed) return;\r\n this._setState('connecting');\r\n\r\n // Fire-and-forget: a promise é gerenciada internamente.\r\n void this._connectWithTicket();\r\n }\r\n\r\n /** Implementação assíncrona de _connect — busca ticket e abre WS. */\r\n private async _connectWithTicket(): Promise<void> {\r\n if (this._closed) return;\r\n\r\n // ── 1. Busca o ticket ────────────────────────────────────────────────────\r\n let ticket: RealtimeTicket;\r\n try {\r\n ticket = await this._ticketProvider();\r\n } catch (err) {\r\n // Ticket fetch falhou — permanece em 'connecting' e agenda reconexão.\r\n // O WS não é aberto (fail-closed).\r\n if (this._closed) return;\r\n const delay = this._computeBackoffDelay(this._reconnectAttempt);\r\n this._reconnectAttempt++;\r\n this._reconnectTimer = this._setTimeout(() => {\r\n this._reconnectTimer = null;\r\n if (!this._closed) this._connect();\r\n }, delay);\r\n // Permanece em 'connecting' — não altera estado (já está lá).\r\n void err; // silencia \"unused variable\" lint\r\n return;\r\n }\r\n\r\n if (this._closed) return;\r\n\r\n // ── 2. Armazena o ticket para embedding nos frames subscribe ─────────────\r\n this._currentTicket = ticket;\r\n\r\n // ── 3. Abre o WebSocket ──────────────────────────────────────────────────\r\n const ws = this._wsFactory(this._gatewayUrl);\r\n this._ws = ws;\r\n\r\n ws.onopen = this._handleOpen.bind(this);\r\n ws.onmessage = this._handleMessage.bind(this);\r\n ws.onclose = this._handleClose.bind(this);\r\n ws.onerror = this._handleError.bind(this);\r\n }\r\n\r\n // ── Handlers de WebSocket ─────────────────────────────────────────────────\r\n\r\n private _handleOpen(_event: Event): void {\r\n if (this._closed) return;\r\n\r\n this._reconnectAttempt = 0; // reconexão bem-sucedida — reseta counter\r\n this._setState('connected');\r\n\r\n // Drena frames que foram enfileirados enquanto o socket estava CONNECTING.\r\n for (const frame of this._pendingFrames) {\r\n this._sendNow(frame);\r\n }\r\n this._pendingFrames = [];\r\n\r\n // Resubscreve todas as subscriptions ativas (relevante em reconexões\r\n // onde _pendingFrames estava vazio mas as subs já existiam).\r\n // No open inicial, _subscriptions está vazio ou populado (se subscribe\r\n // foi chamado antes do open). Os frames foram para _pendingFrames.\r\n // Em reconexão: _pendingFrames foi drenado acima — mas as subscriptions\r\n // ativas precisam ser re-registradas no NOVO socket.\r\n // Porém, os frames que foram para _pendingFrames já incluem os subscribes\r\n // iniciais. Precisamos distinguir: reconexão vs. primeira conexão.\r\n // Para simplificar e ser correto nos dois casos, resubscreve SEMPRE\r\n // subscriptions que não estavam no _pendingFrames que acabamos de drenar.\r\n this._resubscribeAll();\r\n\r\n // Inicia heartbeat se habilitado.\r\n this._scheduleHeartbeat();\r\n }\r\n\r\n private _handleMessage(event: MessageEvent): void {\r\n if (this._closed) return;\r\n\r\n let frame: InboundFrame;\r\n try {\r\n frame = JSON.parse(event.data as string) as InboundFrame;\r\n } catch {\r\n // frame malformado — ignora\r\n return;\r\n }\r\n\r\n switch (frame.op) {\r\n case 'delta':\r\n case 'resync':\r\n case 'stale':\r\n case 'error':\r\n this._routeToSubscription(frame);\r\n break;\r\n\r\n case 'pong':\r\n // heartbeat respondido — nada a fazer (timer já foi limpo)\r\n break;\r\n\r\n case 'drain':\r\n this._handleDrain();\r\n break;\r\n\r\n default:\r\n // op desconhecido — ignora silenciosamente\r\n break;\r\n }\r\n }\r\n\r\n private _handleClose(_event: CloseEvent): void {\r\n if (this._closed) return;\r\n\r\n this._cancelHeartbeatTimer();\r\n this._ws = null;\r\n this._scheduleReconnect();\r\n }\r\n\r\n private _handleError(_event: Event): void {\r\n // O error é sempre seguido de onclose — não precisamos fazer nada aqui;\r\n // o onclose cuidará da reconexão.\r\n // Marcamos connecting para sinalizar que algo deu errado enquanto aguardamos.\r\n if (this._closed) return;\r\n this._setState('connecting');\r\n }\r\n\r\n // ── Drain (graceful shutdown do gateway) ─────────────────────────────────\r\n\r\n private _handleDrain(): void {\r\n if (this._closed) return;\r\n\r\n this._setState('draining');\r\n this._cancelHeartbeatTimer();\r\n\r\n // Fecha o socket atual sem esperar o close natural do gateway.\r\n if (this._ws) {\r\n this._detachHandlers(this._ws);\r\n if (this._ws.readyState !== WS_CLOSED) {\r\n this._ws.close(1001, 'drain');\r\n }\r\n this._ws = null;\r\n }\r\n\r\n // Reconecta com backoff — o gateway vai subir em seguida.\r\n this._scheduleReconnect();\r\n }\r\n\r\n // ── Roteamento de frames ──────────────────────────────────────────────────\r\n\r\n private _routeToSubscription(frame: InboundFrame): void {\r\n const entry = this._subscriptions.get(frame.subscriptionId);\r\n if (!entry) {\r\n // subscriptionId desconhecido — ignora silenciosamente\r\n return;\r\n }\r\n try {\r\n entry.callback(frame);\r\n } catch {\r\n // erro no callback do produto não deve derrubar o cliente\r\n }\r\n }\r\n\r\n // ── Resubscrição ──────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Reenvía frames `subscribe` para todas as subscriptions ativas.\r\n * Chamado no `onopen` de reconexões para restaurar o estado remoto.\r\n *\r\n * Durante a PRIMEIRA conexão: _pendingFrames já foi drenado com os\r\n * subscribes iniciais acima. ResubscribeAll envia novamente — como a\r\n * lista de subscriptions foi populada pelos `subscribe()` calls anteriores\r\n * ao open, e os frames drenados também os incluem, teríamos duplicatas.\r\n *\r\n * Solução: resubscribeAll só é invocado após drenar _pendingFrames, e\r\n * como o gateway é idempotente para o mesmo subscriptionId (segundo o\r\n * design do componente #19), a duplicata é inócua. Em reconexões, onde\r\n * _pendingFrames está vazio, os frames são os únicos enviados.\r\n *\r\n * Para o caso do primeiro open com subscribes anteriores ao open, os\r\n * frames já foram drenados de _pendingFrames — não chamamos resubscribeAll\r\n * se era a primeira conexão (_reconnectAttempt era 0 antes de resetar).\r\n * Rastreamos isso com _hasConnectedOnce.\r\n */\r\n private _hasConnectedOnce = false;\r\n\r\n private _resubscribeAll(): void {\r\n if (!this._hasConnectedOnce) {\r\n // Primeiro open: os subscribes foram drenados de _pendingFrames.\r\n // Não resubscreve para evitar duplicata.\r\n this._hasConnectedOnce = true;\r\n return;\r\n }\r\n\r\n // Reconexão: envia subscribe frames para todas as subs ativas.\r\n // O ticket corrente (obtido antes de abrir este WS) é embutido em\r\n // cada frame — assim o gateway pode validar a autenticidade.\r\n for (const entry of this._subscriptions.values()) {\r\n const frame: OutboundFrame = {\r\n op: 'subscribe',\r\n subscriptionId: entry.subscriptionId,\r\n collection: entry.collection,\r\n query: this._buildSubscribeQuery(entry.query ?? {}),\r\n };\r\n this._sendNow(frame);\r\n }\r\n }\r\n\r\n // ── Ticket embedding ──────────────────────────────────────────────────────\r\n\r\n /**\r\n * Constrói o descriptor `query` para um frame `subscribe`, embutindo o\r\n * `token` do ticket corrente em `query.filter._ticket` e o `_dbId` do\r\n * banco lógico em `query.filter._dbId` (BL-8 fix).\r\n *\r\n * O gateway extrai `filter._ticket` do primeiro frame `subscribe` e valida\r\n * contra `POST /api/sdk/v1/db/realtime/validate`. `filter._dbId` é exigido\r\n * pelo `@neetru/realtime-changestream._extractDbId` para rotear a\r\n * subscription ao banco correto — sem ele a subscription é rejeitada.\r\n *\r\n * Retorna `undefined` se a query seria vazia E não há ticket (estado\r\n * transitório antes do primeiro ticket — não deve ocorrer normalmente pois\r\n * `_connect` só abre o WS após obter o ticket).\r\n */\r\n private _buildSubscribeQuery(\r\n query: RealtimeQuery,\r\n ): RealtimeQuery | undefined {\r\n const ticket = this._currentTicket;\r\n const hasUserQuery = Object.keys(query).length > 0;\r\n\r\n if (!ticket) {\r\n // Sem ticket — retorna a query original sem embedding (defensivo;\r\n // na prática nunca chega aqui pois _connect não abre WS sem ticket).\r\n return hasUserQuery ? query : undefined;\r\n }\r\n\r\n // BL-8: mescla _ticket + _dbId no filter, preservando filtros do caller.\r\n const mergedFilter: Record<string, unknown> = {\r\n ...(query.filter ?? {}),\r\n _ticket: ticket.token,\r\n };\r\n\r\n // Embute _dbId apenas quando configurado (compatibilidade reversa).\r\n if (this._dbId !== undefined) {\r\n mergedFilter['_dbId'] = this._dbId;\r\n }\r\n\r\n return {\r\n ...query,\r\n filter: mergedFilter,\r\n };\r\n }\r\n\r\n // ── Backoff e reconexão ───────────────────────────────────────────────────\r\n\r\n /** Agenda uma tentativa de reconexão com backoff exponencial + jitter. */\r\n private _scheduleReconnect(): void {\r\n if (this._closed) return;\r\n\r\n this._cancelReconnectTimer();\r\n this._setState('connecting');\r\n\r\n // Invalida o ticket corrente — a reconexão deve buscar um novo.\r\n this._currentTicket = null;\r\n\r\n const delayMs = this._computeBackoffDelay(this._reconnectAttempt);\r\n this._reconnectAttempt++;\r\n\r\n this._reconnectTimer = this._setTimeout(() => {\r\n this._reconnectTimer = null;\r\n if (!this._closed) {\r\n this._connect();\r\n }\r\n }, delayMs);\r\n }\r\n\r\n /**\r\n * Calcula o delay de backoff para o attempt N.\r\n *\r\n * Fórmula: `min(baseMs * 2^N, maxMs) * jitter`\r\n * onde `jitter ∈ [JITTER_MIN, JITTER_MAX]` (±50%).\r\n */\r\n private _computeBackoffDelay(attempt: number): number {\r\n const exponential = this._backoffBaseMs * Math.pow(2, attempt);\r\n const capped = Math.min(exponential, this._backoffMaxMs);\r\n const jitter = JITTER_MIN + Math.random() * (JITTER_MAX - JITTER_MIN);\r\n return Math.round(capped * jitter);\r\n }\r\n\r\n private _cancelReconnectTimer(): void {\r\n if (this._reconnectTimer !== null) {\r\n this._clearTimeout(this._reconnectTimer);\r\n this._reconnectTimer = null;\r\n }\r\n }\r\n\r\n // ── Heartbeat ─────────────────────────────────────────────────────────────\r\n\r\n /** Agenda o próximo ping. Não-operacional se heartbeatIntervalMs === 0. */\r\n private _scheduleHeartbeat(): void {\r\n if (this._heartbeatIntervalMs === 0) return;\r\n this._cancelHeartbeatTimer();\r\n\r\n this._heartbeatTimer = this._setTimeout(() => {\r\n this._heartbeatTimer = null;\r\n this._sendPing();\r\n // agenda o próximo ciclo\r\n this._scheduleHeartbeat();\r\n }, this._heartbeatIntervalMs);\r\n }\r\n\r\n private _cancelHeartbeatTimer(): void {\r\n if (this._heartbeatTimer !== null) {\r\n this._clearTimeout(this._heartbeatTimer);\r\n this._heartbeatTimer = null;\r\n }\r\n }\r\n\r\n private _sendPing(): void {\r\n // O ping usa um subscriptionId especial vazio ('') para o heartbeat\r\n // de aplicação (distinto do ping/pong do protocolo WebSocket).\r\n const frame: OutboundFrame = { op: 'ping', subscriptionId: '' };\r\n this._sendOrBuffer(frame);\r\n }\r\n\r\n // ── Envio de frames ───────────────────────────────────────────────────────\r\n\r\n /**\r\n * Envia o frame imediatamente se o socket está aberto; caso contrário,\r\n * enfileira em `_pendingFrames` para envio no próximo `onopen`.\r\n */\r\n private _sendOrBuffer(frame: OutboundFrame): void {\r\n if (\r\n this._ws !== null &&\r\n this._ws.readyState === WS_OPEN\r\n ) {\r\n this._sendNow(frame);\r\n } else {\r\n // Socket ainda está CONNECTING ou foi perdido — enfileira.\r\n // Frames de unsubscribe não precisam ser bufferizados pois não há\r\n // estado remoto a limpar (o remote não tem a sub se o socket não abriu).\r\n if (frame.op !== 'unsubscribe') {\r\n this._pendingFrames.push(frame);\r\n }\r\n }\r\n }\r\n\r\n /** Serializa e envia o frame imediatamente via WebSocket. */\r\n private _sendNow(frame: OutboundFrame): void {\r\n if (!this._ws || this._ws.readyState !== WS_OPEN) return;\r\n try {\r\n this._ws.send(JSON.stringify(frame));\r\n } catch {\r\n // Falha de send (ex: buffer cheio) — ignora; o onclose cuidará da reconexão.\r\n }\r\n }\r\n\r\n // ── Estado da conexão ─────────────────────────────────────────────────────\r\n\r\n private _setState(state: ConnectionState): void {\r\n if (this._connectionState === state) return;\r\n this._connectionState = state;\r\n for (const listener of this._stateListeners) {\r\n try {\r\n listener(state);\r\n } catch {\r\n // erro no listener do produto não deve derrubar o cliente\r\n }\r\n }\r\n }\r\n\r\n // ── Desvinculação de handlers ─────────────────────────────────────────────\r\n\r\n /** Remove todos os handlers de um WebSocket (evita disparo após close()). */\r\n private _detachHandlers(ws: WebSocketLike): void {\r\n ws.onopen = null;\r\n ws.onmessage = null;\r\n ws.onclose = null;\r\n ws.onerror = null;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Factory de WebSocket padrão\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Factory padrão: cria um `WebSocket` nativo do browser/runtime.\r\n * Substituída por FakeWebSocket em testes.\r\n */\r\nconst defaultWebSocketFactory: WebSocketFactory = (url: string): WebSocketLike => {\r\n // `WebSocket` é global no browser e no Node 22+ (sem import).\r\n // Em ambientes sem WebSocket global, o produto deve injetar a factory.\r\n if (typeof WebSocket === 'undefined') {\r\n throw new Error(\r\n '[NeetruRealtimeClient] WebSocket não disponível neste ambiente. ' +\r\n 'Injete uma implementação via `webSocketFactory` nas opções.',\r\n );\r\n }\r\n return new WebSocket(url);\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Re-exports de tipos para conveniência do consumidor\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type {\r\n RealtimeClientOptions,\r\n RealtimeQuery,\r\n RealtimeTicket,\r\n TicketProvider,\r\n ConnectionState,\r\n ConnectionStateListener,\r\n SubscriptionCallback,\r\n InboundFrame,\r\n OutboundFrame,\r\n} from './types';\r\n","/**\r\n * Checkout namespace (v1.1) — `client.checkout.*`\r\n *\r\n * Fluxo canônico (vide `docs/FLUXO_SIGNUP_BILLING_CHECKOUT.md` §6):\r\n * 1. SaaS produto chama `client.checkout.start({productId, planId, callbackUrl})`.\r\n * 2. SDK posta em `POST /api/v1/checkout/intents` (Bearer access_token OIDC).\r\n * 3. Core cria `checkout_intents/{intentId}` (TTL 15min) + retorna `redirectUrl`.\r\n * 4. Em browser, SDK redireciona automaticamente pra `redirectUrl`. Em\r\n * Node/SSR, retorna o objeto `{intentId, redirectUrl}` sem redirect.\r\n * 5. Portal (`minhaconta.neetru.com/portal/kyc/{intentId}`) coleta KYC + cartão.\r\n * 6. Usuário volta pra `callbackUrl?status=success&intentId=...` quando completo.\r\n *\r\n * **Dev mode** (`NEETRU_ENV=dev`): `start()` retorna URL fake sem network call.\r\n * Útil pra dev externo SaaS testar UI sem provisionar conta Neetru.\r\n *\r\n * **Estabilidade**: minor bump v1.0 → v1.1 (feature add, sem breaking).\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n// ─── Types públicos ─────────────────────────────────────────────────────────\r\n\r\n/** Tipo do tenant alvo da subscription (PF=uid, PJ=orgId). */\r\nexport type CheckoutTenantType = 'pf' | 'pj';\r\n\r\n/** Status do `checkout_intents/{intentId}` no Core. */\r\nexport type CheckoutIntentStatus =\r\n | 'pending'\r\n | 'kyc_in_progress'\r\n | 'stripe_redirected'\r\n | 'completed'\r\n | 'expired'\r\n | 'cancelled';\r\n\r\nexport interface CheckoutStartInput {\r\n /** Slug do produto no catálogo (ex: `neetru-pulse`). */\r\n productId: string;\r\n /** Slug do plano no catálogo do produto (ex: `pro_monthly`). */\r\n planId: string;\r\n /** Pra onde o produto SaaS quer voltar pós-checkout. https obrigatório (ou http://localhost em dev). */\r\n callbackUrl: string;\r\n /** Override pra checkout em nome de uma org. Default: PF do uid logado. */\r\n tenantType?: CheckoutTenantType;\r\n /** Quando `tenantType='pj'`, id da org. Ignorado quando PF. */\r\n tenantId?: string;\r\n /**\r\n * Em browsers, default `true` — SDK faz `window.location.href = redirectUrl`.\r\n * Passe `false` se quiser controlar o redirect manualmente.\r\n */\r\n autoRedirect?: boolean;\r\n /**\r\n * **C2 (auditoria 2026-06-10):** access_token OIDC do **usuário final** que\r\n * está assinando. OBRIGATÓRIO no modo HTTP real — o endpoint de checkout do\r\n * Core (`/api/v1/checkout/intents`) autentica a identidade do cliente (Bearer\r\n * access_token OIDC ou cookie de sessão), NÃO a chave de API do SDK (`nrt_*`).\r\n * Enviar a chave `nrt_*` resultava em 401 sempre. O SDK é BFF-pattern: o app\r\n * consumidor gerencia o ciclo OIDC e passa o access_token aqui.\r\n */\r\n accessToken?: string;\r\n}\r\n\r\n/** Auth por chamada do checkout — access_token OIDC do usuário final. */\r\nexport interface CheckoutAuthOpts {\r\n /** access_token OIDC do usuário final (vide CheckoutStartInput.accessToken). */\r\n accessToken?: string;\r\n}\r\n\r\nexport interface CheckoutStartResult {\r\n intentId: string;\r\n redirectUrl: string;\r\n status: CheckoutIntentStatus;\r\n expiresAt: string;\r\n /** True se KYC ainda precisa ser coletado no portal. UI pode mostrar hint. */\r\n requiresKyc: boolean;\r\n}\r\n\r\nexport interface CheckoutIntentInfo {\r\n intentId: string;\r\n uid: string;\r\n targetTenantId: string;\r\n targetTenantType: CheckoutTenantType;\r\n productId: string;\r\n planId: string;\r\n callbackUrl: string;\r\n status: CheckoutIntentStatus;\r\n /** Stripe Checkout Session id quando avançou pra `stripe_redirected`. */\r\n stripeSessionId?: string | null;\r\n expiresAt: string;\r\n /** True se já passou `expiresAt` mas Core ainda não marcou expired. */\r\n isStale?: boolean;\r\n}\r\n\r\nexport interface CheckoutNamespace {\r\n /**\r\n * Inicia checkout. Em browser, redireciona automaticamente pro portal.\r\n * Em Node/SSR, retorna o resultado sem efeitos colaterais — caller decide\r\n * o que fazer com `redirectUrl`.\r\n *\r\n * Dev mode (`NEETRU_ENV=dev`): retorna URL fake `https://localhost:9003/portal/checkout/mock-XXXX`.\r\n */\r\n start(input: CheckoutStartInput): Promise<CheckoutStartResult>;\r\n /** Lê estado atual do intent (Core). Requer `opts.accessToken` no HTTP real. */\r\n get(intentId: string, opts?: CheckoutAuthOpts): Promise<CheckoutIntentInfo>;\r\n /** Cancela um intent que ainda não virou `stripe_redirected`. Requer `opts.accessToken` no HTTP real. */\r\n cancel(intentId: string, opts?: CheckoutAuthOpts): Promise<{ ok: true; alreadyCancelled: boolean }>;\r\n}\r\n\r\n/**\r\n * C2: monta a auth do checkout a partir do access_token OIDC do usuário final.\r\n * Fail-closed: sem token, lança erro claro em vez de mandar a chave `nrt_*`\r\n * (que o endpoint rejeita com 401). Retorna requireAuth:false + header Bearer\r\n * manual — httpRequest preserva `headers.authorization` quando requireAuth=false.\r\n */\r\nfunction checkoutAuth(\r\n accessToken: string | undefined,\r\n method: string,\r\n): { requireAuth: false; headers: Record<string, string> } {\r\n if (!accessToken || typeof accessToken !== 'string') {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n `checkout.${method} requer o access_token OIDC do usuário final (passe \\`accessToken\\`). ` +\r\n `A chave de API do SDK (nrt_*) NÃO é aceita pelo endpoint de checkout — ele autentica a ` +\r\n `identidade do cliente que está assinando (Bearer access_token OIDC ou cookie de sessão).`,\r\n );\r\n }\r\n return { requireAuth: false, headers: { authorization: `Bearer ${accessToken}` } };\r\n}\r\n\r\n// ─── Implementação real (HTTP) ─────────────────────────────────────────────\r\n\r\ninterface RawStartCheckoutResponse {\r\n ok?: boolean;\r\n intentId?: string;\r\n redirectUrl?: string;\r\n status?: string;\r\n expiresAt?: string;\r\n requiresKyc?: boolean;\r\n}\r\n\r\ninterface RawGetCheckoutResponse {\r\n ok?: boolean;\r\n intent?: {\r\n intentId?: string;\r\n uid?: string;\r\n targetTenantId?: string;\r\n targetTenantType?: string;\r\n productId?: string;\r\n planId?: string;\r\n callbackUrl?: string;\r\n status?: string;\r\n stripeSessionId?: string | null;\r\n expiresAt?: string;\r\n };\r\n isStale?: boolean;\r\n}\r\n\r\nfunction parseStartResponse(raw: unknown): CheckoutStartResult {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'checkout.start response is not an object');\r\n }\r\n const r = raw as RawStartCheckoutResponse;\r\n if (typeof r.intentId !== 'string' || !r.intentId) {\r\n throw new NeetruError('invalid_response', 'checkout.start response missing intentId');\r\n }\r\n if (typeof r.redirectUrl !== 'string' || !r.redirectUrl) {\r\n throw new NeetruError('invalid_response', 'checkout.start response missing redirectUrl');\r\n }\r\n return {\r\n intentId: r.intentId,\r\n redirectUrl: r.redirectUrl,\r\n status: (r.status as CheckoutIntentStatus | undefined) ?? 'pending',\r\n expiresAt: typeof r.expiresAt === 'string' ? r.expiresAt : new Date().toISOString(),\r\n requiresKyc: r.requiresKyc === true,\r\n };\r\n}\r\n\r\nfunction parseGetResponse(raw: unknown): CheckoutIntentInfo {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'checkout.get response is not an object');\r\n }\r\n const r = raw as RawGetCheckoutResponse;\r\n const intent = r.intent;\r\n if (!intent || typeof intent !== 'object') {\r\n throw new NeetruError('invalid_response', 'checkout.get response missing intent');\r\n }\r\n if (typeof intent.intentId !== 'string') {\r\n throw new NeetruError('invalid_response', 'checkout.get response missing intentId');\r\n }\r\n return {\r\n intentId: intent.intentId,\r\n uid: intent.uid ?? '',\r\n targetTenantId: intent.targetTenantId ?? '',\r\n targetTenantType: (intent.targetTenantType as CheckoutTenantType | undefined) ?? 'pf',\r\n productId: intent.productId ?? '',\r\n planId: intent.planId ?? '',\r\n callbackUrl: intent.callbackUrl ?? '',\r\n status: (intent.status as CheckoutIntentStatus | undefined) ?? 'pending',\r\n stripeSessionId: intent.stripeSessionId ?? null,\r\n expiresAt: intent.expiresAt ?? new Date().toISOString(),\r\n isStale: r.isStale === true,\r\n };\r\n}\r\n\r\n/**\r\n * Detecta se estamos em browser context. Em SSR / Node / Edge, `window`\r\n * pode não existir — fazemos check defensivo.\r\n */\r\nfunction inBrowser(): boolean {\r\n try {\r\n return (\r\n typeof globalThis !== 'undefined' &&\r\n typeof (globalThis as { window?: { location?: { href?: string } } }).window !== 'undefined' &&\r\n typeof globalThis.location !== 'undefined' &&\r\n typeof globalThis.location.assign === 'function'\r\n );\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nfunction performRedirect(url: string): void {\r\n try {\r\n globalThis.location.assign(url);\r\n } catch {\r\n /* noop em runtimes sem location.assign — caller decide */\r\n }\r\n}\r\n\r\n/**\r\n * Implementação HTTP real. Posta no Core, parse response, redireciona se browser.\r\n */\r\nfunction createHttpCheckoutNamespace(config: ResolvedConfig): CheckoutNamespace {\r\n return {\r\n async start(input: CheckoutStartInput): Promise<CheckoutStartResult> {\r\n if (!input?.productId) {\r\n throw new NeetruError('validation_failed', 'checkout.start: productId is required');\r\n }\r\n if (!input?.planId) {\r\n throw new NeetruError('validation_failed', 'checkout.start: planId is required');\r\n }\r\n if (!input?.callbackUrl) {\r\n throw new NeetruError('validation_failed', 'checkout.start: callbackUrl is required');\r\n }\r\n\r\n const body: Record<string, unknown> = {\r\n productId: input.productId,\r\n planId: input.planId,\r\n callbackUrl: input.callbackUrl,\r\n };\r\n if (input.tenantType) body.targetTenantType = input.tenantType;\r\n if (input.tenantId) body.targetTenantId = input.tenantId;\r\n\r\n // bug: sem idempotencyKey → retry criava intents duplicados (fix: alinhar com usage.report/support.createTicket)\r\n const { requireAuth, headers } = checkoutAuth(input.accessToken, 'start');\r\n const raw = await httpRequest<RawStartCheckoutResponse>(config, {\r\n method: 'POST',\r\n path: '/api/v1/checkout/intents',\r\n body,\r\n requireAuth,\r\n headers,\r\n idempotencyKey: true,\r\n });\r\n const result = parseStartResponse(raw);\r\n\r\n const shouldRedirect = input.autoRedirect !== false;\r\n if (shouldRedirect && inBrowser()) {\r\n performRedirect(result.redirectUrl);\r\n }\r\n return result;\r\n },\r\n\r\n async get(intentId: string, opts?: CheckoutAuthOpts): Promise<CheckoutIntentInfo> {\r\n if (!intentId || typeof intentId !== 'string') {\r\n throw new NeetruError('validation_failed', 'checkout.get: intentId is required');\r\n }\r\n const { requireAuth, headers } = checkoutAuth(opts?.accessToken, 'get');\r\n const raw = await httpRequest<RawGetCheckoutResponse>(config, {\r\n method: 'GET',\r\n path: `/api/v1/checkout/intents/${encodeURIComponent(intentId)}`,\r\n requireAuth,\r\n headers,\r\n });\r\n return parseGetResponse(raw);\r\n },\r\n\r\n async cancel(intentId: string, opts?: CheckoutAuthOpts): Promise<{ ok: true; alreadyCancelled: boolean }> {\r\n if (!intentId || typeof intentId !== 'string') {\r\n throw new NeetruError('validation_failed', 'checkout.cancel: intentId is required');\r\n }\r\n const { requireAuth, headers } = checkoutAuth(opts?.accessToken, 'cancel');\r\n const raw = await httpRequest<{ ok?: boolean; alreadyCancelled?: boolean }>(config, {\r\n method: 'DELETE',\r\n path: `/api/v1/checkout/intents/${encodeURIComponent(intentId)}`,\r\n requireAuth,\r\n headers,\r\n });\r\n return {\r\n ok: true,\r\n alreadyCancelled: (raw as { alreadyCancelled?: boolean })?.alreadyCancelled === true,\r\n };\r\n },\r\n };\r\n}\r\n\r\n// ─── Mock dev (sem network) ─────────────────────────────────────────────────\r\n\r\n/**\r\n * Mock dev — retorna URL fake `https://localhost:9003/portal/checkout/mock-XXXX`\r\n * sem tocar no Core. Útil pra dev externo SaaS testar UI/redirect sem precisar\r\n * de Bearer token Neetru.\r\n *\r\n * Dev mode persiste intents em mapa in-memory pro `get`/`cancel` retornarem\r\n * resultado consistente.\r\n */\r\nexport class MockCheckout implements CheckoutNamespace {\r\n private readonly intents = new Map<string, CheckoutIntentInfo>();\r\n\r\n async start(input: CheckoutStartInput): Promise<CheckoutStartResult> {\r\n if (!input?.productId) {\r\n throw new NeetruError('validation_failed', 'checkout.start: productId is required');\r\n }\r\n if (!input?.planId) {\r\n throw new NeetruError('validation_failed', 'checkout.start: planId is required');\r\n }\r\n if (!input?.callbackUrl) {\r\n throw new NeetruError('validation_failed', 'checkout.start: callbackUrl is required');\r\n }\r\n\r\n const intentId = `chk_mock_${Math.random().toString(36).slice(2, 10)}`;\r\n const expiresAt = new Date(Date.now() + 15 * 60 * 1000).toISOString();\r\n const redirectUrl = `https://localhost:9003/portal/checkout/${intentId}`;\r\n\r\n this.intents.set(intentId, {\r\n intentId,\r\n uid: 'dev-fixture-uid',\r\n targetTenantId: input.tenantId ?? 'dev-fixture-uid',\r\n targetTenantType: input.tenantType ?? 'pf',\r\n productId: input.productId,\r\n planId: input.planId,\r\n callbackUrl: input.callbackUrl,\r\n status: 'pending',\r\n stripeSessionId: null,\r\n expiresAt,\r\n });\r\n\r\n return {\r\n intentId,\r\n redirectUrl,\r\n status: 'pending',\r\n expiresAt,\r\n requiresKyc: false,\r\n };\r\n }\r\n\r\n async get(intentId: string, _opts?: CheckoutAuthOpts): Promise<CheckoutIntentInfo> {\r\n const found = this.intents.get(intentId);\r\n if (!found) {\r\n throw new NeetruError('not_found', `Mock intent ${intentId} not found`);\r\n }\r\n return { ...found };\r\n }\r\n\r\n async cancel(intentId: string, _opts?: CheckoutAuthOpts): Promise<{ ok: true; alreadyCancelled: boolean }> {\r\n const found = this.intents.get(intentId);\r\n if (!found) {\r\n throw new NeetruError('not_found', `Mock intent ${intentId} not found`);\r\n }\r\n const alreadyCancelled = found.status === 'cancelled';\r\n this.intents.set(intentId, { ...found, status: 'cancelled' });\r\n return { ok: true, alreadyCancelled };\r\n }\r\n}\r\n\r\n// ─── Factory ────────────────────────────────────────────────────────────────\r\n\r\nexport function createCheckoutNamespace(config: ResolvedConfig): CheckoutNamespace {\r\n if (config.env === 'dev') return new MockCheckout();\r\n return createHttpCheckoutNamespace(config);\r\n}\r\n","/**\r\n * Webhooks namespace (v1.2) — produtos SaaS registram endpoints HTTP no Core\r\n * pra receber notificações de eventos.\r\n *\r\n * Casos típicos:\r\n * - `subscription.activated` quando cliente conclui checkout\r\n * - `subscription.cancelled` / `subscription.payment_failed`\r\n * - `usage.quota_exceeded` quando produto bate teto mensal\r\n * - `account.suspended` quando staff Neetru suspende uma conta\r\n *\r\n * Pull-vs-push: o SDK existente é pull-only (`getQuota`, etc). Webhooks\r\n * fecham o gap pra eventos assíncronos sem o produto precisar fazer polling.\r\n *\r\n * Segurança:\r\n * - Endpoint do produto recebe HMAC SHA-256 em header `X-Neetru-Signature`\r\n * usando `secret` opcional do registro. Sem `secret`, header ausente —\r\n * produto deve usar HTTPS + IP allowlist.\r\n * - Replay protection: header `X-Neetru-Timestamp` (ms) — produto deve\r\n * rejeitar > 5min de skew.\r\n * - Retry: Core retenta 3x com backoff exponencial (1s, 5s, 25s) se 5xx\r\n * ou timeout. Após 3 falhas → marca endpoint `degraded` por 1h.\r\n *\r\n * Endpoints REST (em prod):\r\n * - `POST /api/sdk/v1/webhooks` — registra novo endpoint\r\n * - `GET /api/sdk/v1/webhooks` — lista endpoints do produto\r\n * - `DELETE /api/sdk/v1/webhooks/{id}` — remove endpoint\r\n * - `POST /api/sdk/v1/webhooks/{id}/test` — dispara evento de teste\r\n *\r\n * Mock em `NEETRU_ENV=dev`: tudo in-memory, sem rede.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport { assertValidSdkId } from './validators';\r\nimport type { ResolvedConfig } from './types';\r\n\r\n/** Eventos Neetru que produtos podem assinar. Lista expansível por minor bump. */\r\nexport type WebhookEvent =\r\n | 'subscription.activated'\r\n | 'subscription.cancelled'\r\n | 'subscription.payment_failed'\r\n | 'subscription.trial_ending'\r\n | 'usage.quota_exceeded'\r\n | 'account.suspended'\r\n | 'account.reactivated'\r\n | 'support.ticket_replied';\r\n\r\nexport interface WebhookEndpoint {\r\n id: string;\r\n url: string;\r\n events: WebhookEvent[];\r\n /** Quando true, `X-Neetru-Signature` é enviado em cada dispatch. */\r\n hasSecret: boolean;\r\n status: 'active' | 'degraded' | 'disabled';\r\n /** ISO timestamp do último dispatch bem-sucedido. */\r\n lastDeliveryAt?: string;\r\n /** Quantos dispatches falharam consecutivos (resetado em sucesso). */\r\n consecutiveFailures?: number;\r\n createdAt: string;\r\n}\r\n\r\nexport interface RegisterWebhookInput {\r\n /**\r\n * **3.0 (breaking):** `productId` é obrigatório no body. Se ausente,\r\n * SDK tenta resolver do `config.productId` (default no `createNeetruClient`);\r\n * lança `validation_failed` se ambos faltarem.\r\n */\r\n productId?: string;\r\n url: string;\r\n events: WebhookEvent[];\r\n /**\r\n * Secret pra HMAC SHA-256 (mín 16 chars). Recomendado.\r\n * Quando ausente, dispatches vão sem assinatura — produto deve ter\r\n * IP allowlist ou outra defesa.\r\n */\r\n secret?: string;\r\n}\r\n\r\nexport interface WebhookTestResult {\r\n ok: boolean;\r\n statusCode?: number;\r\n durationMs?: number;\r\n error?: string;\r\n}\r\n\r\n/**\r\n * 3.0: opções de scoping — todos os verbos exigem `productId` (default do\r\n * `config.productId` se ausente).\r\n */\r\nexport interface WebhookScopeOptions {\r\n productId?: string;\r\n}\r\n\r\nexport interface WebhooksNamespace {\r\n /** Registra um novo endpoint. */\r\n register(input: RegisterWebhookInput): Promise<WebhookEndpoint>;\r\n /** Lista endpoints registrados pelo produto. */\r\n list(options?: WebhookScopeOptions): Promise<WebhookEndpoint[]>;\r\n /** Remove um endpoint. */\r\n unregister(id: string, options?: WebhookScopeOptions): Promise<{ ok: true }>;\r\n /** Dispara evento de teste pra validar conectividade. */\r\n test(id: string, options?: WebhookScopeOptions): Promise<WebhookTestResult>;\r\n}\r\n\r\n/**\r\n * Verifica assinatura HMAC SHA-256 de payload de webhook recebido pelo\r\n * produto consumer. **3.0**: Universal (browser/Node/Edge) via WebCrypto.subtle.\r\n *\r\n * Constant-time compare via byte-level XOR accumulator (não usa\r\n * `timingSafeEqual` do Node porque WebCrypto não tem equivalente direto).\r\n *\r\n * **3.1.3 (auditoria 2026-06-10)**: o Core assina HMAC sobre\r\n * `` `${timestamp}.${rawBody}` `` (vide `computeWebhookSignature` em\r\n * `functions/src/lib/webhook-delivery-core.ts`) — o `timestamp` é o valor do\r\n * header `X-Neetru-Timestamp`. Passe-o no 4º parâmetro; sem ele o HMAC é\r\n * computado só sobre o body e NUNCA confere com entregas reais do Core.\r\n * Prefira `verifyWebhookRequest`, que lê os headers e já faz tudo.\r\n *\r\n * @param payload Corpo cru da request (string ou Uint8Array). NÃO use o objeto\r\n * parseado — JSON.stringify pode diferir do que foi assinado.\r\n * @param signature Header `X-Neetru-Signature` recebido (formato `sha256=<hex>`).\r\n * @param secret Secret registrado em `webhooks.register({ secret })`.\r\n * @param timestamp Valor do header `X-Neetru-Timestamp` (ms epoch). Quando\r\n * presente, o HMAC cobre `` `${timestamp}.${payload}` ``\r\n * (esquema canônico do Core — replay protection embutida).\r\n * @returns Promise<boolean> — true se assinatura confere, false caso contrário.\r\n *\r\n * @example\r\n * ```ts\r\n * // Next.js Route Handler (Edge ou Node runtime — funciona em ambos)\r\n * export async function POST(req: Request) {\r\n * const raw = await req.text();\r\n * const sig = req.headers.get('X-Neetru-Signature');\r\n * const ts = req.headers.get('X-Neetru-Timestamp');\r\n * const ok = await verifyWebhookSignature(raw, sig, process.env.NEETRU_WEBHOOK_SECRET!, ts ?? undefined);\r\n * if (!ok) return new Response('unauthorized', { status: 401 });\r\n * const event = JSON.parse(raw);\r\n * // ... handle event\r\n * return Response.json({ ok: true });\r\n * }\r\n * ```\r\n *\r\n * @throws NeetruError('runtime_unsupported') se runtime não expõe WebCrypto.\r\n * Não retorna `false` silencioso — caller precisa distinguir \"assinatura\r\n * inválida\" (return false) de \"ambiente não suporta\" (throw).\r\n */\r\nexport async function verifyWebhookSignature(\r\n payload: string | Uint8Array,\r\n signature: string | null | undefined,\r\n secret: string,\r\n timestamp?: string | number,\r\n): Promise<boolean> {\r\n if (!signature || !secret) return false;\r\n // Aceita \"sha256=<hex>\" ou \"<hex>\" cru.\r\n const sigHex = signature.startsWith('sha256=') ? signature.slice(7) : signature;\r\n if (!/^[0-9a-f]+$/i.test(sigHex)) return false;\r\n\r\n // WebCrypto disponível em Node ≥20, browsers modernos, Edge runtimes.\r\n const subtle: SubtleCrypto | undefined =\r\n typeof globalThis !== 'undefined' && 'crypto' in globalThis\r\n ? (globalThis as { crypto?: { subtle?: SubtleCrypto } }).crypto?.subtle\r\n : undefined;\r\n if (!subtle) {\r\n throw new NeetruError(\r\n 'runtime_unsupported',\r\n 'verifyWebhookSignature requires globalThis.crypto.subtle (Node ≥20, modern browser, or Edge runtime).',\r\n );\r\n }\r\n\r\n const encoder = new TextEncoder();\r\n const keyBytes = encoder.encode(secret);\r\n // TextEncoder.encode retorna Uint8Array<ArrayBuffer>; payload Uint8Array\r\n // pode vir como Uint8Array<ArrayBufferLike> (SharedArrayBuffer compat). Cast\r\n // explicit pra ArrayBuffer view — Web Crypto aceita ambos em runtime.\r\n const rawBytes: Uint8Array =\r\n typeof payload === 'string' ? encoder.encode(payload) : payload;\r\n // Esquema canônico do Core: HMAC(`${timestamp}.${rawBody}`). Sem timestamp,\r\n // assina só o body (compat com verificações custom fora do fluxo Core).\r\n let payloadBytes: Uint8Array = rawBytes;\r\n if (timestamp !== undefined) {\r\n const prefix = encoder.encode(`${timestamp}.`);\r\n const merged = new Uint8Array(prefix.length + rawBytes.length);\r\n merged.set(prefix, 0);\r\n merged.set(rawBytes, prefix.length);\r\n payloadBytes = merged;\r\n }\r\n\r\n const key = await subtle.importKey(\r\n 'raw',\r\n keyBytes as BufferSource,\r\n { name: 'HMAC', hash: 'SHA-256' },\r\n false,\r\n ['sign'],\r\n );\r\n const macBuffer = await subtle.sign(\r\n 'HMAC',\r\n key,\r\n payloadBytes as BufferSource,\r\n );\r\n const macBytes = new Uint8Array(macBuffer);\r\n\r\n // Decode hex signature em bytes.\r\n const sigBytes = hexToBytes(sigHex.toLowerCase());\r\n if (!sigBytes || sigBytes.length !== macBytes.length) return false;\r\n\r\n // Constant-time compare via XOR accumulator.\r\n let diff = 0;\r\n for (let i = 0; i < macBytes.length; i++) {\r\n diff |= macBytes[i] ^ sigBytes[i];\r\n }\r\n return diff === 0;\r\n}\r\n\r\n// ─── verifyWebhookRequest — assinatura + replay protection ─────────────────\r\n\r\n/**\r\n * Opções de `verifyWebhookRequest`.\r\n */\r\nexport interface VerifyWebhookRequestOptions {\r\n /**\r\n * Janela de tolerância em milliseconds para o skew de timestamp.\r\n * Default: 300_000 (5 minutos), conforme documentado na spec de webhooks.\r\n * Valores menores aumentam a proteção contra replay; valores maiores acomodam\r\n * clocks com drift. Não use valores acima de 600_000 (10 min).\r\n */\r\n toleranceMs?: number;\r\n}\r\n\r\n/**\r\n * Resultado de `verifyWebhookRequest`.\r\n */\r\nexport type VerifyWebhookRequestResult =\r\n | { ok: true }\r\n | { ok: false; reason: 'invalid_signature' | 'timestamp_missing' | 'timestamp_expired' | 'runtime_unsupported' };\r\n\r\n/**\r\n * Helper server-only que combina:\r\n * 1. Verificação de assinatura HMAC-SHA256 (`X-Neetru-Signature`)\r\n * 2. **Replay-protection** via skew de timestamp (`X-Neetru-Timestamp`)\r\n *\r\n * Rejeita o request se o timestamp estiver fora da janela `toleranceMs`\r\n * (default ±5 min). Isso fecha a janela de replay onde um atacante captura\r\n * um request válido e o re-envia mais tarde.\r\n *\r\n * **Use este helper em vez de `verifyWebhookSignature` diretamente** — ele\r\n * é a forma correta de validar um webhook Neetru em produção.\r\n *\r\n * @param payload Corpo cru da request (string ou Uint8Array).\r\n * @param headers Headers do request (pode ser um `Headers` Web API ou\r\n * `Record<string, string | undefined>`). Lidos: `X-Neetru-Signature` e\r\n * `X-Neetru-Timestamp`.\r\n * @param secret Secret registrado em `webhooks.register({ secret })`.\r\n * @param options Opções adicionais (ex: `toleranceMs`).\r\n * @returns `{ ok: true }` ou `{ ok: false, reason }` — nunca lança, a menos\r\n * que o runtime não suporte WebCrypto (então propaga `NeetruError('runtime_unsupported')`).\r\n *\r\n * @example\r\n * ```ts\r\n * // Next.js Route Handler\r\n * export async function POST(req: Request) {\r\n * const raw = await req.text();\r\n * const result = await verifyWebhookRequest(raw, req.headers, process.env.NEETRU_WEBHOOK_SECRET!);\r\n * if (!result.ok) {\r\n * console.warn('Webhook rejeitado:', result.reason);\r\n * return new Response('unauthorized', { status: 401 });\r\n * }\r\n * const event = JSON.parse(raw);\r\n * // ... handle event\r\n * return Response.json({ ok: true });\r\n * }\r\n * ```\r\n */\r\nexport async function verifyWebhookRequest(\r\n payload: string | Uint8Array,\r\n headers: Headers | Record<string, string | undefined>,\r\n secret: string,\r\n options: VerifyWebhookRequestOptions = {},\r\n): Promise<VerifyWebhookRequestResult> {\r\n const toleranceMs = options.toleranceMs ?? 300_000; // 5 minutos\r\n\r\n // Lê os headers de forma compatível com Web API Headers e Record<string, string>\r\n const getHeader = (name: string): string | null | undefined => {\r\n if (typeof (headers as Headers).get === 'function') {\r\n return (headers as Headers).get(name);\r\n }\r\n const rec = headers as Record<string, string | undefined>;\r\n // Normaliza pra lowercase pra lidar com variações de casing\r\n const lower = name.toLowerCase();\r\n for (const key of Object.keys(rec)) {\r\n if (key.toLowerCase() === lower) return rec[key] ?? null;\r\n }\r\n return null;\r\n };\r\n\r\n // 1. Verifica skew de timestamp ANTES da criptografia (fail-fast barato)\r\n // getHeader já normaliza lowercase (Record) e Headers.get é case-insensitive — redundância removida\r\n const tsHeader = getHeader('x-neetru-timestamp');\r\n if (!tsHeader) {\r\n return { ok: false, reason: 'timestamp_missing' };\r\n }\r\n const tsMs = Number(tsHeader);\r\n if (!Number.isFinite(tsMs)) {\r\n return { ok: false, reason: 'timestamp_missing' };\r\n }\r\n const skewMs = Math.abs(Date.now() - tsMs);\r\n if (skewMs > toleranceMs) {\r\n return { ok: false, reason: 'timestamp_expired' };\r\n }\r\n\r\n // 2. Verifica assinatura HMAC-SHA256 (WebCrypto — pode lançar runtime_unsupported).\r\n // 3.1.3 fix (auditoria 2026-06-10): o HMAC do Core cobre `${timestamp}.${rawBody}`\r\n // — antes verificávamos só o body, então TODA entrega legítima falhava aqui.\r\n const sig = getHeader('x-neetru-signature');\r\n const valid = await verifyWebhookSignature(payload, sig, secret, tsHeader);\r\n if (!valid) {\r\n return { ok: false, reason: 'invalid_signature' };\r\n }\r\n\r\n return { ok: true };\r\n}\r\n\r\n/** Hex → bytes. Retorna null em input com tamanho ímpar/inválido. */\r\nfunction hexToBytes(hex: string): Uint8Array | null {\r\n if (hex.length % 2 !== 0) return null;\r\n const bytes = new Uint8Array(hex.length / 2);\r\n for (let i = 0; i < bytes.length; i++) {\r\n const high = parseInt(hex[i * 2], 16);\r\n const low = parseInt(hex[i * 2 + 1], 16);\r\n if (Number.isNaN(high) || Number.isNaN(low)) return null;\r\n bytes[i] = (high << 4) | low;\r\n }\r\n return bytes;\r\n}\r\n\r\n// ─── HTTP impl ──────────────────────────────────────────────────────────────\r\n\r\nconst VALID_EVENTS: readonly WebhookEvent[] = [\r\n 'subscription.activated',\r\n 'subscription.cancelled',\r\n 'subscription.payment_failed',\r\n 'subscription.trial_ending',\r\n 'usage.quota_exceeded',\r\n 'account.suspended',\r\n 'account.reactivated',\r\n 'support.ticket_replied',\r\n];\r\n\r\nfunction toEndpoint(raw: unknown): WebhookEndpoint {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Webhook response is not an object');\r\n }\r\n const r = raw as Record<string, unknown>;\r\n if (typeof r.id !== 'string') {\r\n throw new NeetruError('invalid_response', 'Webhook missing id');\r\n }\r\n return {\r\n id: r.id,\r\n url: typeof r.url === 'string' ? r.url : '',\r\n events: Array.isArray(r.events)\r\n ? (r.events as unknown[]).filter((e): e is WebhookEvent =>\r\n VALID_EVENTS.includes(e as WebhookEvent),\r\n )\r\n : [],\r\n hasSecret: r.hasSecret === true,\r\n status:\r\n r.status === 'active' || r.status === 'degraded' || r.status === 'disabled'\r\n ? r.status\r\n : 'active',\r\n lastDeliveryAt: typeof r.lastDeliveryAt === 'string' ? r.lastDeliveryAt : undefined,\r\n consecutiveFailures:\r\n typeof r.consecutiveFailures === 'number' ? r.consecutiveFailures : undefined,\r\n createdAt: typeof r.createdAt === 'string' ? r.createdAt : new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction validateInput(input: RegisterWebhookInput): void {\r\n if (!input.url || typeof input.url !== 'string') {\r\n throw new NeetruError('validation_failed', 'url é obrigatória');\r\n }\r\n try {\r\n const parsed = new URL(input.url);\r\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\r\n throw new Error('invalid protocol');\r\n }\r\n // Em prod, http: é warning (não bloqueia) — testes locais podem usar\r\n } catch {\r\n throw new NeetruError('validation_failed', `url inválida: ${input.url}`);\r\n }\r\n if (!Array.isArray(input.events) || input.events.length === 0) {\r\n throw new NeetruError('validation_failed', 'events deve ter pelo menos 1 evento');\r\n }\r\n for (const ev of input.events) {\r\n if (!VALID_EVENTS.includes(ev)) {\r\n throw new NeetruError('validation_failed', `evento desconhecido: ${ev}`);\r\n }\r\n }\r\n if (input.secret !== undefined && input.secret.length < 16) {\r\n throw new NeetruError('validation_failed', 'secret deve ter ≥16 chars (recomendado 32+)');\r\n }\r\n}\r\n\r\n/** Resolve productId: option explícito > input.productId > config.productId.\r\n *\r\n * **M-03 fix (Opus review 2026-05-27):** valida client-side contra `SDK_ID_RE`\r\n * antes de mandar pro Core — evita 400 silencioso em produção. */\r\nfunction resolveProductId(\r\n config: ResolvedConfig,\r\n ...candidates: Array<string | undefined>\r\n): string {\r\n for (const c of candidates) {\r\n if (typeof c === 'string' && c.length > 0) {\r\n assertValidSdkId('productId', c);\r\n return c;\r\n }\r\n }\r\n if (config.productId) {\r\n assertValidSdkId('productId', config.productId);\r\n return config.productId;\r\n }\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productId required (pass to options/input or set on createNeetruClient)',\r\n );\r\n}\r\n\r\nexport function createWebhooksNamespace(config: ResolvedConfig): WebhooksNamespace {\r\n return {\r\n async register(input) {\r\n validateInput(input);\r\n const productId = resolveProductId(config, input.productId);\r\n const raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/webhooks',\r\n body: {\r\n productId,\r\n url: input.url,\r\n events: input.events,\r\n ...(input.secret ? { secret: input.secret } : {}),\r\n },\r\n requireAuth: true,\r\n });\r\n return toEndpoint(raw);\r\n },\r\n async list(options) {\r\n const productId = resolveProductId(config, options?.productId);\r\n const raw = await httpRequest<{ endpoints?: unknown[] }>(config, {\r\n method: 'GET',\r\n path: '/api/sdk/v1/webhooks',\r\n query: { productId },\r\n requireAuth: true,\r\n });\r\n const list = Array.isArray(raw?.endpoints) ? raw.endpoints : [];\r\n return list.map(toEndpoint);\r\n },\r\n async unregister(id, options) {\r\n if (!id) throw new NeetruError('validation_failed', 'id obrigatório');\r\n const productId = resolveProductId(config, options?.productId);\r\n await httpRequest<unknown>(config, {\r\n method: 'DELETE',\r\n path: `/api/sdk/v1/webhooks/${encodeURIComponent(id)}`,\r\n query: { productId },\r\n requireAuth: true,\r\n });\r\n return { ok: true };\r\n },\r\n async test(id, options) {\r\n if (!id) throw new NeetruError('validation_failed', 'id obrigatório');\r\n const productId = resolveProductId(config, options?.productId);\r\n const raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: `/api/sdk/v1/webhooks/${encodeURIComponent(id)}/test`,\r\n query: { productId },\r\n requireAuth: true,\r\n idempotencyKey: true,\r\n });\r\n if (!raw || typeof raw !== 'object') {\r\n return { ok: false, error: 'invalid response' };\r\n }\r\n const r = raw as Record<string, unknown>;\r\n return {\r\n ok: r.ok === true,\r\n statusCode: typeof r.statusCode === 'number' ? r.statusCode : undefined,\r\n durationMs: typeof r.durationMs === 'number' ? r.durationMs : undefined,\r\n error: typeof r.error === 'string' ? r.error : undefined,\r\n };\r\n },\r\n };\r\n}\r\n\r\n// ─── Mock impl (dev / tests) ────────────────────────────────────────────────\r\n\r\nexport class MockWebhooks implements WebhooksNamespace {\r\n private endpoints = new Map<string, WebhookEndpoint>();\r\n private nextId = 1;\r\n\r\n async register(input: RegisterWebhookInput): Promise<WebhookEndpoint> {\r\n validateInput(input);\r\n const id = `mock_wh_${this.nextId++}`;\r\n const endpoint: WebhookEndpoint = {\r\n id,\r\n url: input.url,\r\n events: input.events,\r\n hasSecret: !!input.secret,\r\n status: 'active',\r\n createdAt: new Date().toISOString(),\r\n };\r\n this.endpoints.set(id, endpoint);\r\n return endpoint;\r\n }\r\n\r\n async list(_options?: WebhookScopeOptions): Promise<WebhookEndpoint[]> {\r\n return [...this.endpoints.values()];\r\n }\r\n\r\n async unregister(id: string, _options?: WebhookScopeOptions): Promise<{ ok: true }> {\r\n if (!this.endpoints.has(id)) {\r\n throw new NeetruError('not_found', `Webhook ${id} não encontrado`);\r\n }\r\n this.endpoints.delete(id);\r\n return { ok: true };\r\n }\r\n\r\n async test(id: string, _options?: WebhookScopeOptions): Promise<WebhookTestResult> {\r\n if (!this.endpoints.has(id)) {\r\n throw new NeetruError('not_found', `Webhook ${id} não encontrado`);\r\n }\r\n return { ok: true, statusCode: 200, durationMs: 42 };\r\n }\r\n}\r\n","/**\r\n * Notifications namespace (v1.2) — produtos SaaS enviam notificações in-app\r\n * pros SEUS usuários (distinto das `notifications/` staff-only do Core).\r\n *\r\n * Caso típico: produto gestovendas notifica usuário \"Pedido #X recebido\" no\r\n * portal sem precisar manter a própria coleção Firestore.\r\n *\r\n * Schema isolado por produto: `product_user_notifications/{productId}/{notifId}`.\r\n * Owner Neetru não vê o conteúdo (privacidade do produto), mas o Core\r\n * armazena + serve a leitura. Produto pode também listar via SDK.\r\n *\r\n * Endpoints REST (em prod):\r\n * - `POST /api/sdk/v1/notifications` — produto envia\r\n * - `GET /api/sdk/v1/notifications/user/{userId}` — produto lista do user\r\n * - `POST /api/sdk/v1/notifications/{id}/read` — user marca lida (proxy)\r\n * - `POST /api/sdk/v1/notifications/{id}/dismiss` — user descarta (proxy)\r\n *\r\n * Severidade canônica: `info | success | warning | error`.\r\n *\r\n * Mock em `NEETRU_ENV=dev`: in-memory.\r\n */\r\nimport { NeetruError } from './errors';\r\nimport { httpRequest } from './http';\r\nimport { assertValidSdkId } from './validators';\r\nimport type { ResolvedConfig } from './types';\r\n\r\nexport type ProductNotificationSeverity =\r\n | 'info'\r\n | 'success'\r\n | 'warning'\r\n | 'error';\r\n\r\nexport interface ProductNotification {\r\n id: string;\r\n /** UID do usuário final (do produto, não staff Neetru). */\r\n userId: string;\r\n /** Identificador semântico do evento (ex: `order.received`). */\r\n kind: string;\r\n severity: ProductNotificationSeverity;\r\n title: string;\r\n body?: string;\r\n /** Link opcional pra ação. */\r\n link?: string;\r\n /** Metadata livre (serializável). */\r\n metadata?: Record<string, string | number | boolean | null>;\r\n createdAt: string;\r\n /** ISO quando user marcou lida. */\r\n readAt?: string;\r\n /** ISO quando user descartou. */\r\n dismissedAt?: string;\r\n}\r\n\r\nexport interface SendNotificationInput {\r\n /**\r\n * **3.0 (breaking):** productId é obrigatório (Core valida via Zod). Default\r\n * resolve do `config.productId`; lança `validation_failed` se ausente.\r\n */\r\n productId?: string;\r\n userId: string;\r\n kind: string;\r\n title: string;\r\n severity?: ProductNotificationSeverity;\r\n body?: string;\r\n link?: string;\r\n metadata?: Record<string, string | number | boolean | null>;\r\n /**\r\n * Dedup — se já existir notificação com mesmo fingerprint dentro de 24h,\r\n * NÃO cria duplicata. Útil pra evitar spam quando webhook reentrega.\r\n */\r\n fingerprint?: string;\r\n}\r\n\r\nexport interface ListNotificationsOptions {\r\n /**\r\n * **3.0 (breaking):** productId é obrigatório no Core. Default resolve do\r\n * `config.productId`.\r\n */\r\n productId?: string;\r\n /** Inclui notificações dismissed (default false). */\r\n includeDismissed?: boolean;\r\n /** Filtro por unread. */\r\n onlyUnread?: boolean;\r\n /** Máx itens (default 50, máx 200). */\r\n limit?: number;\r\n}\r\n\r\n/** 3.0: scope option pra markRead/dismiss (productId obrigatório no Core). */\r\nexport interface NotificationScopeOptions {\r\n productId?: string;\r\n}\r\n\r\nexport interface NotificationsNamespace {\r\n /** Produto envia uma notificação pra um usuário do produto. */\r\n send(input: SendNotificationInput): Promise<ProductNotification>;\r\n /** Lista notificações de um usuário. */\r\n list(\r\n userId: string,\r\n options?: ListNotificationsOptions,\r\n ): Promise<ProductNotification[]>;\r\n /** Marca como lida. */\r\n markRead(id: string, options?: NotificationScopeOptions): Promise<{ ok: true }>;\r\n /** Descarta. */\r\n dismiss(id: string, options?: NotificationScopeOptions): Promise<{ ok: true }>;\r\n}\r\n\r\n// ─── HTTP impl ──────────────────────────────────────────────────────────────\r\n\r\nconst VALID_SEVERITIES: readonly ProductNotificationSeverity[] = [\r\n 'info',\r\n 'success',\r\n 'warning',\r\n 'error',\r\n];\r\n\r\nfunction toNotification(raw: unknown): ProductNotification {\r\n if (!raw || typeof raw !== 'object') {\r\n throw new NeetruError('invalid_response', 'Notification response is not an object');\r\n }\r\n const r = raw as Record<string, unknown>;\r\n if (typeof r.id !== 'string') {\r\n throw new NeetruError('invalid_response', 'Notification missing id');\r\n }\r\n const sev = VALID_SEVERITIES.includes(r.severity as ProductNotificationSeverity)\r\n ? (r.severity as ProductNotificationSeverity)\r\n : 'info';\r\n return {\r\n id: r.id,\r\n userId: typeof r.userId === 'string' ? r.userId : '',\r\n kind: typeof r.kind === 'string' ? r.kind : 'unknown',\r\n severity: sev,\r\n title: typeof r.title === 'string' ? r.title : '',\r\n body: typeof r.body === 'string' ? r.body : undefined,\r\n link: typeof r.link === 'string' ? r.link : undefined,\r\n metadata:\r\n r.metadata && typeof r.metadata === 'object'\r\n ? (r.metadata as Record<string, string | number | boolean | null>)\r\n : undefined,\r\n createdAt: typeof r.createdAt === 'string' ? r.createdAt : new Date().toISOString(),\r\n readAt: typeof r.readAt === 'string' ? r.readAt : undefined,\r\n dismissedAt: typeof r.dismissedAt === 'string' ? r.dismissedAt : undefined,\r\n };\r\n}\r\n\r\nfunction validateInput(input: SendNotificationInput): void {\r\n if (!input.userId) throw new NeetruError('validation_failed', 'userId obrigatório');\r\n if (!input.kind) throw new NeetruError('validation_failed', 'kind obrigatório');\r\n if (!input.title) throw new NeetruError('validation_failed', 'title obrigatório');\r\n if (input.severity && !VALID_SEVERITIES.includes(input.severity)) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n `severity inválida: ${input.severity} (use ${VALID_SEVERITIES.join('|')})`,\r\n );\r\n }\r\n if (input.title.length > 200) {\r\n throw new NeetruError('validation_failed', 'title máx 200 chars');\r\n }\r\n if (input.body && input.body.length > 2000) {\r\n throw new NeetruError('validation_failed', 'body máx 2000 chars');\r\n }\r\n}\r\n\r\n/** Resolve productId fail-closed (option > input > config).\r\n *\r\n * **M-03 fix (Opus review 2026-05-27):** valida client-side contra `SDK_ID_RE`. */\r\nfunction resolveProductId(\r\n config: ResolvedConfig,\r\n ...candidates: Array<string | undefined>\r\n): string {\r\n for (const c of candidates) {\r\n if (typeof c === 'string' && c.length > 0) {\r\n assertValidSdkId('productId', c);\r\n return c;\r\n }\r\n }\r\n if (config.productId) {\r\n assertValidSdkId('productId', config.productId);\r\n return config.productId;\r\n }\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productId required (pass to options/input or set on createNeetruClient)',\r\n );\r\n}\r\n\r\nexport function createNotificationsNamespace(\r\n config: ResolvedConfig,\r\n): NotificationsNamespace {\r\n return {\r\n async send(input) {\r\n validateInput(input);\r\n const productId = resolveProductId(config, input.productId);\r\n const body: Record<string, unknown> = {\r\n productId,\r\n userId: input.userId,\r\n kind: input.kind,\r\n title: input.title,\r\n severity: input.severity ?? 'info',\r\n };\r\n if (input.body !== undefined) body.body = input.body;\r\n if (input.link !== undefined) body.link = input.link;\r\n if (input.metadata !== undefined) body.metadata = input.metadata;\r\n if (input.fingerprint !== undefined) body.fingerprint = input.fingerprint;\r\n const raw = await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: '/api/sdk/v1/notifications',\r\n body,\r\n requireAuth: true,\r\n idempotencyKey: true,\r\n });\r\n return toNotification(raw);\r\n },\r\n async list(userId, options) {\r\n if (!userId) throw new NeetruError('validation_failed', 'userId obrigatório');\r\n const productId = resolveProductId(config, options?.productId);\r\n const query: Record<string, string | number | boolean | undefined> = {\r\n productId,\r\n };\r\n if (options?.includeDismissed) query.includeDismissed = true;\r\n if (options?.onlyUnread) query.onlyUnread = true;\r\n if (options?.limit) {\r\n query.limit = Math.min(Math.max(1, options.limit), 200);\r\n }\r\n const raw = await httpRequest<{ notifications?: unknown[] }>(config, {\r\n method: 'GET',\r\n path: `/api/sdk/v1/notifications/user/${encodeURIComponent(userId)}`,\r\n query,\r\n requireAuth: true,\r\n });\r\n const list = Array.isArray(raw?.notifications) ? raw.notifications : [];\r\n return list.map(toNotification);\r\n },\r\n async markRead(id, options) {\r\n if (!id) throw new NeetruError('validation_failed', 'id obrigatório');\r\n const productId = resolveProductId(config, options?.productId);\r\n await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: `/api/sdk/v1/notifications/${encodeURIComponent(id)}/read`,\r\n query: { productId },\r\n requireAuth: true,\r\n });\r\n return { ok: true };\r\n },\r\n async dismiss(id, options) {\r\n if (!id) throw new NeetruError('validation_failed', 'id obrigatório');\r\n const productId = resolveProductId(config, options?.productId);\r\n await httpRequest<unknown>(config, {\r\n method: 'POST',\r\n path: `/api/sdk/v1/notifications/${encodeURIComponent(id)}/dismiss`,\r\n query: { productId },\r\n requireAuth: true,\r\n });\r\n return { ok: true };\r\n },\r\n };\r\n}\r\n\r\n// ─── Mock impl ──────────────────────────────────────────────────────────────\r\n\r\nexport class MockNotifications implements NotificationsNamespace {\r\n private notifications = new Map<string, ProductNotification>();\r\n private nextId = 1;\r\n\r\n async send(input: SendNotificationInput): Promise<ProductNotification> {\r\n validateInput(input);\r\n // Dedup por fingerprint: se já existe um com mesmo fingerprint < 24h, retorna ele.\r\n if (input.fingerprint) {\r\n const dayAgo = Date.now() - 86_400_000;\r\n for (const existing of this.notifications.values()) {\r\n const meta = existing.metadata ?? {};\r\n if (\r\n meta.fingerprint === input.fingerprint &&\r\n existing.userId === input.userId &&\r\n new Date(existing.createdAt).getTime() > dayAgo\r\n ) {\r\n return existing;\r\n }\r\n }\r\n }\r\n const id = `mock_notif_${this.nextId++}`;\r\n const notif: ProductNotification = {\r\n id,\r\n userId: input.userId,\r\n kind: input.kind,\r\n severity: input.severity ?? 'info',\r\n title: input.title,\r\n body: input.body,\r\n link: input.link,\r\n metadata: input.fingerprint\r\n ? { ...(input.metadata ?? {}), fingerprint: input.fingerprint }\r\n : input.metadata,\r\n createdAt: new Date().toISOString(),\r\n };\r\n this.notifications.set(id, notif);\r\n return notif;\r\n }\r\n\r\n async list(\r\n userId: string,\r\n options?: ListNotificationsOptions,\r\n ): Promise<ProductNotification[]> {\r\n if (!userId) throw new NeetruError('validation_failed', 'userId obrigatório');\r\n const limit = Math.min(Math.max(1, options?.limit ?? 50), 200);\r\n return [...this.notifications.values()]\r\n .filter((n) => n.userId === userId)\r\n .filter((n) => options?.includeDismissed || !n.dismissedAt)\r\n .filter((n) => !options?.onlyUnread || !n.readAt)\r\n .sort((a, b) => b.createdAt.localeCompare(a.createdAt))\r\n .slice(0, limit);\r\n }\r\n\r\n async markRead(id: string, _options?: NotificationScopeOptions): Promise<{ ok: true }> {\r\n const n = this.notifications.get(id);\r\n if (!n) throw new NeetruError('not_found', `Notification ${id} não encontrada`);\r\n if (!n.readAt) {\r\n n.readAt = new Date().toISOString();\r\n this.notifications.set(id, n);\r\n }\r\n return { ok: true };\r\n }\r\n\r\n async dismiss(id: string, _options?: NotificationScopeOptions): Promise<{ ok: true }> {\r\n const n = this.notifications.get(id);\r\n if (!n) throw new NeetruError('not_found', `Notification ${id} não encontrada`);\r\n if (!n.dismissedAt) {\r\n n.dismissedAt = new Date().toISOString();\r\n this.notifications.set(id, n);\r\n }\r\n return { ok: true };\r\n }\r\n}\r\n","/**\r\n * Mocks determinísticos do SDK — overridáveis em tests do consumer ou\r\n * ativados automaticamente quando `NEETRU_ENV=dev`.\r\n *\r\n * Nada aqui faz I/O. Tudo é puro/sincrono/in-memory. Compat total com\r\n * runtimes browser/Node/Edge — sem `node:` builtins.\r\n *\r\n * Cada mock implementa o mesmo namespace interface das implementações reais\r\n * (`AuthNamespace`, `UsageNamespace`, `SupportNamespace`) — caller pode\r\n * substituir 1:1 sem branching.\r\n *\r\n * @example\r\n * ```ts\r\n * import { createNeetruClient, MockAuth } from '@neetru/sdk';\r\n *\r\n * const client = createNeetruClient({\r\n * mocks: { auth: new MockAuth({ uid: 'fake-user', email: 'x@x.com' }) },\r\n * });\r\n * ```\r\n */\r\n\r\nimport type {\r\n AuthNamespace,\r\n AuthStateListener,\r\n CreateTicketInput,\r\n EntitlementCheck,\r\n NeetruUser,\r\n RedirectCallbackResult,\r\n SignInOptions,\r\n SupportNamespace,\r\n SupportTicket,\r\n UsageNamespace,\r\n UsageQuota,\r\n} from './types';\r\nimport type {\r\n NeetruDb,\r\n NeetruSqlClient,\r\n} from './db/client-db';\r\nimport type { DbCollectionRef, DbWhereFilter, DbListResult, DbGetResult, DbBatchOp, DbDocRef, DbQuery } from './db/collection-ref';\r\nimport type { SyncState, ConflictRecord, Unsubscribe } from './db/offline/types';\r\nimport { NeetruDbError } from './db-errors';\r\nimport { NeetruError } from './errors';\r\n\r\n// ─── User fixture default ──────────────────────────────────────────────────\r\n\r\n/**\r\n * User fixture determinístico — usado quando `NEETRU_ENV=dev` e nenhum mock\r\n * custom é injetado. Email/uid estáveis pra snapshot tests.\r\n */\r\nexport const DEV_FIXTURE_USER: NeetruUser = Object.freeze({\r\n uid: 'dev-fixture-uid-0001',\r\n email: 'dev@neetru.local',\r\n emailVerified: true,\r\n displayName: 'Dev Fixture',\r\n isCustomer: true,\r\n isStaff: false,\r\n}) as NeetruUser;\r\n\r\n// ─── MockAuth ──────────────────────────────────────────────────────────────\r\n\r\n/** Opções do construtor de `MockAuth`. */\r\nexport interface MockAuthOptions {\r\n /**\r\n * Permite que `verifyToken` decodifique tokens JWT sem verificar assinatura.\r\n *\r\n * **SOMENTE para uso em testes.** Com `allowUnsignedDecode: false` (default),\r\n * `verifyToken` lança `unauthorized` em vez de aceitar qualquer JWT não-assinado —\r\n * isso previne que misconfiguração de env (`NEETRU_ENV=dev` em prod) vire bypass\r\n * de autenticação. Testes que precisam do comportamento de decode devem passar\r\n * `{ allowUnsignedDecode: true }` explicitamente.\r\n */\r\n allowUnsignedDecode?: boolean;\r\n}\r\n\r\n/**\r\n * Implementação in-memory do `AuthNamespace`. signIn marca o user como\r\n * logado; signOut limpa. onAuthStateChanged dispara callback síncrono no\r\n * subscribe + a cada mudança.\r\n */\r\nexport class MockAuth implements AuthNamespace {\r\n private _user: NeetruUser | null;\r\n private _listeners: Set<AuthStateListener>;\r\n private _allowUnsignedDecode: boolean;\r\n\r\n constructor(initialUser: NeetruUser | null = null, options?: MockAuthOptions) {\r\n this._user = initialUser;\r\n this._listeners = new Set();\r\n this._allowUnsignedDecode = options?.allowUnsignedDecode ?? false;\r\n\r\n // Emite aviso proeminente em dev quando fora de testes, pra deixar claro\r\n // que verifyToken no mock NÃO valida assinaturas.\r\n // Guard: não spamma em ambientes de teste (process.env.NODE_ENV=test ou\r\n // VITEST=true). Emite só uma vez por instância (basta pra chamar atenção).\r\n if (this._allowUnsignedDecode) {\r\n const isTestEnv =\r\n (typeof process !== 'undefined' && (\r\n process.env?.NODE_ENV === 'test' ||\r\n process.env?.VITEST === 'true' ||\r\n process.env?.VITEST != null\r\n ));\r\n if (!isTestEnv && typeof console !== 'undefined') {\r\n console.warn(\r\n '[neetru-sdk] MockAuth.verifyToken está em modo allowUnsignedDecode=true: ' +\r\n 'tokens NÃO têm assinatura verificada. ' +\r\n 'Este modo é exclusivo para testes — NUNCA use como security boundary em código deployado.',\r\n );\r\n }\r\n }\r\n }\r\n\r\n async signIn(_options?: SignInOptions): Promise<NeetruUser> {\r\n // Mock: apenas marca user como logado (usa fixture se não havia).\r\n if (!this._user) this._user = { ...DEV_FIXTURE_USER };\r\n this._notify();\r\n return this._user;\r\n }\r\n\r\n async signOut(): Promise<void> {\r\n this._user = null;\r\n this._notify();\r\n }\r\n\r\n getUser(): NeetruUser | null {\r\n return this._user;\r\n }\r\n\r\n onAuthStateChanged(listener: AuthStateListener): () => void {\r\n this._listeners.add(listener);\r\n // Dispara imediatamente com estado atual (espelha API Firebase Auth).\r\n try {\r\n listener(this._user);\r\n } catch {\r\n // Callback do consumer não pode quebrar o subscribe.\r\n }\r\n return () => {\r\n this._listeners.delete(listener);\r\n };\r\n }\r\n\r\n /**\r\n * Mock de `verifyToken` — por default lança `unauthorized` pra prevenir uso\r\n * acidental como security boundary em código deployado.\r\n *\r\n * Para decodificar JWTs sem verificar assinatura em testes, crie a instância\r\n * com `new MockAuth(user, { allowUnsignedDecode: true })`. Isso é um opt-in\r\n * explícito — nunca acontece silenciosamente.\r\n *\r\n * Para simular falhas ou resultados customizados, use `__mockVerifyToken(fn)`.\r\n */\r\n async verifyToken(token: string): Promise<NeetruUser> {\r\n if (this._verifyTokenOverride) {\r\n return this._verifyTokenOverride(token);\r\n }\r\n if (!token) {\r\n throw new NeetruError('token_invalid_signature', 'Token inválido: string vazia');\r\n }\r\n // Sem opt-in explícito, recusa-se a decodificar — decodificar JWTs sem\r\n // verificar assinatura é uma vulnerabilidade se este mock vazar pra produção\r\n // (ex: NEETRU_ENV=dev configurado erroneamente, ou globalThis.NEETRU_ENV\r\n // injetado por bundle). O caller deve usar __mockVerifyToken() ou passar\r\n // allowUnsignedDecode: true no construtor.\r\n if (!this._allowUnsignedDecode) {\r\n throw new NeetruError(\r\n 'unauthorized',\r\n 'MockAuth.verifyToken não verifica assinaturas JWT e NÃO deve ser usado como ' +\r\n 'security boundary em código deployado. ' +\r\n 'Em testes, use new MockAuth(user, { allowUnsignedDecode: true }) para habilitar ' +\r\n 'decodificação sem assinatura, ou __mockVerifyToken(fn) para injetar resultado customizado.',\r\n );\r\n }\r\n // allowUnsignedDecode=true: decodifica claims base64 sem verificar assinatura (testes).\r\n try {\r\n const parts = token.split('.');\r\n if (parts.length === 3) {\r\n const b64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');\r\n const pad = '='.repeat((4 - (b64.length % 4)) % 4);\r\n const decoded = JSON.parse(\r\n typeof atob === 'function'\r\n ? atob(b64 + pad)\r\n : Buffer.from(b64 + pad, 'base64').toString('utf-8'),\r\n ) as Record<string, unknown>;\r\n if (typeof decoded.sub === 'string') {\r\n return {\r\n uid: decoded.sub,\r\n email: typeof decoded.email === 'string' ? decoded.email : '',\r\n emailVerified: typeof decoded.email_verified === 'boolean' ? decoded.email_verified : undefined,\r\n displayName: typeof decoded.name === 'string' ? decoded.name : undefined,\r\n photoURL: typeof decoded.picture === 'string' ? decoded.picture : undefined,\r\n isStaff: decoded.is_staff === true,\r\n isCustomer: decoded.is_customer === true,\r\n tenantId: typeof decoded.tenant_id === 'string' ? decoded.tenant_id : undefined,\r\n ...decoded,\r\n };\r\n }\r\n }\r\n } catch {\r\n /* fall through to return current user */\r\n }\r\n // Fallback: retorna o user atual do mock.\r\n if (this._user) return this._user;\r\n throw new NeetruError('token_invalid_signature', 'Nenhum user mock disponível e JWT sem sub válido');\r\n }\r\n\r\n /**\r\n * Mock de `handleRedirectCallback` (Bug 2 / 3.1.3) — não há redirect real no\r\n * mock, então retorna `null` por default. Use `__setPendingCallback(result)`\r\n * em testes pra simular um retorno do IdP.\r\n */\r\n async handleRedirectCallback(_currentUrl?: string): Promise<RedirectCallbackResult | null> {\r\n return this._pendingCallback;\r\n }\r\n\r\n /**\r\n * Mock de `getIdToken` (Bug 2 / 3.1.3). Retorna `null` por default; use\r\n * `__setIdToken(token)` pra injetar um token cru em testes.\r\n */\r\n getIdToken(): string | null {\r\n return this._idToken;\r\n }\r\n\r\n private _pendingCallback: RedirectCallbackResult | null = null;\r\n private _idToken: string | null = null;\r\n\r\n /** Test helper — simula o material devolvido por um callback OIDC. */\r\n __setPendingCallback(result: RedirectCallbackResult | null): void {\r\n this._pendingCallback = result;\r\n }\r\n\r\n /** Test helper — injeta o id_token cru retornado por `getIdToken`. */\r\n __setIdToken(token: string | null): void {\r\n this._idToken = token;\r\n }\r\n\r\n private _verifyTokenOverride: ((token: string) => Promise<NeetruUser>) | null = null;\r\n\r\n /**\r\n * Injeta override pra `verifyToken` em testes — permite simular expiração,\r\n * assinatura inválida etc sem precisar de JWT real.\r\n *\r\n * @example\r\n * ```ts\r\n * const mock = new MockAuth(null);\r\n * mock.__mockVerifyToken(async () => { throw new NeetruError('token_expired', '...'); });\r\n * ```\r\n */\r\n __mockVerifyToken(fn: ((token: string) => Promise<NeetruUser>) | null): void {\r\n this._verifyTokenOverride = fn;\r\n }\r\n\r\n /** Helper de tests — força um user state arbitrário. */\r\n __setUser(user: NeetruUser | null): void {\r\n this._user = user;\r\n this._notify();\r\n }\r\n\r\n private _notify(): void {\r\n for (const l of this._listeners) {\r\n try {\r\n l(this._user);\r\n } catch {\r\n // ignore consumer errors\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ─── MockUsage (3.0 — track/getQuota removidos) ────────────────────────────\r\n\r\ninterface UsageReportRecord {\r\n resource: string;\r\n qty: number;\r\n productId?: string;\r\n tenantId?: string;\r\n timestamp: string;\r\n}\r\n\r\n/**\r\n * In-memory `UsageNamespace` 3.0. `report()` acumula counter local; `check()`\r\n * compara com `__setQuota(resource, {used, limit})` fixture.\r\n *\r\n * Breaking 3.0:\r\n * - `track(event, props)` REMOVIDO.\r\n * - `getQuota(metric)` REMOVIDO.\r\n * - `__getRecords()` agora retorna `UsageReportRecord[]` (resource/qty).\r\n */\r\nexport class MockUsage implements UsageNamespace {\r\n private _reports: UsageReportRecord[] = [];\r\n private _quotas: Map<string, UsageQuota>;\r\n private _counters: Map<string, number> = new Map();\r\n\r\n constructor(initialQuotas: Record<string, UsageQuota> = {}) {\r\n this._quotas = new Map(Object.entries(initialQuotas));\r\n }\r\n\r\n async report(\r\n resource: string,\r\n qty: number = 1,\r\n options?: { productId?: string; tenantId?: string },\r\n ): Promise<{\r\n ok: true;\r\n counterId?: string;\r\n value?: number;\r\n limit?: number;\r\n remaining?: number;\r\n status?: string;\r\n }> {\r\n if (!resource) throw new Error('resource required');\r\n const safeQty = Number.isFinite(qty) && qty > 0 ? Math.floor(qty) : 1;\r\n const existing = this._counters.get(resource) ?? 0;\r\n const next = existing + safeQty;\r\n this._counters.set(resource, next);\r\n this._reports.push({\r\n resource,\r\n qty: safeQty,\r\n productId: options?.productId,\r\n tenantId: options?.tenantId,\r\n timestamp: new Date().toISOString(),\r\n });\r\n const limitFixture = this._quotas.get(resource);\r\n const limit = limitFixture?.limit ?? -1;\r\n return {\r\n ok: true,\r\n counterId: `mock_${resource}`,\r\n value: next,\r\n limit,\r\n remaining: limit < 0 ? -1 : Math.max(0, limit - next),\r\n status: limit > 0 && next >= limit ? 'read_only_overlimit' : 'ok',\r\n };\r\n }\r\n\r\n async check(\r\n resource: string,\r\n _options?: { productId?: string; tenantId?: string },\r\n ): Promise<{\r\n allowed: boolean;\r\n reason?: string;\r\n remaining?: number;\r\n limit?: number;\r\n planId?: string | null;\r\n planFeatures?: string[];\r\n behavior?: 'readonly' | null;\r\n }> {\r\n const quota = this._quotas.get(resource);\r\n const used = this._counters.get(resource) ?? 0;\r\n if (!quota) {\r\n return { allowed: true, reason: 'granted', limit: -1, remaining: -1, behavior: null };\r\n }\r\n const remaining = quota.limit < 0 ? -1 : Math.max(0, quota.limit - used);\r\n if (remaining === 0) {\r\n return {\r\n allowed: false,\r\n reason: 'limit_exceeded',\r\n limit: quota.limit,\r\n remaining: 0,\r\n behavior: 'readonly',\r\n };\r\n }\r\n return {\r\n allowed: true,\r\n reason: 'granted',\r\n limit: quota.limit,\r\n remaining,\r\n behavior: null,\r\n };\r\n }\r\n\r\n /** Test helper — retorna histórico de `report()` calls. */\r\n __getReports(): readonly UsageReportRecord[] {\r\n return [...this._reports];\r\n }\r\n /** @deprecated Removido em 3.0 (usage.track foi removido). Use `__getReports`. */\r\n __getRecords(): readonly UsageReportRecord[] {\r\n return this.__getReports();\r\n }\r\n /** Test helper — substitui quota fixture. */\r\n __setQuota(metric: string, quota: UsageQuota): void {\r\n this._quotas.set(metric, quota);\r\n }\r\n /** Test helper — limpa estado. */\r\n __reset(): void {\r\n this._reports = [];\r\n this._quotas.clear();\r\n this._counters.clear();\r\n }\r\n}\r\n\r\n// ─── MockSupport ───────────────────────────────────────────────────────────\r\n\r\n/**\r\n * In-memory `SupportNamespace`. createTicket gera ID `mock-ticket-{n}`;\r\n * listMyTickets retorna todos criados (FIFO). Sequência por instância\r\n * (evita poluição cross-test do estado de módulo).\r\n */\r\nexport class MockSupport implements SupportNamespace {\r\n private _tickets: SupportTicket[] = [];\r\n private _ticketSeq = 0;\r\n\r\n async createTicket(input: CreateTicketInput): Promise<SupportTicket> {\r\n // L-03 fix (Opus review): MockSupport agora espelha contrato 3.0 do Core.\r\n // Antes aceitava input sem productSlug, mascarando bugs em tests que\r\n // passariam em prod com 400 validation_failed.\r\n if (!input?.subject) throw new NeetruError('validation_failed', 'subject required');\r\n if (!input?.message) throw new NeetruError('validation_failed', 'message required');\r\n if (!input?.productSlug) {\r\n throw new NeetruError(\r\n 'validation_failed',\r\n 'productSlug required (3.0 breaking — pass to input or set on createNeetruClient)',\r\n );\r\n }\r\n const ticket: SupportTicket = {\r\n id: `mock-ticket-${++this._ticketSeq}`,\r\n subject: input.subject,\r\n message: input.message,\r\n severity: input.severity ?? 'normal',\r\n status: 'open',\r\n createdAt: new Date().toISOString(),\r\n productSlug: input.productSlug,\r\n };\r\n this._tickets.push(ticket);\r\n return ticket;\r\n }\r\n\r\n async listMyTickets(options?: { productSlug?: string }): Promise<SupportTicket[]> {\r\n if (options?.productSlug) {\r\n return this._tickets.filter((t) => t.productSlug === options.productSlug);\r\n }\r\n return [...this._tickets];\r\n }\r\n\r\n /** Test helper. */\r\n __reset(): void {\r\n this._tickets = [];\r\n this._ticketSeq = 0;\r\n }\r\n}\r\n\r\n// ─── MockEntitlements ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * In-memory entitlements. Por default `allowed=true` em tudo (dev convém).\r\n * Use `__deny(slug, feature)` em tests pra simular bloqueio.\r\n */\r\nexport class MockEntitlements {\r\n private _denied: Set<string> = new Set();\r\n\r\n async check(productSlug: string, feature: string): Promise<boolean> {\r\n return !this._denied.has(`${productSlug}:${feature}`);\r\n }\r\n\r\n async checkDetailed(productSlug: string, feature: string): Promise<EntitlementCheck> {\r\n const allowed = await this.check(productSlug, feature);\r\n return {\r\n allowed,\r\n productSlug,\r\n feature,\r\n reason: allowed ? 'granted' : 'mock_denied',\r\n };\r\n }\r\n\r\n /** Test helper. */\r\n __deny(productSlug: string, feature: string): void {\r\n this._denied.add(`${productSlug}:${feature}`);\r\n }\r\n /** Test helper. */\r\n __reset(): void {\r\n this._denied.clear();\r\n }\r\n}\r\n\r\n// ─── MockDb (v2.0) ─────────────────────────────────────────────────────────\r\n\r\n/**\r\n * In-memory `NeetruDb`. Cada `collection(name)` aponta para um Map; ops\r\n * são totalmente síncronas (mas API await-friendly).\r\n *\r\n * v2.0: implementa a interface `NeetruDb` completa (collection, sql, syncState,\r\n * flush, clearCache, getConflicts, onSyncStateChanged).\r\n *\r\n * Útil para testar produtos consumidores sem rodar Core REST nem IndexedDB.\r\n */\r\nexport class MockDb implements NeetruDb {\r\n private _store: Map<string, Map<string, Record<string, unknown>>> = new Map();\r\n private _fixtures: Map<string, Record<string, Record<string, unknown>>>;\r\n\r\n constructor(initialFixtures: Record<string, Record<string, Record<string, unknown>>> = {}) {\r\n this._fixtures = new Map(Object.entries(initialFixtures));\r\n }\r\n\r\n collection<T = Record<string, unknown>>(name: string): DbCollectionRef<T> {\r\n const _store = this._store;\r\n const _fixtures = this._fixtures;\r\n if (!_store.has(name)) {\r\n const init = _fixtures.get(name);\r\n _store.set(\r\n name,\r\n init ? new Map(Object.entries(init)) : new Map(),\r\n );\r\n }\r\n const coll = _store.get(name)!;\r\n\r\n const matchesFilter = (\r\n doc: Record<string, unknown>,\r\n f: DbWhereFilter,\r\n ): boolean => {\r\n const v = doc[f.field];\r\n switch (f.op) {\r\n case '==':\r\n return v === f.value;\r\n case '!=':\r\n return v !== f.value;\r\n case '<':\r\n return typeof v === 'number' && typeof f.value === 'number' && v < f.value;\r\n case '<=':\r\n return typeof v === 'number' && typeof f.value === 'number' && v <= f.value;\r\n case '>':\r\n return typeof v === 'number' && typeof f.value === 'number' && v > f.value;\r\n case '>=':\r\n return typeof v === 'number' && typeof f.value === 'number' && v >= f.value;\r\n case 'in':\r\n return Array.isArray(f.value) && (f.value as unknown[]).includes(v);\r\n case 'array-contains':\r\n return Array.isArray(v) && (v as unknown[]).includes(f.value);\r\n case 'not-in':\r\n return Array.isArray(f.value) && !(f.value as unknown[]).includes(v);\r\n default:\r\n return true;\r\n }\r\n };\r\n\r\n let autoSeq = 0;\r\n\r\n // Helper to build a minimal DbListResult from raw items\r\n function buildListResult<U>(items: Array<Record<string, unknown>>): DbListResult<U> {\r\n return {\r\n docs: items.map((d, i) => ({ id: (d.id as string) ?? String(i), data: d as U })),\r\n nextCursor: null,\r\n fromCache: false,\r\n stale: false,\r\n hasPendingWrites: false,\r\n changes: [],\r\n };\r\n }\r\n\r\n // Helper to build a DbGetResult for a single doc\r\n function buildGetResult<U>(data: Record<string, unknown>, id: string): DbGetResult<U> {\r\n return {\r\n docs: [{ id, data: data as U }],\r\n fromCache: false,\r\n stale: false,\r\n hasPendingWrites: false,\r\n changes: [],\r\n };\r\n }\r\n\r\n const ref: DbCollectionRef<T> = {\r\n async list(q?: DbQuery): Promise<DbListResult<T>> {\r\n let items = Array.from(coll.values());\r\n if (q?.where && q.where.length > 0) {\r\n items = items.filter((doc) =>\r\n (q.where as DbWhereFilter[]).every((f) => matchesFilter(doc, f)),\r\n );\r\n }\r\n if (q?.orderBy) {\r\n const { field, direction } = q.orderBy;\r\n items = items.slice().sort((a, b) => {\r\n const av = a[field];\r\n const bv = b[field];\r\n const avs = av ?? '';\r\n const bvs = bv ?? '';\r\n const cmp = (avs as string) < (bvs as string) ? -1 : (avs as string) > (bvs as string) ? 1 : 0;\r\n return direction === 'desc' ? -cmp : cmp;\r\n });\r\n }\r\n const limit = q?.limit ?? 20;\r\n items = items.slice(0, limit);\r\n return buildListResult<T>(items);\r\n },\r\n async get(id: string): Promise<DbGetResult<T> | null> {\r\n const data = coll.get(id);\r\n if (!data) return null;\r\n return buildGetResult<T>(data, id);\r\n },\r\n async add(data: Omit<T, 'id'>): Promise<{ ok: true; id: string }> {\r\n const id = `mock-${++autoSeq}-${Math.random().toString(36).slice(2, 8)}`;\r\n coll.set(id, { ...(data as Record<string, unknown>), id });\r\n return { ok: true, id };\r\n },\r\n async set(id: string, data: Omit<T, 'id'>): Promise<{ ok: true }> {\r\n coll.set(id, { ...(data as Record<string, unknown>), id });\r\n return { ok: true };\r\n },\r\n async update(id: string, data: Partial<Omit<T, 'id'>>): Promise<{ ok: true }> {\r\n const cur = coll.get(id);\r\n if (!cur) {\r\n coll.set(id, { ...(data as Record<string, unknown>), id });\r\n } else {\r\n coll.set(id, { ...cur, ...(data as Record<string, unknown>) });\r\n }\r\n return { ok: true };\r\n },\r\n async remove(id: string): Promise<{ ok: true }> {\r\n coll.delete(id);\r\n return { ok: true };\r\n },\r\n async batch(ops: DbBatchOp[]): Promise<{ ok: true }> {\r\n for (const op of ops) {\r\n // Mock usa a coleção corrente (collName) — o campo collection foi removido\r\n // do discriminated union em 2.1.1; batch opera sempre na coleção do ref.\r\n const collMap = coll;\r\n if (op.kind === 'add') {\r\n const id = `mock-batch-${++autoSeq}`;\r\n collMap.set(id, { ...(op.data as Record<string, unknown>), id });\r\n } else if (op.kind === 'set') {\r\n collMap.set(op.id, { ...(op.data as Record<string, unknown>), id: op.id });\r\n } else if (op.kind === 'update') {\r\n const cur = collMap.get(op.id);\r\n collMap.set(op.id, { ...(cur ?? {}), ...(op.data as Record<string, unknown>), id: op.id });\r\n } else if (op.kind === 'remove') {\r\n collMap.delete(op.id);\r\n }\r\n }\r\n return { ok: true };\r\n },\r\n onDoc(id: string, cb: (doc: T | null) => void): Unsubscribe {\r\n // Entrega snapshot inicial imediato (sync mock)\r\n const data = coll.get(id);\r\n Promise.resolve().then(() => cb(data ? (data as T) : null));\r\n // Mock: não há feed realtime — retorna no-op unsubscribe\r\n return () => {};\r\n },\r\n onSnapshot(q: DbQuery | undefined, cb: (snap: DbListResult<T>) => void): Unsubscribe {\r\n // Entrega snapshot inicial imediato (sync mock)\r\n Promise.resolve().then(async () => {\r\n const snap = await ref.list(q);\r\n cb(snap);\r\n });\r\n return () => {};\r\n },\r\n doc(id: string): DbDocRef<T> {\r\n return {\r\n get id(): string { return id; },\r\n get path(): string { return `${name}/${id}`; },\r\n get collection(): string { return name; },\r\n async get() {\r\n const data = coll.get(id);\r\n if (!data) return null;\r\n return buildGetResult<T>(data, id);\r\n },\r\n async set(data: Omit<T, 'id'>) {\r\n coll.set(id, { ...(data as Record<string, unknown>), id });\r\n return { ok: true };\r\n },\r\n async update(data: Partial<Omit<T, 'id'>>) {\r\n const cur = coll.get(id);\r\n if (!cur) {\r\n coll.set(id, { ...(data as Record<string, unknown>), id });\r\n } else {\r\n coll.set(id, { ...cur, ...(data as Record<string, unknown>) });\r\n }\r\n return { ok: true };\r\n },\r\n async remove() {\r\n coll.delete(id);\r\n return { ok: true };\r\n },\r\n onSnapshot(cb: (snap: DbGetResult<T> | null) => void): Unsubscribe {\r\n const data = coll.get(id);\r\n Promise.resolve().then(() =>\r\n cb(data ? buildGetResult<T>(data, id) : null),\r\n );\r\n return () => {};\r\n },\r\n };\r\n },\r\n };\r\n\r\n return ref;\r\n }\r\n\r\n /**\r\n * Implementa SQL in-memory para testes — preferência: `@electric-sql/pglite`\r\n * + `drizzle-orm/pglite`; fallback: `pg-mem` + `drizzle-orm/node-postgres`\r\n * com strip interceptor.\r\n *\r\n * bug_6bae8674461f4600809e2f9de13c6043 (HIGH 26/05): fix anterior (2.3.3)\r\n * teve efeito INVERSO. Injetar `pool.types.getTypeParser` fez drizzle-orm\r\n * passar `query.types.getTypeParser` pro pg-mem, que tem guard interno\r\n * `if (query.types?.getTypeParser) throw NotSupported`. Ou seja: presença\r\n * de getTypeParser é o gatilho do erro — não ausência.\r\n *\r\n * Solução A (pglite, preferida): `@electric-sql/pglite` é WASM-Postgres\r\n * nativo — sem adapter pg-mem, sem esse conflito de tipos.\r\n * Solução B (fallback pg-mem): strip interceptor no pool.query que deleta\r\n * `types.getTypeParser` do objeto de query ANTES do pg-mem ver. Compat com\r\n * consumers que só têm pg-mem nas devDeps.\r\n *\r\n * Use `options.initSql` pra rodar DDL no setup (CREATE TABLE etc).\r\n */\r\n async sql<TSchema extends Record<string, unknown>>(\r\n schema: TSchema,\r\n options?: { database?: string; initSql?: string | string[] },\r\n ): Promise<NeetruSqlClient<TSchema>> {\r\n const ddls = options?.initSql\r\n ? Array.isArray(options.initSql) ? options.initSql : [options.initSql]\r\n : [];\r\n\r\n // ── Solução A: pglite (preferida) ────────────────────────────────────────\r\n // PGlite é WASM-Postgres nativo — sem adapter pg-mem, sem o conflito de\r\n // tipos (pg-mem rejeita queries com getTypeParser presente; pglite não tem\r\n // esse guard).\r\n try {\r\n // bug_168368ae: webpackIgnore obrigatório — peerDeps optional server-only.\r\n const pglitePkg = await import(/* webpackIgnore: true */ '@electric-sql/pglite');\r\n const drizzlePglitePkg = await import(/* webpackIgnore: true */ 'drizzle-orm/pglite');\r\n\r\n // PGlite.create() retorna instância já pronta (waitReady resolvido).\r\n const pglite = await pglitePkg.PGlite.create();\r\n\r\n for (const ddl of ddls) {\r\n await pglite.query(ddl);\r\n }\r\n\r\n const pgliteOrm = drizzlePglitePkg.drizzle(pglite, { schema });\r\n\r\n // NeetruSqlClient.orm é tipado como NodePgDatabase — pglite e node-postgres\r\n // implementam a mesma superfície Drizzle mas com tipos de resultado internos\r\n // distintos (Results vs QueryResult). Cast via unknown necessário.\r\n const ormAsNode = pgliteOrm as unknown as import('drizzle-orm/node-postgres').NodePgDatabase<TSchema>;\r\n\r\n return {\r\n orm: ormAsNode,\r\n async transaction(fn, _opts) {\r\n return await pgliteOrm.transaction(fn as never) as never;\r\n },\r\n async close() {\r\n if (!pglite.closed) await pglite.close();\r\n },\r\n };\r\n } catch (_pgliteErr) {\r\n // Pglite indisponível (não instalado ou WASM falhou) — cai no pg-mem.\r\n }\r\n\r\n // ── Solução B: pg-mem + strip interceptor (fallback) ─────────────────────\r\n let pgMemMod: typeof import('pg-mem');\r\n let drizzlePg: typeof import('drizzle-orm/node-postgres');\r\n try {\r\n // bug_168368ae: webpackIgnore obrigatório.\r\n pgMemMod = await import(/* webpackIgnore: true */ 'pg-mem');\r\n drizzlePg = await import(/* webpackIgnore: true */ 'drizzle-orm/node-postgres');\r\n } catch {\r\n throw new NeetruDbError(\r\n 'db_unavailable',\r\n '[MockDb] sql() requer @electric-sql/pglite OU pg-mem + drizzle-orm + pg como devDependencies. ' +\r\n 'Preferido: npm install -D @electric-sql/pglite drizzle-orm. ' +\r\n 'Alternativo: npm install -D pg-mem drizzle-orm pg.',\r\n );\r\n }\r\n\r\n const memDb = pgMemMod.newDb({ noAstCoverageCheck: true });\r\n\r\n if (ddls.length > 0) {\r\n for (const ddl of ddls) {\r\n memDb.public.none(ddl);\r\n }\r\n }\r\n\r\n const adapters = memDb.adapters.createPg();\r\n const PoolCtor = (adapters as { Pool: new () => unknown }).Pool;\r\n const pool = new PoolCtor() as Record<string, unknown>;\r\n\r\n // bug_6bae8674 strip interceptor: pg-mem rejeita queries que TÊM\r\n // `query.types.getTypeParser` presente (guard interno NotSupported).\r\n // drizzle-orm/node-postgres/session.js injeta `rawQuery.types = pool.types`\r\n // em toda query. Ao interceptar pool.query e deletar getTypeParser do objeto\r\n // de query antes de passar pro pg-mem, o guard não dispara.\r\n // NÃO adicionar getTypeParser ao pool.types (fix 2.3.3 causou efeito inverso).\r\n const origQuery = (pool as { query: (...a: unknown[]) => unknown }).query.bind(pool);\r\n (pool as { query: (...a: unknown[]) => unknown }).query = (q: unknown, ...rest: unknown[]) => {\r\n if (q !== null && typeof q === 'object') {\r\n const queryObj = q as Record<string, unknown>;\r\n const types = queryObj['types'];\r\n if (types !== null && typeof types === 'object' && 'getTypeParser' in (types as object)) {\r\n delete (types as Record<string, unknown>)['getTypeParser'];\r\n }\r\n }\r\n return origQuery(q, ...rest);\r\n };\r\n\r\n const orm = drizzlePg.drizzle(pool as never, { schema }) as unknown as\r\n import('drizzle-orm/node-postgres').NodePgDatabase<TSchema>;\r\n\r\n return {\r\n orm,\r\n async transaction(fn, _opts) {\r\n return await orm.transaction(fn as never) as never;\r\n },\r\n async close() {\r\n const p = pool as { end?: () => Promise<void> };\r\n if (p.end) await p.end();\r\n },\r\n };\r\n }\r\n\r\n get syncState(): SyncState {\r\n return {\r\n status: 'idle',\r\n pendingWrites: 0,\r\n lastSyncedAt: null,\r\n isLeaderTab: true,\r\n };\r\n }\r\n\r\n onSyncStateChanged(_cb: (s: SyncState) => void): Unsubscribe {\r\n return () => {};\r\n }\r\n\r\n async flush(): Promise<void> {\r\n // no-op in mock\r\n }\r\n\r\n async clearCache(): Promise<void> {\r\n this._store.clear();\r\n }\r\n\r\n async getConflicts(): Promise<ConflictRecord[]> {\r\n return [];\r\n }\r\n\r\n /** Test helper — substitui fixture inteira de uma collection. */\r\n __setFixture(name: string, items: Record<string, Record<string, unknown>>): void {\r\n this._store.set(name, new Map(Object.entries(items)));\r\n }\r\n\r\n /** Test helper — reset total. */\r\n __reset(): void {\r\n this._store.clear();\r\n }\r\n}\r\n"]}