@neetru/sdk 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +33 -3
  2. package/README.md +135 -159
  3. package/dist/auth.cjs +486 -40
  4. package/dist/auth.cjs.map +1 -1
  5. package/dist/auth.d.cts +1 -1
  6. package/dist/auth.d.ts +1 -1
  7. package/dist/auth.mjs +486 -40
  8. package/dist/auth.mjs.map +1 -1
  9. package/dist/catalog.cjs +64 -21
  10. package/dist/catalog.cjs.map +1 -1
  11. package/dist/catalog.d.cts +2 -2
  12. package/dist/catalog.d.ts +2 -2
  13. package/dist/catalog.mjs +64 -21
  14. package/dist/catalog.mjs.map +1 -1
  15. package/dist/checkout.cjs +61 -15
  16. package/dist/checkout.cjs.map +1 -1
  17. package/dist/checkout.d.cts +1 -1
  18. package/dist/checkout.d.ts +1 -1
  19. package/dist/checkout.mjs +61 -15
  20. package/dist/checkout.mjs.map +1 -1
  21. package/dist/db.cjs +67 -22
  22. package/dist/db.cjs.map +1 -1
  23. package/dist/db.d.cts +1 -1
  24. package/dist/db.d.ts +1 -1
  25. package/dist/db.mjs +67 -22
  26. package/dist/db.mjs.map +1 -1
  27. package/dist/entitlements.cjs +102 -21
  28. package/dist/entitlements.cjs.map +1 -1
  29. package/dist/entitlements.d.cts +11 -5
  30. package/dist/entitlements.d.ts +11 -5
  31. package/dist/entitlements.mjs +102 -21
  32. package/dist/entitlements.mjs.map +1 -1
  33. package/dist/index.cjs +491 -41
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +3 -3
  36. package/dist/index.d.ts +3 -3
  37. package/dist/index.mjs +488 -42
  38. package/dist/index.mjs.map +1 -1
  39. package/dist/mocks.cjs +3 -2
  40. package/dist/mocks.cjs.map +1 -1
  41. package/dist/mocks.d.cts +4 -2
  42. package/dist/mocks.d.ts +4 -2
  43. package/dist/mocks.mjs +3 -2
  44. package/dist/mocks.mjs.map +1 -1
  45. package/dist/notifications.cjs +296 -0
  46. package/dist/notifications.cjs.map +1 -0
  47. package/dist/notifications.d.cts +1 -0
  48. package/dist/notifications.d.ts +1 -0
  49. package/dist/notifications.mjs +293 -0
  50. package/dist/notifications.mjs.map +1 -0
  51. package/dist/react.cjs +7 -3
  52. package/dist/react.cjs.map +1 -1
  53. package/dist/react.d.cts +1 -1
  54. package/dist/react.d.ts +1 -1
  55. package/dist/react.mjs +7 -3
  56. package/dist/react.mjs.map +1 -1
  57. package/dist/support.cjs +61 -15
  58. package/dist/support.cjs.map +1 -1
  59. package/dist/support.d.cts +1 -1
  60. package/dist/support.d.ts +1 -1
  61. package/dist/support.mjs +61 -15
  62. package/dist/support.mjs.map +1 -1
  63. package/dist/telemetry.cjs +131 -16
  64. package/dist/telemetry.cjs.map +1 -1
  65. package/dist/telemetry.d.cts +17 -1
  66. package/dist/telemetry.d.ts +17 -1
  67. package/dist/telemetry.mjs +131 -16
  68. package/dist/telemetry.mjs.map +1 -1
  69. package/dist/{types-BA53dd8S.d.cts → types-CQAfwqUS.d.cts} +172 -8
  70. package/dist/{types-BA53dd8S.d.ts → types-CQAfwqUS.d.ts} +172 -8
  71. package/dist/usage.cjs +61 -15
  72. package/dist/usage.cjs.map +1 -1
  73. package/dist/usage.d.cts +1 -1
  74. package/dist/usage.d.ts +1 -1
  75. package/dist/usage.mjs +61 -15
  76. package/dist/usage.mjs.map +1 -1
  77. package/dist/webhooks.cjs +316 -0
  78. package/dist/webhooks.cjs.map +1 -0
  79. package/dist/webhooks.d.cts +1 -0
  80. package/dist/webhooks.d.ts +1 -0
  81. package/dist/webhooks.mjs +312 -0
  82. package/dist/webhooks.mjs.map +1 -0
  83. package/package.json +22 -6
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/telemetry.ts"],"names":[],"mappings":"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","file":"telemetry.mjs","sourcesContent":["/**\n * Erros tipados do SDK.\n *\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\n * por `.code` (string estável) sem parsing de message.\n */\n\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\nexport type NeetruErrorCode =\n | 'invalid_config'\n | 'missing_api_key'\n | 'unauthorized'\n | 'forbidden'\n | 'not_found'\n | 'rate_limited'\n | 'validation_failed'\n | 'network_error'\n | 'invalid_response'\n | 'server_error'\n | 'unknown';\n\n/**\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\n *\n * @example\n * ```ts\n * try { await client.catalog.list(); }\n * catch (e) {\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\n * }\n * ```\n */\nexport class NeetruError extends Error {\n public readonly code: NeetruErrorCode | string;\n public readonly status?: number;\n public readonly requestId?: string;\n\n constructor(\n code: NeetruErrorCode | string,\n message: string,\n status?: number,\n requestId?: string,\n ) {\n super(message);\n this.name = 'NeetruError';\n this.code = code;\n this.status = status;\n this.requestId = requestId;\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\n Object.setPrototypeOf(this, NeetruError.prototype);\n }\n}\n","/**\n * HTTP transport interno do SDK.\n *\n * Responsabilidades:\n * - Construir URL absoluta a partir de `baseUrl` + path\n * - Injetar Bearer token quando `requireAuth=true`\n * - Mapear status HTTP → `NeetruError` com `code` estável\n * - Parse defensivo de JSON (não lança em body vazio em 204)\n *\n * Não faz retry/backoff em v0.1 (carry-over Sprint 3+).\n */\nimport { NeetruError, type NeetruErrorCode } from './errors';\nimport type { ResolvedConfig } from './types';\n\n/** Opções da request HTTP. */\nexport interface HttpRequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n /** Path relativo (ex: `/api/v1/cli/catalog`). Concatenado a `baseUrl`. */\n path: string;\n /** Query string params (chave → valor primitivo). Valores `undefined` ignorados. */\n query?: Record<string, string | number | boolean | undefined>;\n /** Body JSON-serializável. Ignorado em GET/DELETE. */\n body?: unknown;\n /**\n * Se true, injeta `Authorization: Bearer <apiKey>`. Lança `missing_api_key`\n * se config.apiKey ausente. Default false.\n */\n requireAuth?: boolean;\n /** Cabeçalhos extras. */\n headers?: Record<string, string>;\n}\n\n/** Mapeamento status → code estável do NeetruError. */\nfunction statusToCode(status: number): NeetruErrorCode {\n if (status === 401) return 'unauthorized';\n if (status === 403) return 'forbidden';\n if (status === 404) return 'not_found';\n if (status === 422 || status === 400) return 'validation_failed';\n if (status === 429) return 'rate_limited';\n if (status >= 500) return 'server_error';\n return 'unknown';\n}\n\nfunction buildUrl(baseUrl: string, path: string, query?: HttpRequestOptions['query']): string {\n // Trim trailing slash em base e leading em path pra evitar `//`.\n const base = baseUrl.replace(/\\/+$/, '');\n const p = path.startsWith('/') ? path : `/${path}`;\n const url = new URL(`${base}${p}`);\n if (query) {\n for (const [k, v] of Object.entries(query)) {\n if (v === undefined) continue;\n url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n}\n\n/** Parse JSON defensivo — retorna `undefined` em body vazio. */\nasync function safeJson(res: Response): Promise<unknown> {\n const text = await res.text();\n if (!text) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Executa request HTTP. Em sucesso retorna body parseado; em erro lança\n * `NeetruError` com `code` derivado do status.\n */\nexport async function httpRequest<T>(\n config: ResolvedConfig,\n opts: HttpRequestOptions,\n): Promise<T> {\n const method = opts.method ?? 'GET';\n const url = buildUrl(config.baseUrl, opts.path, opts.query);\n\n const headers: Record<string, string> = {\n accept: 'application/json',\n ...opts.headers,\n };\n\n if (opts.requireAuth) {\n if (!config.apiKey) {\n throw new NeetruError(\n 'missing_api_key',\n 'This operation requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.',\n );\n }\n headers.authorization = `Bearer ${config.apiKey}`;\n }\n\n const init: RequestInit = { method, headers };\n if (opts.body !== undefined && method !== 'GET' && method !== 'DELETE') {\n headers['content-type'] = 'application/json';\n init.body = JSON.stringify(opts.body);\n }\n\n let res: Response;\n try {\n res = await config.fetch(url, init);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'fetch failed';\n throw new NeetruError('network_error', `Network error: ${message}`);\n }\n\n const requestId = res.headers.get('x-request-id') ?? res.headers.get('x-correlation-id') ?? undefined;\n\n if (!res.ok) {\n const body = (await safeJson(res)) as { error?: { code?: string; message?: string } | string } | undefined;\n let code: string = statusToCode(res.status);\n let message = `HTTP ${res.status}`;\n if (body && typeof body === 'object' && 'error' in body) {\n const errField = body.error;\n if (typeof errField === 'string') {\n message = errField;\n } else if (errField && typeof errField === 'object') {\n if (typeof errField.code === 'string') code = errField.code;\n if (typeof errField.message === 'string') message = errField.message;\n }\n }\n throw new NeetruError(code, message, res.status, requestId);\n }\n\n const parsed = await safeJson(res);\n // Caller é responsável por validar shape; SDK assume backend correto.\n return parsed as T;\n}\n","/**\n * Telemetria — emite eventos do produto cliente pro Core.\n *\n * Endpoint legacy `event()`:\n * `POST /api/v1/sdk/telemetry/event` — persiste em `usage_events/{id}`.\n *\n * Sprint 6 — `log()`:\n * - Em `NEETRU_ENV=dev`: console.{level} apenas (sem network).\n * - Em `workspace`/`prod`: `POST /sdk/v1/telemetry/log` com Bearer +\n * correlationId injetado.\n *\n * v0.1 sem batching — cada chamada é uma request.\n */\nimport { NeetruError } from './errors';\nimport { httpRequest } from './http';\nimport type {\n ResolvedConfig,\n TelemetryEventAck,\n TelemetryEventInput,\n TelemetryLogAck,\n TelemetryLogInput,\n TelemetryLogLevel,\n} from './types';\n\ninterface RawTelemetryAck {\n ok?: boolean;\n eventId?: string;\n}\n\ninterface RawLogAck {\n ok?: boolean;\n logId?: string;\n}\n\nconst VALID_LOG_LEVELS: readonly TelemetryLogLevel[] = ['debug', 'info', 'warn', 'error', 'fatal'];\n\nfunction consoleFor(level: TelemetryLogLevel): (message?: unknown, ...optional: unknown[]) => void {\n switch (level) {\n case 'debug': return console.debug.bind(console);\n case 'info': return console.info.bind(console);\n case 'warn': return console.warn.bind(console);\n case 'error': return console.error.bind(console);\n case 'fatal': return console.error.bind(console);\n default: return console.log.bind(console);\n }\n}\n\nexport function createTelemetryNamespace(config: ResolvedConfig) {\n return {\n /**\n * Persiste um evento de uso. Lança `NeetruError` em qualquer falha\n * (incluindo rate-limit).\n *\n * @example\n * ```ts\n * await client.telemetry.event({\n * name: 'dashboard_opened',\n * properties: { plan: 'pro', tab: 'overview' },\n * });\n * ```\n */\n async event(input: TelemetryEventInput): Promise<TelemetryEventAck> {\n if (!input || typeof input !== 'object') {\n throw new NeetruError('validation_failed', 'event input is required');\n }\n if (typeof input.name !== 'string' || input.name.length === 0) {\n throw new NeetruError('validation_failed', 'event.name is required');\n }\n if (input.name.length > 128) {\n throw new NeetruError('validation_failed', 'event.name max 128 chars');\n }\n\n const body: Record<string, unknown> = { name: input.name };\n if (input.properties && typeof input.properties === 'object') {\n body.properties = input.properties;\n }\n if (input.timestamp) body.timestamp = input.timestamp;\n\n const raw = await httpRequest<RawTelemetryAck>(config, {\n method: 'POST',\n path: '/api/v1/sdk/telemetry/event',\n body,\n requireAuth: true,\n });\n\n if (!raw || raw.ok !== true || typeof raw.eventId !== 'string') {\n throw new NeetruError('invalid_response', 'Telemetry response missing eventId');\n }\n return { ok: true, eventId: raw.eventId };\n },\n\n /**\n * Registra um log estruturado per-product (Sprint 6).\n *\n * - `NEETRU_ENV=dev`: console.{level}, retorna ack mock.\n * - workspace/prod: HTTP POST com Bearer auth + correlationId no header.\n *\n * @example\n * ```ts\n * await client.telemetry.log({\n * level: 'error',\n * message: 'Falha ao calcular total',\n * metadata: { orderId: 'o-123' },\n * });\n * ```\n */\n async log(input: TelemetryLogInput): Promise<TelemetryLogAck> {\n if (!input || typeof input !== 'object') {\n throw new NeetruError('validation_failed', 'log input is required');\n }\n if (!VALID_LOG_LEVELS.includes(input.level)) {\n throw new NeetruError('validation_failed', `level must be one of ${VALID_LOG_LEVELS.join(', ')}`);\n }\n if (typeof input.message !== 'string' || input.message.length === 0) {\n throw new NeetruError('validation_failed', 'message is required');\n }\n if (input.message.length > 4_000) {\n throw new NeetruError('validation_failed', 'message max 4000 chars');\n }\n\n // Dev mode: console only, no network.\n if (config.env === 'dev') {\n const fn = consoleFor(input.level);\n fn(`[neetru-sdk] ${input.level}: ${input.message}`, input.metadata ?? {});\n return { ok: true, mode: 'mock' };\n }\n\n const body: Record<string, unknown> = {\n level: input.level,\n message: input.message,\n };\n if (input.metadata) body.metadata = input.metadata;\n if (input.productSlug) body.productSlug = input.productSlug;\n\n // CorrelationId: explicit input wins; senão tenta lê de globalThis (set\n // por instrumentação do consumer).\n let cid = input.correlationId;\n if (!cid) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const g = (globalThis as any).NEETRU_CORRELATION_ID;\n if (typeof g === 'string' && g.length > 0) cid = g;\n } catch {\n /* ignore */\n }\n }\n\n const headers: Record<string, string> = {};\n if (cid) headers['x-correlation-id'] = cid;\n\n const raw = await httpRequest<RawLogAck>(config, {\n method: 'POST',\n path: '/sdk/v1/telemetry/log',\n body,\n requireAuth: true,\n headers,\n });\n\n if (!raw || raw.ok !== true) {\n throw new NeetruError('invalid_response', 'Telemetry log response missing ok');\n }\n return {\n ok: true,\n logId: typeof raw.logId === 'string' ? raw.logId : undefined,\n mode: 'http',\n };\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/telemetry.ts"],"names":["err","message"],"mappings":"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","file":"telemetry.mjs","sourcesContent":["/**\n * Erros tipados do SDK.\n *\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\n * por `.code` (string estável) sem parsing de message.\n */\n\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\nexport type NeetruErrorCode =\n | 'invalid_config'\n | 'missing_api_key'\n | 'unauthorized'\n | 'forbidden'\n | 'not_found'\n | 'rate_limited'\n | 'validation_failed'\n | 'network_error'\n | 'invalid_response'\n | 'server_error'\n | 'unknown';\n\n/**\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\n *\n * @example\n * ```ts\n * try { await client.catalog.list(); }\n * catch (e) {\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\n * }\n * ```\n */\nexport class NeetruError extends Error {\n public readonly code: NeetruErrorCode | string;\n public readonly status?: number;\n public readonly requestId?: string;\n\n constructor(\n code: NeetruErrorCode | string,\n message: string,\n status?: number,\n requestId?: string,\n ) {\n super(message);\n this.name = 'NeetruError';\n this.code = code;\n this.status = status;\n this.requestId = requestId;\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\n Object.setPrototypeOf(this, NeetruError.prototype);\n }\n}\n","/**\n * HTTP transport interno do SDK.\n *\n * Responsabilidades:\n * - Construir URL absoluta a partir de `baseUrl` + path\n * - Injetar Bearer token quando `requireAuth=true`\n * - Mapear status HTTP → `NeetruError` com `code` estável\n * - Parse defensivo de JSON (não lança em body vazio em 204)\n * - Retry/backoff exponencial em `rate_limited` (429), `server_error` (5xx)\n * e `network_error` (timeout/falha de rede). Honra `Retry-After` quando\n * presente. Default 2 retries (3 tentativas no total). Caller opta-out\n * com `retries: 0`.\n */\nimport { NeetruError, type NeetruErrorCode } from './errors';\nimport type { ResolvedConfig } from './types';\n\n/** Opções da request HTTP. */\nexport interface HttpRequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n /** Path relativo (ex: `/api/v1/cli/catalog`). Concatenado a `baseUrl`. */\n path: string;\n /** Query string params (chave → valor primitivo). Valores `undefined` ignorados. */\n query?: Record<string, string | number | boolean | undefined>;\n /** Body JSON-serializável. Ignorado em GET/DELETE. */\n body?: unknown;\n /**\n * Se true, injeta `Authorization: Bearer <apiKey>`. Lança `missing_api_key`\n * se config.apiKey ausente. Default false.\n */\n requireAuth?: boolean;\n /** Cabeçalhos extras. */\n headers?: Record<string, string>;\n /**\n * Número de retries em códigos transientes (`rate_limited`, `server_error`,\n * `network_error`). Default 2 (= 3 tentativas total). Caller passa `0` pra\n * desativar (útil em operações não-idempotentes específicas).\n */\n retries?: number;\n}\n\nconst DEFAULT_RETRIES = 2;\nconst RETRYABLE_CODES = new Set<NeetruErrorCode>([\n 'rate_limited',\n 'server_error',\n 'network_error',\n]);\n\n/** Backoff exponencial com jitter ±20%. attempt: 0=primeira, 1=primeiro retry, ... */\nfunction backoffMs(attempt: number): number {\n const base = 200 * Math.pow(4, attempt); // 200ms, 800ms, 3.2s, ...\n const jitter = base * 0.2 * (Math.random() * 2 - 1);\n return Math.max(50, Math.round(base + jitter));\n}\n\n/**\n * Honra `Retry-After` header (segundos ou HTTP-date). Retorna ms ou null se\n * inválido. RFC 9110 §10.2.3.\n */\nfunction parseRetryAfter(value: string | null): number | null {\n if (!value) return null;\n const secs = Number(value);\n if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1000);\n const dateMs = Date.parse(value);\n if (Number.isFinite(dateMs)) {\n const delta = dateMs - Date.now();\n if (delta > 0) return delta;\n }\n return null;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Mapeamento status → code estável do NeetruError. */\nfunction statusToCode(status: number): NeetruErrorCode {\n if (status === 401) return 'unauthorized';\n if (status === 403) return 'forbidden';\n if (status === 404) return 'not_found';\n if (status === 422 || status === 400) return 'validation_failed';\n if (status === 429) return 'rate_limited';\n if (status >= 500) return 'server_error';\n return 'unknown';\n}\n\nfunction buildUrl(baseUrl: string, path: string, query?: HttpRequestOptions['query']): string {\n // Trim trailing slash em base e leading em path pra evitar `//`.\n const base = baseUrl.replace(/\\/+$/, '');\n const p = path.startsWith('/') ? path : `/${path}`;\n const url = new URL(`${base}${p}`);\n if (query) {\n for (const [k, v] of Object.entries(query)) {\n if (v === undefined) continue;\n url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n}\n\n/** Parse JSON defensivo — retorna `undefined` em body vazio. */\nasync function safeJson(res: Response): Promise<unknown> {\n const text = await res.text();\n if (!text) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Executa request HTTP. Em sucesso retorna body parseado; em erro lança\n * `NeetruError` com `code` derivado do status. Aplica retry/backoff\n * automático em códigos transientes (rate_limited/server_error/network_error)\n * conforme `opts.retries` (default 2 = 3 tentativas).\n */\nexport async function httpRequest<T>(\n config: ResolvedConfig,\n opts: HttpRequestOptions,\n): Promise<T> {\n const method = opts.method ?? 'GET';\n const url = buildUrl(config.baseUrl, opts.path, opts.query);\n const maxRetries = opts.retries ?? DEFAULT_RETRIES;\n\n const headers: Record<string, string> = {\n accept: 'application/json',\n ...opts.headers,\n };\n\n if (opts.requireAuth) {\n if (!config.apiKey) {\n throw new NeetruError(\n 'missing_api_key',\n 'This operation requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.',\n );\n }\n headers.authorization = `Bearer ${config.apiKey}`;\n }\n\n // Body só é serializado uma vez — reusado entre tentativas.\n const bodyString =\n opts.body !== undefined && method !== 'GET' && method !== 'DELETE'\n ? JSON.stringify(opts.body)\n : undefined;\n if (bodyString !== undefined) {\n headers['content-type'] = 'application/json';\n }\n\n let lastError: NeetruError | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const init: RequestInit = { method, headers };\n if (bodyString !== undefined) init.body = bodyString;\n // BUG-020 fix (2026-05-13): timeout default 30s. AbortSignal.timeout\n // requer Node 18+ ou browsers recentes.\n init.signal = AbortSignal.timeout(30_000);\n\n let res: Response;\n try {\n res = await config.fetch(url, init);\n } catch (err) {\n const message =\n err instanceof DOMException && err.name === 'TimeoutError'\n ? 'Network error: timeout after 30s'\n : `Network error: ${err instanceof Error ? err.message : 'fetch failed'}`;\n lastError = new NeetruError('network_error', message);\n if (attempt < maxRetries) {\n await sleep(backoffMs(attempt));\n continue;\n }\n throw lastError;\n }\n\n const requestId =\n res.headers.get('x-request-id') ?? res.headers.get('x-correlation-id') ?? undefined;\n\n if (res.ok) {\n const parsed = await safeJson(res);\n return parsed as T;\n }\n\n const body = (await safeJson(res)) as\n | { error?: { code?: string; message?: string } | string }\n | undefined;\n let code: string = statusToCode(res.status);\n let message = `HTTP ${res.status}`;\n if (body && typeof body === 'object' && 'error' in body) {\n const errField = body.error;\n if (typeof errField === 'string') {\n message = errField;\n } else if (errField && typeof errField === 'object') {\n if (typeof errField.code === 'string') code = errField.code;\n if (typeof errField.message === 'string') message = errField.message;\n }\n }\n const err = new NeetruError(code, message, res.status, requestId);\n lastError = err;\n\n const isRetryable = RETRYABLE_CODES.has(code as NeetruErrorCode);\n if (isRetryable && attempt < maxRetries) {\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\n const delay = retryAfter ?? backoffMs(attempt);\n await sleep(delay);\n continue;\n }\n throw err;\n }\n\n // Unreachable — loop sempre retorna ou lança. Safety net.\n throw lastError ?? new NeetruError('unknown', 'unexpected httpRequest exit');\n}\n","/**\n * Telemetria — emite eventos do produto cliente pro Core.\n *\n * APIs disponíveis:\n * - `event(input)` — chamada single-shot, await retorna { ok, eventId }.\n * `POST /api/v1/sdk/telemetry/event` — persiste em `usage_events/{id}`.\n * - `track(input)` — fire-and-forget (v1.2). Enqueue + flush 500ms debounce.\n * Reusa o mesmo endpoint mas não bloqueia o caller — ideal pra alta\n * frequência (cliques, page-views). Falhas viram warning no console.\n * - `flush()` — força flush imediato da queue (chamar antes de unload).\n * - `log(input)` — log estruturado `POST /api/sdk/v1/telemetry/log` com\n * Bearer + correlationId. Em `NEETRU_ENV=dev` cai pra console.{level}.\n */\nimport { NeetruError } from './errors';\nimport { httpRequest } from './http';\nimport type {\n ResolvedConfig,\n TelemetryEventAck,\n TelemetryEventInput,\n TelemetryLogAck,\n TelemetryLogInput,\n TelemetryLogLevel,\n} from './types';\n\ninterface RawTelemetryAck {\n ok?: boolean;\n eventId?: string;\n}\n\ninterface RawLogAck {\n ok?: boolean;\n logId?: string;\n}\n\nconst VALID_LOG_LEVELS: readonly TelemetryLogLevel[] = ['debug', 'info', 'warn', 'error', 'fatal'];\n\nfunction consoleFor(level: TelemetryLogLevel): (message?: unknown, ...optional: unknown[]) => void {\n switch (level) {\n case 'debug': return console.debug.bind(console);\n case 'info': return console.info.bind(console);\n case 'warn': return console.warn.bind(console);\n case 'error': return console.error.bind(console);\n case 'fatal': return console.error.bind(console);\n default: return console.log.bind(console);\n }\n}\n\n/** Janela de debounce do `track()` antes de drenar a queue. */\nconst TRACK_FLUSH_MS = 500;\n/** Limite de eventos na queue antes de flush forçado (defensivo). */\nconst TRACK_MAX_QUEUE = 50;\n\nexport function createTelemetryNamespace(config: ResolvedConfig) {\n // Queue local pra track() — fire-and-forget batchado.\n const queue: TelemetryEventInput[] = [];\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n async function drainQueue(): Promise<void> {\n if (queue.length === 0) return;\n const batch = queue.splice(0, queue.length);\n flushTimer = null;\n await Promise.allSettled(\n batch.map(async (ev) => {\n try {\n const body: Record<string, unknown> = { name: ev.name };\n if (ev.properties && typeof ev.properties === 'object') {\n body.properties = ev.properties;\n }\n if (ev.timestamp) body.timestamp = ev.timestamp;\n await httpRequest<RawTelemetryAck>(config, {\n method: 'POST',\n path: '/api/v1/sdk/telemetry/event',\n body,\n requireAuth: true,\n retries: 1,\n });\n } catch (err) {\n if (typeof console !== 'undefined') {\n console.warn('[neetru-sdk] telemetry.track flush failed for event', ev.name, err);\n }\n }\n }),\n );\n }\n\n function scheduleFlush(): void {\n if (flushTimer) return;\n flushTimer = setTimeout(() => {\n void drainQueue();\n }, TRACK_FLUSH_MS);\n }\n\n return {\n /**\n * Persiste um evento de uso. Lança `NeetruError` em qualquer falha\n * (incluindo rate-limit).\n *\n * @example\n * ```ts\n * await client.telemetry.event({\n * name: 'dashboard_opened',\n * properties: { plan: 'pro', tab: 'overview' },\n * });\n * ```\n */\n async event(input: TelemetryEventInput): Promise<TelemetryEventAck> {\n if (!input || typeof input !== 'object') {\n throw new NeetruError('validation_failed', 'event input is required');\n }\n if (typeof input.name !== 'string' || input.name.length === 0) {\n throw new NeetruError('validation_failed', 'event.name is required');\n }\n if (input.name.length > 128) {\n throw new NeetruError('validation_failed', 'event.name max 128 chars');\n }\n\n const body: Record<string, unknown> = { name: input.name };\n if (input.properties && typeof input.properties === 'object') {\n body.properties = input.properties;\n }\n if (input.timestamp) body.timestamp = input.timestamp;\n\n const raw = await httpRequest<RawTelemetryAck>(config, {\n method: 'POST',\n path: '/api/v1/sdk/telemetry/event',\n body,\n requireAuth: true,\n });\n\n if (!raw || raw.ok !== true || typeof raw.eventId !== 'string') {\n throw new NeetruError('invalid_response', 'Telemetry response missing eventId');\n }\n return { ok: true, eventId: raw.eventId };\n },\n\n /**\n * Fire-and-forget: enqueue + flush 500ms debounce. Não retorna `eventId`\n * — falhas são logadas como warning. Ideal pra alta frequência.\n *\n * @example\n * ```ts\n * client.telemetry.track({ name: 'page_view', properties: { path: '/' } });\n * // segue execução; flush async em background\n * ```\n */\n track(input: TelemetryEventInput): void {\n if (!input || typeof input !== 'object') return;\n if (typeof input.name !== 'string' || input.name.length === 0) return;\n if (input.name.length > 128) return;\n queue.push(input);\n if (queue.length >= TRACK_MAX_QUEUE) {\n void drainQueue();\n } else {\n scheduleFlush();\n }\n },\n\n /**\n * Força flush imediato da queue de `track()`. Resolva antes de\n * page unload / SSR boundary pra não perder eventos.\n */\n async flush(): Promise<void> {\n if (flushTimer) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n await drainQueue();\n },\n\n /**\n * Registra um log estruturado per-product (Sprint 6).\n *\n * - `NEETRU_ENV=dev`: console.{level}, retorna ack mock.\n * - workspace/prod: HTTP POST com Bearer auth + correlationId no header.\n *\n * @example\n * ```ts\n * await client.telemetry.log({\n * level: 'error',\n * message: 'Falha ao calcular total',\n * metadata: { orderId: 'o-123' },\n * });\n * ```\n */\n async log(input: TelemetryLogInput): Promise<TelemetryLogAck> {\n if (!input || typeof input !== 'object') {\n throw new NeetruError('validation_failed', 'log input is required');\n }\n if (!VALID_LOG_LEVELS.includes(input.level)) {\n throw new NeetruError('validation_failed', `level must be one of ${VALID_LOG_LEVELS.join(', ')}`);\n }\n if (typeof input.message !== 'string' || input.message.length === 0) {\n throw new NeetruError('validation_failed', 'message is required');\n }\n if (input.message.length > 4_000) {\n throw new NeetruError('validation_failed', 'message max 4000 chars');\n }\n\n // Dev mode: console only, no network.\n if (config.env === 'dev') {\n const fn = consoleFor(input.level);\n fn(`[neetru-sdk] ${input.level}: ${input.message}`, input.metadata ?? {});\n return { ok: true, mode: 'mock' };\n }\n\n const body: Record<string, unknown> = {\n level: input.level,\n message: input.message,\n };\n if (input.metadata) body.metadata = input.metadata;\n if (input.productSlug) body.productSlug = input.productSlug;\n\n // CorrelationId: explicit input wins; senão tenta lê de globalThis (set\n // por instrumentação do consumer).\n let cid = input.correlationId;\n if (!cid) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const g = (globalThis as any).NEETRU_CORRELATION_ID;\n if (typeof g === 'string' && g.length > 0) cid = g;\n } catch {\n /* ignore */\n }\n }\n\n const headers: Record<string, string> = {};\n if (cid) headers['x-correlation-id'] = cid;\n\n const raw = await httpRequest<RawLogAck>(config, {\n method: 'POST',\n path: '/api/sdk/v1/telemetry/log',\n body,\n requireAuth: true,\n headers,\n });\n\n if (!raw || raw.ok !== true) {\n throw new NeetruError('invalid_response', 'Telemetry log response missing ok');\n }\n return {\n ok: true,\n logId: typeof raw.logId === 'string' ? raw.logId : undefined,\n mode: 'http',\n };\n },\n };\n}\n"]}
@@ -78,6 +78,156 @@ declare class MockCheckout implements CheckoutNamespace {
78
78
  }
79
79
  declare function createCheckoutNamespace(config: ResolvedConfig): CheckoutNamespace;
80
80
 
81
+ type ProductNotificationSeverity = 'info' | 'success' | 'warning' | 'error';
82
+ interface ProductNotification {
83
+ id: string;
84
+ /** UID do usuário final (do produto, não staff Neetru). */
85
+ userId: string;
86
+ /** Identificador semântico do evento (ex: `order.received`). */
87
+ kind: string;
88
+ severity: ProductNotificationSeverity;
89
+ title: string;
90
+ body?: string;
91
+ /** Link opcional pra ação. */
92
+ link?: string;
93
+ /** Metadata livre (serializável). */
94
+ metadata?: Record<string, string | number | boolean | null>;
95
+ createdAt: string;
96
+ /** ISO quando user marcou lida. */
97
+ readAt?: string;
98
+ /** ISO quando user descartou. */
99
+ dismissedAt?: string;
100
+ }
101
+ interface SendNotificationInput {
102
+ userId: string;
103
+ kind: string;
104
+ title: string;
105
+ severity?: ProductNotificationSeverity;
106
+ body?: string;
107
+ link?: string;
108
+ metadata?: Record<string, string | number | boolean | null>;
109
+ /**
110
+ * Dedup — se já existir notificação com mesmo fingerprint dentro de 24h,
111
+ * NÃO cria duplicata. Útil pra evitar spam quando webhook reentrega.
112
+ */
113
+ fingerprint?: string;
114
+ }
115
+ interface ListNotificationsOptions {
116
+ /** Inclui notificações dismissed (default false). */
117
+ includeDismissed?: boolean;
118
+ /** Filtro por unread. */
119
+ onlyUnread?: boolean;
120
+ /** Máx itens (default 50, máx 200). */
121
+ limit?: number;
122
+ }
123
+ interface NotificationsNamespace {
124
+ /** Produto envia uma notificação pra um usuário do produto. */
125
+ send(input: SendNotificationInput): Promise<ProductNotification>;
126
+ /** Lista notificações de um usuário. */
127
+ list(userId: string, options?: ListNotificationsOptions): Promise<ProductNotification[]>;
128
+ /** Marca como lida. */
129
+ markRead(id: string): Promise<{
130
+ ok: true;
131
+ }>;
132
+ /** Descarta. */
133
+ dismiss(id: string): Promise<{
134
+ ok: true;
135
+ }>;
136
+ }
137
+ declare function createNotificationsNamespace(config: ResolvedConfig): NotificationsNamespace;
138
+ declare class MockNotifications implements NotificationsNamespace {
139
+ private notifications;
140
+ private nextId;
141
+ send(input: SendNotificationInput): Promise<ProductNotification>;
142
+ list(userId: string, options?: ListNotificationsOptions): Promise<ProductNotification[]>;
143
+ markRead(id: string): Promise<{
144
+ ok: true;
145
+ }>;
146
+ dismiss(id: string): Promise<{
147
+ ok: true;
148
+ }>;
149
+ }
150
+
151
+ /** Eventos Neetru que produtos podem assinar. Lista expansível por minor bump. */
152
+ type WebhookEvent = 'subscription.activated' | 'subscription.cancelled' | 'subscription.payment_failed' | 'subscription.trial_ending' | 'usage.quota_exceeded' | 'account.suspended' | 'account.reactivated' | 'support.ticket_replied';
153
+ interface WebhookEndpoint {
154
+ id: string;
155
+ url: string;
156
+ events: WebhookEvent[];
157
+ /** Quando true, `X-Neetru-Signature` é enviado em cada dispatch. */
158
+ hasSecret: boolean;
159
+ status: 'active' | 'degraded' | 'disabled';
160
+ /** ISO timestamp do último dispatch bem-sucedido. */
161
+ lastDeliveryAt?: string;
162
+ /** Quantos dispatches falharam consecutivos (resetado em sucesso). */
163
+ consecutiveFailures?: number;
164
+ createdAt: string;
165
+ }
166
+ interface RegisterWebhookInput {
167
+ url: string;
168
+ events: WebhookEvent[];
169
+ /**
170
+ * Secret pra HMAC SHA-256 (mín 16 chars). Recomendado.
171
+ * Quando ausente, dispatches vão sem assinatura — produto deve ter
172
+ * IP allowlist ou outra defesa.
173
+ */
174
+ secret?: string;
175
+ }
176
+ interface WebhookTestResult {
177
+ ok: boolean;
178
+ statusCode?: number;
179
+ durationMs?: number;
180
+ error?: string;
181
+ }
182
+ interface WebhooksNamespace {
183
+ /** Registra um novo endpoint. */
184
+ register(input: RegisterWebhookInput): Promise<WebhookEndpoint>;
185
+ /** Lista endpoints registrados pelo produto. */
186
+ list(): Promise<WebhookEndpoint[]>;
187
+ /** Remove um endpoint. */
188
+ unregister(id: string): Promise<{
189
+ ok: true;
190
+ }>;
191
+ /** Dispara evento de teste pra validar conectividade. */
192
+ test(id: string): Promise<WebhookTestResult>;
193
+ }
194
+ /**
195
+ * Verifica assinatura HMAC SHA-256 de payload de webhook recebido pelo
196
+ * produto consumer. Constant-time compare pra resistir a timing attack.
197
+ *
198
+ * @param payload Corpo cru da request (string ou Buffer). NÃO use o objeto
199
+ * parseado — JSON.stringify pode diferir do que foi assinado.
200
+ * @param signature Header `X-Neetru-Signature` recebido (formato `sha256=<hex>`).
201
+ * @param secret Secret registrado em `webhooks.register({ secret })`.
202
+ * @returns true se assinatura confere, false caso contrário.
203
+ *
204
+ * @example
205
+ * ```ts
206
+ * // Express handler
207
+ * app.post('/webhooks/neetru', express.raw({ type: 'application/json' }), (req, res) => {
208
+ * const sig = req.header('X-Neetru-Signature');
209
+ * if (!verifyWebhookSignature(req.body, sig, process.env.WEBHOOK_SECRET!)) {
210
+ * return res.status(401).end();
211
+ * }
212
+ * const event = JSON.parse(req.body.toString('utf8'));
213
+ * // ... handle event
214
+ * res.json({ ok: true });
215
+ * });
216
+ * ```
217
+ */
218
+ declare function verifyWebhookSignature(payload: string | Uint8Array, signature: string | null | undefined, secret: string): boolean;
219
+ declare function createWebhooksNamespace(config: ResolvedConfig): WebhooksNamespace;
220
+ declare class MockWebhooks implements WebhooksNamespace {
221
+ private endpoints;
222
+ private nextId;
223
+ register(input: RegisterWebhookInput): Promise<WebhookEndpoint>;
224
+ list(): Promise<WebhookEndpoint[]>;
225
+ unregister(id: string): Promise<{
226
+ ok: true;
227
+ }>;
228
+ test(id: string): Promise<WebhookTestResult>;
229
+ }
230
+
81
231
  /**
82
232
  * Tipos públicos do SDK Neetru.
83
233
  *
@@ -126,6 +276,8 @@ interface NeetruClientConfig {
126
276
  support?: SupportNamespace;
127
277
  entitlements?: NeetruClient['entitlements'];
128
278
  db?: DbNamespace;
279
+ webhooks?: WebhooksNamespace;
280
+ notifications?: NotificationsNamespace;
129
281
  };
130
282
  /**
131
283
  * v0.3 — productId default usado por `usage.report()` / `usage.check()` /
@@ -251,25 +403,33 @@ interface NeetruClient {
251
403
  /** Busca produto único por slug. */
252
404
  get(slug: string): Promise<Product>;
253
405
  };
254
- /** Namespace entitlements. */
406
+ /** Namespace entitlements (v1.2: cache LRU 60s TTL). */
255
407
  readonly entitlements: {
256
408
  /**
257
409
  * Verifica se o portador da apiKey pode usar `feature` do produto `slug`.
258
- * Retorna boolean por contrato simplificado v0.1.
410
+ * Cacheado 60s. `{ cacheBust: true }` força ida ao servidor.
259
411
  */
260
- check(productSlug: string, feature: string): Promise<boolean>;
412
+ check(productSlug: string, feature: string, opts?: {
413
+ cacheBust?: boolean;
414
+ }): Promise<boolean>;
261
415
  /** Variante que retorna o objeto completo com `reason`. */
262
- checkDetailed(productSlug: string, feature: string): Promise<EntitlementCheck>;
416
+ checkDetailed(productSlug: string, feature: string, opts?: {
417
+ cacheBust?: boolean;
418
+ }): Promise<EntitlementCheck>;
263
419
  };
264
- /** Namespace telemetria. */
420
+ /** Namespace telemetria (v1.2: track fire-and-forget + flush). */
265
421
  readonly telemetry: {
266
- /** Persiste um evento. Não lança em rate-limit não-fatal — relança outros erros. */
422
+ /** Persiste um evento single-shot. await retorna { ok, eventId }. */
267
423
  event(input: TelemetryEventInput): Promise<TelemetryEventAck>;
424
+ /** Fire-and-forget: enqueue + flush 500ms debounce. Sem retorno. */
425
+ track(input: TelemetryEventInput): void;
426
+ /** Força flush da queue do track() (chamar antes de unload). */
427
+ flush(): Promise<void>;
268
428
  /**
269
429
  * Registra um log estruturado per-product (Sprint 6).
270
430
  *
271
431
  * - Em `NEETRU_ENV=dev`: apenas console.{level} (sem network).
272
- * - Em `workspace`/`prod`: POST `/sdk/v1/telemetry/log` com Bearer + correlationId.
432
+ * - Em `workspace`/`prod`: POST `/api/sdk/v1/telemetry/log` com Bearer + correlationId.
273
433
  */
274
434
  log(input: TelemetryLogInput): Promise<TelemetryLogAck>;
275
435
  };
@@ -281,6 +441,10 @@ interface NeetruClient {
281
441
  readonly db: DbNamespace;
282
442
  /** Namespace checkout (v1.1 — start/get/cancel intent + auto-redirect). */
283
443
  readonly checkout: CheckoutNamespace;
444
+ /** Namespace webhooks (v1.2 — register/list/unregister/test). */
445
+ readonly webhooks: WebhooksNamespace;
446
+ /** Namespace notifications (v1.2 — send/list/markRead/dismiss). */
447
+ readonly notifications: NotificationsNamespace;
284
448
  }
285
449
  /**
286
450
  * User retornado pelo OIDC ID token. Schema neutro — não vaza Firebase
@@ -487,4 +651,4 @@ interface CatalogListOptions {
487
651
  includeDrafts?: boolean;
488
652
  }
489
653
 
490
- export { type AuthNamespace as A, type TelemetryLogInput as B, type CatalogListOptions as C, DEFAULT_BASE_URL as D, type EntitlementCheck as E, type TelemetryLogAck as F, MockCheckout as M, type NeetruClientConfig as N, type Product as P, type ResolvedConfig as R, type SignInOptions as S, type TelemetryEventAck as T, type UsageEventInput as U, type NeetruClient as a, type AuthStateListener as b, type CatalogListResponse as c, type CheckoutIntentInfo as d, type CheckoutIntentStatus as e, type CheckoutNamespace as f, type CheckoutStartInput as g, type CheckoutStartResult as h, type CheckoutTenantType as i, type CreateTicketInput as j, type DbCollectionRef as k, type DbListOptions as l, type DbNamespace as m, type DbWhereFilter as n, type NeetruEnv as o, type NeetruUser as p, type ProductPlan as q, type ProductStatus as r, type SupportNamespace as s, type SupportSeverity as t, type SupportStatus as u, type SupportTicket as v, type TelemetryEventInput as w, type UsageNamespace as x, type UsageQuota as y, createCheckoutNamespace as z };
654
+ export { verifyWebhookSignature as $, type AuthNamespace as A, type SupportSeverity as B, type CatalogListOptions as C, DEFAULT_BASE_URL as D, type EntitlementCheck as E, type SupportStatus as F, type SupportTicket as G, type TelemetryEventInput as H, type UsageNamespace as I, type UsageQuota as J, type WebhookEvent as K, type ListNotificationsOptions as L, MockCheckout as M, type NeetruClientConfig as N, type WebhookTestResult as O, type Product as P, type WebhooksNamespace as Q, type RegisterWebhookInput as R, type SendNotificationInput as S, type TelemetryEventAck as T, type UsageEventInput as U, createCheckoutNamespace as V, type WebhookEndpoint as W, createNotificationsNamespace as X, createWebhooksNamespace as Y, type TelemetryLogInput as Z, type TelemetryLogAck as _, type NeetruClient as a, type AuthStateListener as b, type CatalogListResponse as c, type CheckoutIntentInfo as d, type CheckoutIntentStatus as e, type CheckoutNamespace as f, type CheckoutStartInput as g, type CheckoutStartResult as h, type CheckoutTenantType as i, type CreateTicketInput as j, type DbCollectionRef as k, type DbListOptions as l, type DbNamespace as m, type DbWhereFilter as n, MockNotifications as o, MockWebhooks as p, type NeetruEnv as q, type NeetruUser as r, type NotificationsNamespace as s, type ProductNotification as t, type ProductNotificationSeverity as u, type ProductPlan as v, type ProductStatus as w, type ResolvedConfig as x, type SignInOptions as y, type SupportNamespace as z };
@@ -78,6 +78,156 @@ declare class MockCheckout implements CheckoutNamespace {
78
78
  }
79
79
  declare function createCheckoutNamespace(config: ResolvedConfig): CheckoutNamespace;
80
80
 
81
+ type ProductNotificationSeverity = 'info' | 'success' | 'warning' | 'error';
82
+ interface ProductNotification {
83
+ id: string;
84
+ /** UID do usuário final (do produto, não staff Neetru). */
85
+ userId: string;
86
+ /** Identificador semântico do evento (ex: `order.received`). */
87
+ kind: string;
88
+ severity: ProductNotificationSeverity;
89
+ title: string;
90
+ body?: string;
91
+ /** Link opcional pra ação. */
92
+ link?: string;
93
+ /** Metadata livre (serializável). */
94
+ metadata?: Record<string, string | number | boolean | null>;
95
+ createdAt: string;
96
+ /** ISO quando user marcou lida. */
97
+ readAt?: string;
98
+ /** ISO quando user descartou. */
99
+ dismissedAt?: string;
100
+ }
101
+ interface SendNotificationInput {
102
+ userId: string;
103
+ kind: string;
104
+ title: string;
105
+ severity?: ProductNotificationSeverity;
106
+ body?: string;
107
+ link?: string;
108
+ metadata?: Record<string, string | number | boolean | null>;
109
+ /**
110
+ * Dedup — se já existir notificação com mesmo fingerprint dentro de 24h,
111
+ * NÃO cria duplicata. Útil pra evitar spam quando webhook reentrega.
112
+ */
113
+ fingerprint?: string;
114
+ }
115
+ interface ListNotificationsOptions {
116
+ /** Inclui notificações dismissed (default false). */
117
+ includeDismissed?: boolean;
118
+ /** Filtro por unread. */
119
+ onlyUnread?: boolean;
120
+ /** Máx itens (default 50, máx 200). */
121
+ limit?: number;
122
+ }
123
+ interface NotificationsNamespace {
124
+ /** Produto envia uma notificação pra um usuário do produto. */
125
+ send(input: SendNotificationInput): Promise<ProductNotification>;
126
+ /** Lista notificações de um usuário. */
127
+ list(userId: string, options?: ListNotificationsOptions): Promise<ProductNotification[]>;
128
+ /** Marca como lida. */
129
+ markRead(id: string): Promise<{
130
+ ok: true;
131
+ }>;
132
+ /** Descarta. */
133
+ dismiss(id: string): Promise<{
134
+ ok: true;
135
+ }>;
136
+ }
137
+ declare function createNotificationsNamespace(config: ResolvedConfig): NotificationsNamespace;
138
+ declare class MockNotifications implements NotificationsNamespace {
139
+ private notifications;
140
+ private nextId;
141
+ send(input: SendNotificationInput): Promise<ProductNotification>;
142
+ list(userId: string, options?: ListNotificationsOptions): Promise<ProductNotification[]>;
143
+ markRead(id: string): Promise<{
144
+ ok: true;
145
+ }>;
146
+ dismiss(id: string): Promise<{
147
+ ok: true;
148
+ }>;
149
+ }
150
+
151
+ /** Eventos Neetru que produtos podem assinar. Lista expansível por minor bump. */
152
+ type WebhookEvent = 'subscription.activated' | 'subscription.cancelled' | 'subscription.payment_failed' | 'subscription.trial_ending' | 'usage.quota_exceeded' | 'account.suspended' | 'account.reactivated' | 'support.ticket_replied';
153
+ interface WebhookEndpoint {
154
+ id: string;
155
+ url: string;
156
+ events: WebhookEvent[];
157
+ /** Quando true, `X-Neetru-Signature` é enviado em cada dispatch. */
158
+ hasSecret: boolean;
159
+ status: 'active' | 'degraded' | 'disabled';
160
+ /** ISO timestamp do último dispatch bem-sucedido. */
161
+ lastDeliveryAt?: string;
162
+ /** Quantos dispatches falharam consecutivos (resetado em sucesso). */
163
+ consecutiveFailures?: number;
164
+ createdAt: string;
165
+ }
166
+ interface RegisterWebhookInput {
167
+ url: string;
168
+ events: WebhookEvent[];
169
+ /**
170
+ * Secret pra HMAC SHA-256 (mín 16 chars). Recomendado.
171
+ * Quando ausente, dispatches vão sem assinatura — produto deve ter
172
+ * IP allowlist ou outra defesa.
173
+ */
174
+ secret?: string;
175
+ }
176
+ interface WebhookTestResult {
177
+ ok: boolean;
178
+ statusCode?: number;
179
+ durationMs?: number;
180
+ error?: string;
181
+ }
182
+ interface WebhooksNamespace {
183
+ /** Registra um novo endpoint. */
184
+ register(input: RegisterWebhookInput): Promise<WebhookEndpoint>;
185
+ /** Lista endpoints registrados pelo produto. */
186
+ list(): Promise<WebhookEndpoint[]>;
187
+ /** Remove um endpoint. */
188
+ unregister(id: string): Promise<{
189
+ ok: true;
190
+ }>;
191
+ /** Dispara evento de teste pra validar conectividade. */
192
+ test(id: string): Promise<WebhookTestResult>;
193
+ }
194
+ /**
195
+ * Verifica assinatura HMAC SHA-256 de payload de webhook recebido pelo
196
+ * produto consumer. Constant-time compare pra resistir a timing attack.
197
+ *
198
+ * @param payload Corpo cru da request (string ou Buffer). NÃO use o objeto
199
+ * parseado — JSON.stringify pode diferir do que foi assinado.
200
+ * @param signature Header `X-Neetru-Signature` recebido (formato `sha256=<hex>`).
201
+ * @param secret Secret registrado em `webhooks.register({ secret })`.
202
+ * @returns true se assinatura confere, false caso contrário.
203
+ *
204
+ * @example
205
+ * ```ts
206
+ * // Express handler
207
+ * app.post('/webhooks/neetru', express.raw({ type: 'application/json' }), (req, res) => {
208
+ * const sig = req.header('X-Neetru-Signature');
209
+ * if (!verifyWebhookSignature(req.body, sig, process.env.WEBHOOK_SECRET!)) {
210
+ * return res.status(401).end();
211
+ * }
212
+ * const event = JSON.parse(req.body.toString('utf8'));
213
+ * // ... handle event
214
+ * res.json({ ok: true });
215
+ * });
216
+ * ```
217
+ */
218
+ declare function verifyWebhookSignature(payload: string | Uint8Array, signature: string | null | undefined, secret: string): boolean;
219
+ declare function createWebhooksNamespace(config: ResolvedConfig): WebhooksNamespace;
220
+ declare class MockWebhooks implements WebhooksNamespace {
221
+ private endpoints;
222
+ private nextId;
223
+ register(input: RegisterWebhookInput): Promise<WebhookEndpoint>;
224
+ list(): Promise<WebhookEndpoint[]>;
225
+ unregister(id: string): Promise<{
226
+ ok: true;
227
+ }>;
228
+ test(id: string): Promise<WebhookTestResult>;
229
+ }
230
+
81
231
  /**
82
232
  * Tipos públicos do SDK Neetru.
83
233
  *
@@ -126,6 +276,8 @@ interface NeetruClientConfig {
126
276
  support?: SupportNamespace;
127
277
  entitlements?: NeetruClient['entitlements'];
128
278
  db?: DbNamespace;
279
+ webhooks?: WebhooksNamespace;
280
+ notifications?: NotificationsNamespace;
129
281
  };
130
282
  /**
131
283
  * v0.3 — productId default usado por `usage.report()` / `usage.check()` /
@@ -251,25 +403,33 @@ interface NeetruClient {
251
403
  /** Busca produto único por slug. */
252
404
  get(slug: string): Promise<Product>;
253
405
  };
254
- /** Namespace entitlements. */
406
+ /** Namespace entitlements (v1.2: cache LRU 60s TTL). */
255
407
  readonly entitlements: {
256
408
  /**
257
409
  * Verifica se o portador da apiKey pode usar `feature` do produto `slug`.
258
- * Retorna boolean por contrato simplificado v0.1.
410
+ * Cacheado 60s. `{ cacheBust: true }` força ida ao servidor.
259
411
  */
260
- check(productSlug: string, feature: string): Promise<boolean>;
412
+ check(productSlug: string, feature: string, opts?: {
413
+ cacheBust?: boolean;
414
+ }): Promise<boolean>;
261
415
  /** Variante que retorna o objeto completo com `reason`. */
262
- checkDetailed(productSlug: string, feature: string): Promise<EntitlementCheck>;
416
+ checkDetailed(productSlug: string, feature: string, opts?: {
417
+ cacheBust?: boolean;
418
+ }): Promise<EntitlementCheck>;
263
419
  };
264
- /** Namespace telemetria. */
420
+ /** Namespace telemetria (v1.2: track fire-and-forget + flush). */
265
421
  readonly telemetry: {
266
- /** Persiste um evento. Não lança em rate-limit não-fatal — relança outros erros. */
422
+ /** Persiste um evento single-shot. await retorna { ok, eventId }. */
267
423
  event(input: TelemetryEventInput): Promise<TelemetryEventAck>;
424
+ /** Fire-and-forget: enqueue + flush 500ms debounce. Sem retorno. */
425
+ track(input: TelemetryEventInput): void;
426
+ /** Força flush da queue do track() (chamar antes de unload). */
427
+ flush(): Promise<void>;
268
428
  /**
269
429
  * Registra um log estruturado per-product (Sprint 6).
270
430
  *
271
431
  * - Em `NEETRU_ENV=dev`: apenas console.{level} (sem network).
272
- * - Em `workspace`/`prod`: POST `/sdk/v1/telemetry/log` com Bearer + correlationId.
432
+ * - Em `workspace`/`prod`: POST `/api/sdk/v1/telemetry/log` com Bearer + correlationId.
273
433
  */
274
434
  log(input: TelemetryLogInput): Promise<TelemetryLogAck>;
275
435
  };
@@ -281,6 +441,10 @@ interface NeetruClient {
281
441
  readonly db: DbNamespace;
282
442
  /** Namespace checkout (v1.1 — start/get/cancel intent + auto-redirect). */
283
443
  readonly checkout: CheckoutNamespace;
444
+ /** Namespace webhooks (v1.2 — register/list/unregister/test). */
445
+ readonly webhooks: WebhooksNamespace;
446
+ /** Namespace notifications (v1.2 — send/list/markRead/dismiss). */
447
+ readonly notifications: NotificationsNamespace;
284
448
  }
285
449
  /**
286
450
  * User retornado pelo OIDC ID token. Schema neutro — não vaza Firebase
@@ -487,4 +651,4 @@ interface CatalogListOptions {
487
651
  includeDrafts?: boolean;
488
652
  }
489
653
 
490
- export { type AuthNamespace as A, type TelemetryLogInput as B, type CatalogListOptions as C, DEFAULT_BASE_URL as D, type EntitlementCheck as E, type TelemetryLogAck as F, MockCheckout as M, type NeetruClientConfig as N, type Product as P, type ResolvedConfig as R, type SignInOptions as S, type TelemetryEventAck as T, type UsageEventInput as U, type NeetruClient as a, type AuthStateListener as b, type CatalogListResponse as c, type CheckoutIntentInfo as d, type CheckoutIntentStatus as e, type CheckoutNamespace as f, type CheckoutStartInput as g, type CheckoutStartResult as h, type CheckoutTenantType as i, type CreateTicketInput as j, type DbCollectionRef as k, type DbListOptions as l, type DbNamespace as m, type DbWhereFilter as n, type NeetruEnv as o, type NeetruUser as p, type ProductPlan as q, type ProductStatus as r, type SupportNamespace as s, type SupportSeverity as t, type SupportStatus as u, type SupportTicket as v, type TelemetryEventInput as w, type UsageNamespace as x, type UsageQuota as y, createCheckoutNamespace as z };
654
+ export { verifyWebhookSignature as $, type AuthNamespace as A, type SupportSeverity as B, type CatalogListOptions as C, DEFAULT_BASE_URL as D, type EntitlementCheck as E, type SupportStatus as F, type SupportTicket as G, type TelemetryEventInput as H, type UsageNamespace as I, type UsageQuota as J, type WebhookEvent as K, type ListNotificationsOptions as L, MockCheckout as M, type NeetruClientConfig as N, type WebhookTestResult as O, type Product as P, type WebhooksNamespace as Q, type RegisterWebhookInput as R, type SendNotificationInput as S, type TelemetryEventAck as T, type UsageEventInput as U, createCheckoutNamespace as V, type WebhookEndpoint as W, createNotificationsNamespace as X, createWebhooksNamespace as Y, type TelemetryLogInput as Z, type TelemetryLogAck as _, type NeetruClient as a, type AuthStateListener as b, type CatalogListResponse as c, type CheckoutIntentInfo as d, type CheckoutIntentStatus as e, type CheckoutNamespace as f, type CheckoutStartInput as g, type CheckoutStartResult as h, type CheckoutTenantType as i, type CreateTicketInput as j, type DbCollectionRef as k, type DbListOptions as l, type DbNamespace as m, type DbWhereFilter as n, MockNotifications as o, MockWebhooks as p, type NeetruEnv as q, type NeetruUser as r, type NotificationsNamespace as s, type ProductNotification as t, type ProductNotificationSeverity as u, type ProductPlan as v, type ProductStatus as w, type ResolvedConfig as x, type SignInOptions as y, type SupportNamespace as z };