@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.
- package/CHANGELOG.md +33 -3
- package/README.md +135 -159
- package/dist/auth.cjs +486 -40
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/auth.mjs +486 -40
- package/dist/auth.mjs.map +1 -1
- package/dist/catalog.cjs +64 -21
- package/dist/catalog.cjs.map +1 -1
- package/dist/catalog.d.cts +2 -2
- package/dist/catalog.d.ts +2 -2
- package/dist/catalog.mjs +64 -21
- package/dist/catalog.mjs.map +1 -1
- package/dist/checkout.cjs +61 -15
- package/dist/checkout.cjs.map +1 -1
- package/dist/checkout.d.cts +1 -1
- package/dist/checkout.d.ts +1 -1
- package/dist/checkout.mjs +61 -15
- package/dist/checkout.mjs.map +1 -1
- package/dist/db.cjs +67 -22
- package/dist/db.cjs.map +1 -1
- package/dist/db.d.cts +1 -1
- package/dist/db.d.ts +1 -1
- package/dist/db.mjs +67 -22
- package/dist/db.mjs.map +1 -1
- package/dist/entitlements.cjs +102 -21
- package/dist/entitlements.cjs.map +1 -1
- package/dist/entitlements.d.cts +11 -5
- package/dist/entitlements.d.ts +11 -5
- package/dist/entitlements.mjs +102 -21
- package/dist/entitlements.mjs.map +1 -1
- package/dist/index.cjs +491 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +488 -42
- package/dist/index.mjs.map +1 -1
- package/dist/mocks.cjs +3 -2
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.cts +4 -2
- package/dist/mocks.d.ts +4 -2
- package/dist/mocks.mjs +3 -2
- package/dist/mocks.mjs.map +1 -1
- package/dist/notifications.cjs +296 -0
- package/dist/notifications.cjs.map +1 -0
- package/dist/notifications.d.cts +1 -0
- package/dist/notifications.d.ts +1 -0
- package/dist/notifications.mjs +293 -0
- package/dist/notifications.mjs.map +1 -0
- package/dist/react.cjs +7 -3
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.mjs +7 -3
- package/dist/react.mjs.map +1 -1
- package/dist/support.cjs +61 -15
- package/dist/support.cjs.map +1 -1
- package/dist/support.d.cts +1 -1
- package/dist/support.d.ts +1 -1
- package/dist/support.mjs +61 -15
- package/dist/support.mjs.map +1 -1
- package/dist/telemetry.cjs +131 -16
- package/dist/telemetry.cjs.map +1 -1
- package/dist/telemetry.d.cts +17 -1
- package/dist/telemetry.d.ts +17 -1
- package/dist/telemetry.mjs +131 -16
- package/dist/telemetry.mjs.map +1 -1
- package/dist/{types-BA53dd8S.d.cts → types-CQAfwqUS.d.cts} +172 -8
- package/dist/{types-BA53dd8S.d.ts → types-CQAfwqUS.d.ts} +172 -8
- package/dist/usage.cjs +61 -15
- package/dist/usage.cjs.map +1 -1
- package/dist/usage.d.cts +1 -1
- package/dist/usage.d.ts +1 -1
- package/dist/usage.mjs +61 -15
- package/dist/usage.mjs.map +1 -1
- package/dist/webhooks.cjs +316 -0
- package/dist/webhooks.cjs.map +1 -0
- package/dist/webhooks.d.cts +1 -0
- package/dist/webhooks.d.ts +1 -0
- package/dist/webhooks.mjs +312 -0
- package/dist/webhooks.mjs.map +1 -0
- package/package.json +22 -6
package/dist/db.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/db.ts"],"names":[],"mappings":"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","file":"db.cjs","sourcesContent":["/**\n * Erros tipados do SDK.\n *\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\n * por `.code` (string estável) sem parsing de message.\n */\n\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\nexport type NeetruErrorCode =\n | 'invalid_config'\n | 'missing_api_key'\n | 'unauthorized'\n | 'forbidden'\n | 'not_found'\n | 'rate_limited'\n | 'validation_failed'\n | 'network_error'\n | 'invalid_response'\n | 'server_error'\n | 'unknown';\n\n/**\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\n *\n * @example\n * ```ts\n * try { await client.catalog.list(); }\n * catch (e) {\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\n * }\n * ```\n */\nexport class NeetruError extends Error {\n public readonly code: NeetruErrorCode | string;\n public readonly status?: number;\n public readonly requestId?: string;\n\n constructor(\n code: NeetruErrorCode | string,\n message: string,\n status?: number,\n requestId?: string,\n ) {\n super(message);\n this.name = 'NeetruError';\n this.code = code;\n this.status = status;\n this.requestId = requestId;\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\n Object.setPrototypeOf(this, NeetruError.prototype);\n }\n}\n","/**\n * HTTP transport interno do SDK.\n *\n * Responsabilidades:\n * - Construir URL absoluta a partir de `baseUrl` + path\n * - Injetar Bearer token quando `requireAuth=true`\n * - Mapear status HTTP → `NeetruError` com `code` estável\n * - Parse defensivo de JSON (não lança em body vazio em 204)\n *\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 * Datastore namespace (v0.3.1) — Sprint 8.\n *\n * `client.db.collection(name)` retorna um `DbCollectionRef` que mapeia para\n * `tenant_{tid}_{name}` no Core. Endpoints REST disponíveis (Sprint 8 LIVE):\n * - `GET /sdk/v1/datastore/{collection}?limit&where`\n * - `POST /sdk/v1/datastore/{collection}` (add)\n * - `GET /sdk/v1/datastore/{collection}/{id}`\n * - `PATCH /sdk/v1/datastore/{collection}/{id}` (update merge)\n * - `PUT /sdk/v1/datastore/{collection}/{id}` (set replace)\n * - `DELETE /sdk/v1/datastore/{collection}/{id}`\n *\n * O Core resolve `tenantId` via Bearer token. SDK passa `x-neetru-tenant`\n * pra dar visibilidade explícita; backend valida match com o token.\n *\n * Em dev (NEETRU_ENV=dev), `client.db` é `MockDb` (in-memory).\n */\nimport { httpRequest } from './http';\nimport { NeetruError } from './errors';\nimport type {\n DbCollectionRef,\n DbListOptions,\n DbNamespace,\n DbWhereFilter,\n ResolvedConfig,\n} from './types';\n\nconst COLL_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/;\n\nfunction assertValidCollection(name: string): void {\n if (!COLL_RE.test(name)) {\n throw new NeetruError(\n 'validation_failed',\n `Invalid collection name: \"${name}\". Must match ${COLL_RE}.`,\n );\n }\n}\n\n/** Serializa filtro pro formato `field:op:value` aceito pelo backend. */\nfunction serializeWhere(filter: DbWhereFilter): string {\n const { field, op, value } = filter;\n if (op === 'in') {\n if (!Array.isArray(value)) {\n throw new NeetruError(\n 'validation_failed',\n `where op=\"in\" requer value array (recebido: ${typeof value})`,\n );\n }\n return `${field}:in:${value.map((v) => String(v)).join(',')}`;\n }\n return `${field}:${op}:${String(value)}`;\n}\n\n/**\n * Constrói o namespace `db` real (HTTP) com binding ao tenantId resolvido.\n */\nexport function createDbNamespace(config: ResolvedConfig): DbNamespace {\n return {\n collection(name: string): DbCollectionRef {\n assertValidCollection(name);\n\n const headers: Record<string, string> = {};\n if (config.tenantId) headers['x-neetru-tenant'] = config.tenantId;\n\n return {\n async list<T = Record<string, unknown>>(\n opts?: DbListOptions,\n ): Promise<T[]> {\n const query: Record<string, string | number> = {};\n if (opts?.limit !== undefined) query.limit = opts.limit;\n\n // multi-where → request URL múltiplo `where=...&where=...`. Como\n // `httpRequest.query` é Record<>, monta path manualmente quando há\n // filtros pra preservar repetição da chave.\n let path = `/sdk/v1/datastore/${name}`;\n const params = new URLSearchParams();\n if (opts?.limit !== undefined) params.set('limit', String(opts.limit));\n if (opts?.where && opts.where.length > 0) {\n for (const f of opts.where) {\n params.append('where', serializeWhere(f));\n }\n }\n if (config.tenantId) params.set('tenantId', config.tenantId);\n const qs = params.toString();\n if (qs) path += `?${qs}`;\n\n const raw = await httpRequest<{ items?: unknown[] }>(config, {\n method: 'GET',\n path,\n requireAuth: true,\n headers,\n });\n if (!raw || !Array.isArray(raw.items)) {\n throw new NeetruError(\n 'invalid_response',\n 'datastore.list missing items[]',\n );\n }\n return raw.items as T[];\n },\n\n async get<T = Record<string, unknown>>(id: string): Promise<T | null> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n try {\n const raw = await httpRequest<{ item?: T | null }>(config, {\n method: 'GET',\n path: `/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n requireAuth: true,\n headers,\n });\n return raw?.item ?? null;\n } catch (err) {\n if (err instanceof NeetruError && err.code === 'not_found') return null;\n throw err;\n }\n },\n\n async add(data: Record<string, unknown>): Promise<{ ok: true; id: string }> {\n if (!data || typeof data !== 'object') {\n throw new NeetruError('validation_failed', 'data object required');\n }\n const raw = await httpRequest<{ ok?: boolean; id?: string }>(config, {\n method: 'POST',\n path: `/sdk/v1/datastore/${name}`,\n body: { data },\n requireAuth: true,\n headers,\n });\n if (!raw || typeof raw.id !== 'string') {\n throw new NeetruError('invalid_response', 'datastore.add missing id');\n }\n return { ok: true, id: raw.id };\n },\n\n async set(id: string, data: Record<string, unknown>): Promise<{ ok: true }> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n await httpRequest(config, {\n method: 'PUT',\n path: `/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n body: { data },\n requireAuth: true,\n headers,\n });\n return { ok: true };\n },\n\n async update(id: string, data: Record<string, unknown>): Promise<{ ok: true }> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n await httpRequest(config, {\n method: 'PATCH',\n path: `/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n body: { data },\n requireAuth: true,\n headers,\n });\n return { ok: true };\n },\n\n async remove(id: string): Promise<{ ok: true }> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n await httpRequest(config, {\n method: 'DELETE',\n path: `/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n requireAuth: true,\n headers,\n });\n return { ok: true };\n },\n };\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/db.ts"],"names":["err","message"],"mappings":"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","file":"db.cjs","sourcesContent":["/**\n * Erros tipados do SDK.\n *\n * Todo erro lançado pelo SDK estende `NeetruError` — caller pode discriminar\n * por `.code` (string estável) sem parsing de message.\n */\n\n/** Códigos de erro estáveis do SDK. Adicionar aqui requer minor bump. */\nexport type NeetruErrorCode =\n | 'invalid_config'\n | 'missing_api_key'\n | 'unauthorized'\n | 'forbidden'\n | 'not_found'\n | 'rate_limited'\n | 'validation_failed'\n | 'network_error'\n | 'invalid_response'\n | 'server_error'\n | 'unknown';\n\n/**\n * Erro tipado padrão do SDK. Sempre lançado em vez de Error genérico.\n *\n * @example\n * ```ts\n * try { await client.catalog.list(); }\n * catch (e) {\n * if (e instanceof NeetruError && e.code === 'rate_limited') retry();\n * }\n * ```\n */\nexport class NeetruError extends Error {\n public readonly code: NeetruErrorCode | string;\n public readonly status?: number;\n public readonly requestId?: string;\n\n constructor(\n code: NeetruErrorCode | string,\n message: string,\n status?: number,\n requestId?: string,\n ) {\n super(message);\n this.name = 'NeetruError';\n this.code = code;\n this.status = status;\n this.requestId = requestId;\n // Preserva o prototype chain ao herdar de Error (downlevel quirk de TS).\n Object.setPrototypeOf(this, NeetruError.prototype);\n }\n}\n","/**\n * HTTP transport interno do SDK.\n *\n * Responsabilidades:\n * - Construir URL absoluta a partir de `baseUrl` + path\n * - Injetar Bearer token quando `requireAuth=true`\n * - Mapear status HTTP → `NeetruError` com `code` estável\n * - Parse defensivo de JSON (não lança em body vazio em 204)\n * - Retry/backoff exponencial em `rate_limited` (429), `server_error` (5xx)\n * e `network_error` (timeout/falha de rede). Honra `Retry-After` quando\n * presente. Default 2 retries (3 tentativas no total). Caller opta-out\n * com `retries: 0`.\n */\nimport { NeetruError, type NeetruErrorCode } from './errors';\nimport type { ResolvedConfig } from './types';\n\n/** Opções da request HTTP. */\nexport interface HttpRequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n /** Path relativo (ex: `/api/v1/cli/catalog`). Concatenado a `baseUrl`. */\n path: string;\n /** Query string params (chave → valor primitivo). Valores `undefined` ignorados. */\n query?: Record<string, string | number | boolean | undefined>;\n /** Body JSON-serializável. Ignorado em GET/DELETE. */\n body?: unknown;\n /**\n * Se true, injeta `Authorization: Bearer <apiKey>`. Lança `missing_api_key`\n * se config.apiKey ausente. Default false.\n */\n requireAuth?: boolean;\n /** Cabeçalhos extras. */\n headers?: Record<string, string>;\n /**\n * Número de retries em códigos transientes (`rate_limited`, `server_error`,\n * `network_error`). Default 2 (= 3 tentativas total). Caller passa `0` pra\n * desativar (útil em operações não-idempotentes específicas).\n */\n retries?: number;\n}\n\nconst DEFAULT_RETRIES = 2;\nconst RETRYABLE_CODES = new Set<NeetruErrorCode>([\n 'rate_limited',\n 'server_error',\n 'network_error',\n]);\n\n/** Backoff exponencial com jitter ±20%. attempt: 0=primeira, 1=primeiro retry, ... */\nfunction backoffMs(attempt: number): number {\n const base = 200 * Math.pow(4, attempt); // 200ms, 800ms, 3.2s, ...\n const jitter = base * 0.2 * (Math.random() * 2 - 1);\n return Math.max(50, Math.round(base + jitter));\n}\n\n/**\n * Honra `Retry-After` header (segundos ou HTTP-date). Retorna ms ou null se\n * inválido. RFC 9110 §10.2.3.\n */\nfunction parseRetryAfter(value: string | null): number | null {\n if (!value) return null;\n const secs = Number(value);\n if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1000);\n const dateMs = Date.parse(value);\n if (Number.isFinite(dateMs)) {\n const delta = dateMs - Date.now();\n if (delta > 0) return delta;\n }\n return null;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Mapeamento status → code estável do NeetruError. */\nfunction statusToCode(status: number): NeetruErrorCode {\n if (status === 401) return 'unauthorized';\n if (status === 403) return 'forbidden';\n if (status === 404) return 'not_found';\n if (status === 422 || status === 400) return 'validation_failed';\n if (status === 429) return 'rate_limited';\n if (status >= 500) return 'server_error';\n return 'unknown';\n}\n\nfunction buildUrl(baseUrl: string, path: string, query?: HttpRequestOptions['query']): string {\n // Trim trailing slash em base e leading em path pra evitar `//`.\n const base = baseUrl.replace(/\\/+$/, '');\n const p = path.startsWith('/') ? path : `/${path}`;\n const url = new URL(`${base}${p}`);\n if (query) {\n for (const [k, v] of Object.entries(query)) {\n if (v === undefined) continue;\n url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n}\n\n/** Parse JSON defensivo — retorna `undefined` em body vazio. */\nasync function safeJson(res: Response): Promise<unknown> {\n const text = await res.text();\n if (!text) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Executa request HTTP. Em sucesso retorna body parseado; em erro lança\n * `NeetruError` com `code` derivado do status. Aplica retry/backoff\n * automático em códigos transientes (rate_limited/server_error/network_error)\n * conforme `opts.retries` (default 2 = 3 tentativas).\n */\nexport async function httpRequest<T>(\n config: ResolvedConfig,\n opts: HttpRequestOptions,\n): Promise<T> {\n const method = opts.method ?? 'GET';\n const url = buildUrl(config.baseUrl, opts.path, opts.query);\n const maxRetries = opts.retries ?? DEFAULT_RETRIES;\n\n const headers: Record<string, string> = {\n accept: 'application/json',\n ...opts.headers,\n };\n\n if (opts.requireAuth) {\n if (!config.apiKey) {\n throw new NeetruError(\n 'missing_api_key',\n 'This operation requires an apiKey. Pass it to createNeetruClient({ apiKey }) or set NEETRU_API_KEY env var.',\n );\n }\n headers.authorization = `Bearer ${config.apiKey}`;\n }\n\n // Body só é serializado uma vez — reusado entre tentativas.\n const bodyString =\n opts.body !== undefined && method !== 'GET' && method !== 'DELETE'\n ? JSON.stringify(opts.body)\n : undefined;\n if (bodyString !== undefined) {\n headers['content-type'] = 'application/json';\n }\n\n let lastError: NeetruError | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const init: RequestInit = { method, headers };\n if (bodyString !== undefined) init.body = bodyString;\n // BUG-020 fix (2026-05-13): timeout default 30s. AbortSignal.timeout\n // requer Node 18+ ou browsers recentes.\n init.signal = AbortSignal.timeout(30_000);\n\n let res: Response;\n try {\n res = await config.fetch(url, init);\n } catch (err) {\n const message =\n err instanceof DOMException && err.name === 'TimeoutError'\n ? 'Network error: timeout after 30s'\n : `Network error: ${err instanceof Error ? err.message : 'fetch failed'}`;\n lastError = new NeetruError('network_error', message);\n if (attempt < maxRetries) {\n await sleep(backoffMs(attempt));\n continue;\n }\n throw lastError;\n }\n\n const requestId =\n res.headers.get('x-request-id') ?? res.headers.get('x-correlation-id') ?? undefined;\n\n if (res.ok) {\n const parsed = await safeJson(res);\n return parsed as T;\n }\n\n const body = (await safeJson(res)) as\n | { error?: { code?: string; message?: string } | string }\n | undefined;\n let code: string = statusToCode(res.status);\n let message = `HTTP ${res.status}`;\n if (body && typeof body === 'object' && 'error' in body) {\n const errField = body.error;\n if (typeof errField === 'string') {\n message = errField;\n } else if (errField && typeof errField === 'object') {\n if (typeof errField.code === 'string') code = errField.code;\n if (typeof errField.message === 'string') message = errField.message;\n }\n }\n const err = new NeetruError(code, message, res.status, requestId);\n lastError = err;\n\n const isRetryable = RETRYABLE_CODES.has(code as NeetruErrorCode);\n if (isRetryable && attempt < maxRetries) {\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\n const delay = retryAfter ?? backoffMs(attempt);\n await sleep(delay);\n continue;\n }\n throw err;\n }\n\n // Unreachable — loop sempre retorna ou lança. Safety net.\n throw lastError ?? new NeetruError('unknown', 'unexpected httpRequest exit');\n}\n","/**\n * Datastore namespace (v0.3.1) — Sprint 8.\n *\n * `client.db.collection(name)` retorna um `DbCollectionRef` que mapeia para\n * `tenant_{tid}_{name}` no Core. Endpoints REST disponíveis (Sprint 8 LIVE):\n * - `GET /api/sdk/v1/datastore/{collection}?limit&where`\n * - `POST /api/sdk/v1/datastore/{collection}` (add)\n * - `GET /api/sdk/v1/datastore/{collection}/{id}`\n * - `PATCH /api/sdk/v1/datastore/{collection}/{id}` (update merge)\n * - `PUT /api/sdk/v1/datastore/{collection}/{id}` (set replace)\n * - `DELETE /api/sdk/v1/datastore/{collection}/{id}`\n *\n * O Core resolve `tenantId` via Bearer token. SDK passa `x-neetru-tenant`\n * pra dar visibilidade explícita; backend valida match com o token.\n *\n * Em dev (NEETRU_ENV=dev), `client.db` é `MockDb` (in-memory).\n */\nimport { httpRequest } from './http';\nimport { NeetruError } from './errors';\nimport type {\n DbCollectionRef,\n DbListOptions,\n DbNamespace,\n DbWhereFilter,\n ResolvedConfig,\n} from './types';\n\nconst COLL_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/;\n\nfunction assertValidCollection(name: string): void {\n if (!COLL_RE.test(name)) {\n throw new NeetruError(\n 'validation_failed',\n `Invalid collection name: \"${name}\". Must match ${COLL_RE}.`,\n );\n }\n}\n\n/** Serializa filtro pro formato `field:op:value` aceito pelo backend. */\nfunction serializeWhere(filter: DbWhereFilter): string {\n const { field, op, value } = filter;\n if (op === 'in') {\n if (!Array.isArray(value)) {\n throw new NeetruError(\n 'validation_failed',\n `where op=\"in\" requer value array (recebido: ${typeof value})`,\n );\n }\n return `${field}:in:${value.map((v) => String(v)).join(',')}`;\n }\n return `${field}:${op}:${String(value)}`;\n}\n\n/**\n * Constrói o namespace `db` real (HTTP) com binding ao tenantId resolvido.\n */\nexport function createDbNamespace(config: ResolvedConfig): DbNamespace {\n return {\n collection(name: string): DbCollectionRef {\n assertValidCollection(name);\n\n const headers: Record<string, string> = {};\n if (config.tenantId) headers['x-neetru-tenant'] = config.tenantId;\n\n return {\n async list<T = Record<string, unknown>>(\n opts?: DbListOptions,\n ): Promise<T[]> {\n // multi-where → URL múltiplo `where=...&where=...`. Como\n // `httpRequest.query` é Record<>, monta path manualmente quando há\n // filtros pra preservar repetição da chave.\n let path = `/api/sdk/v1/datastore/${name}`;\n const params = new URLSearchParams();\n if (opts?.limit !== undefined) params.set('limit', String(opts.limit));\n if (opts?.where && opts.where.length > 0) {\n for (const f of opts.where) {\n params.append('where', serializeWhere(f));\n }\n }\n if (config.tenantId) params.set('tenantId', config.tenantId);\n const qs = params.toString();\n if (qs) path += `?${qs}`;\n\n const raw = await httpRequest<{ items?: unknown[] }>(config, {\n method: 'GET',\n path,\n requireAuth: true,\n headers,\n });\n if (!raw || !Array.isArray(raw.items)) {\n throw new NeetruError(\n 'invalid_response',\n 'datastore.list missing items[]',\n );\n }\n return raw.items as T[];\n },\n\n async get<T = Record<string, unknown>>(id: string): Promise<T | null> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n try {\n const raw = await httpRequest<{ item?: T | null }>(config, {\n method: 'GET',\n path: `/api/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n requireAuth: true,\n headers,\n });\n return raw?.item ?? null;\n } catch (err) {\n if (err instanceof NeetruError && err.code === 'not_found') return null;\n throw err;\n }\n },\n\n async add(data: Record<string, unknown>): Promise<{ ok: true; id: string }> {\n if (!data || typeof data !== 'object') {\n throw new NeetruError('validation_failed', 'data object required');\n }\n const raw = await httpRequest<{ ok?: boolean; id?: string }>(config, {\n method: 'POST',\n path: `/api/sdk/v1/datastore/${name}`,\n body: { data },\n requireAuth: true,\n headers,\n });\n if (!raw || typeof raw.id !== 'string') {\n throw new NeetruError('invalid_response', 'datastore.add missing id');\n }\n return { ok: true, id: raw.id };\n },\n\n async set(id: string, data: Record<string, unknown>): Promise<{ ok: true }> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n await httpRequest(config, {\n method: 'PUT',\n path: `/api/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n body: { data },\n requireAuth: true,\n headers,\n });\n return { ok: true };\n },\n\n async update(id: string, data: Record<string, unknown>): Promise<{ ok: true }> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n await httpRequest(config, {\n method: 'PATCH',\n path: `/api/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n body: { data },\n requireAuth: true,\n headers,\n });\n return { ok: true };\n },\n\n async remove(id: string): Promise<{ ok: true }> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n await httpRequest(config, {\n method: 'DELETE',\n path: `/api/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n requireAuth: true,\n headers,\n });\n return { ok: true };\n },\n };\n },\n };\n}\n"]}
|
package/dist/db.d.cts
CHANGED
package/dist/db.d.ts
CHANGED
package/dist/db.mjs
CHANGED
|
@@ -14,6 +14,31 @@ var NeetruError = class _NeetruError extends Error {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
// src/http.ts
|
|
17
|
+
var DEFAULT_RETRIES = 2;
|
|
18
|
+
var RETRYABLE_CODES = /* @__PURE__ */ new Set([
|
|
19
|
+
"rate_limited",
|
|
20
|
+
"server_error",
|
|
21
|
+
"network_error"
|
|
22
|
+
]);
|
|
23
|
+
function backoffMs(attempt) {
|
|
24
|
+
const base = 200 * Math.pow(4, attempt);
|
|
25
|
+
const jitter = base * 0.2 * (Math.random() * 2 - 1);
|
|
26
|
+
return Math.max(50, Math.round(base + jitter));
|
|
27
|
+
}
|
|
28
|
+
function parseRetryAfter(value) {
|
|
29
|
+
if (!value) return null;
|
|
30
|
+
const secs = Number(value);
|
|
31
|
+
if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1e3);
|
|
32
|
+
const dateMs = Date.parse(value);
|
|
33
|
+
if (Number.isFinite(dateMs)) {
|
|
34
|
+
const delta = dateMs - Date.now();
|
|
35
|
+
if (delta > 0) return delta;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
function sleep(ms) {
|
|
40
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
41
|
+
}
|
|
17
42
|
function statusToCode(status) {
|
|
18
43
|
if (status === 401) return "unauthorized";
|
|
19
44
|
if (status === 403) return "forbidden";
|
|
@@ -47,6 +72,7 @@ async function safeJson(res) {
|
|
|
47
72
|
async function httpRequest(config, opts) {
|
|
48
73
|
const method = opts.method ?? "GET";
|
|
49
74
|
const url = buildUrl(config.baseUrl, opts.path, opts.query);
|
|
75
|
+
const maxRetries = opts.retries ?? DEFAULT_RETRIES;
|
|
50
76
|
const headers = {
|
|
51
77
|
accept: "application/json",
|
|
52
78
|
...opts.headers
|
|
@@ -60,20 +86,32 @@ async function httpRequest(config, opts) {
|
|
|
60
86
|
}
|
|
61
87
|
headers.authorization = `Bearer ${config.apiKey}`;
|
|
62
88
|
}
|
|
63
|
-
const
|
|
64
|
-
if (
|
|
89
|
+
const bodyString = opts.body !== void 0 && method !== "GET" && method !== "DELETE" ? JSON.stringify(opts.body) : void 0;
|
|
90
|
+
if (bodyString !== void 0) {
|
|
65
91
|
headers["content-type"] = "application/json";
|
|
66
|
-
init.body = JSON.stringify(opts.body);
|
|
67
|
-
}
|
|
68
|
-
let res;
|
|
69
|
-
try {
|
|
70
|
-
res = await config.fetch(url, init);
|
|
71
|
-
} catch (err) {
|
|
72
|
-
const message = err instanceof Error ? err.message : "fetch failed";
|
|
73
|
-
throw new NeetruError("network_error", `Network error: ${message}`);
|
|
74
92
|
}
|
|
75
|
-
|
|
76
|
-
|
|
93
|
+
let lastError = null;
|
|
94
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
95
|
+
const init = { method, headers };
|
|
96
|
+
if (bodyString !== void 0) init.body = bodyString;
|
|
97
|
+
init.signal = AbortSignal.timeout(3e4);
|
|
98
|
+
let res;
|
|
99
|
+
try {
|
|
100
|
+
res = await config.fetch(url, init);
|
|
101
|
+
} catch (err2) {
|
|
102
|
+
const message2 = err2 instanceof DOMException && err2.name === "TimeoutError" ? "Network error: timeout after 30s" : `Network error: ${err2 instanceof Error ? err2.message : "fetch failed"}`;
|
|
103
|
+
lastError = new NeetruError("network_error", message2);
|
|
104
|
+
if (attempt < maxRetries) {
|
|
105
|
+
await sleep(backoffMs(attempt));
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
throw lastError;
|
|
109
|
+
}
|
|
110
|
+
const requestId = res.headers.get("x-request-id") ?? res.headers.get("x-correlation-id") ?? void 0;
|
|
111
|
+
if (res.ok) {
|
|
112
|
+
const parsed = await safeJson(res);
|
|
113
|
+
return parsed;
|
|
114
|
+
}
|
|
77
115
|
const body = await safeJson(res);
|
|
78
116
|
let code = statusToCode(res.status);
|
|
79
117
|
let message = `HTTP ${res.status}`;
|
|
@@ -86,10 +124,18 @@ async function httpRequest(config, opts) {
|
|
|
86
124
|
if (typeof errField.message === "string") message = errField.message;
|
|
87
125
|
}
|
|
88
126
|
}
|
|
89
|
-
|
|
127
|
+
const err = new NeetruError(code, message, res.status, requestId);
|
|
128
|
+
lastError = err;
|
|
129
|
+
const isRetryable = RETRYABLE_CODES.has(code);
|
|
130
|
+
if (isRetryable && attempt < maxRetries) {
|
|
131
|
+
const retryAfter = parseRetryAfter(res.headers.get("retry-after"));
|
|
132
|
+
const delay = retryAfter ?? backoffMs(attempt);
|
|
133
|
+
await sleep(delay);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
throw err;
|
|
90
137
|
}
|
|
91
|
-
|
|
92
|
-
return parsed;
|
|
138
|
+
throw lastError ?? new NeetruError("unknown", "unexpected httpRequest exit");
|
|
93
139
|
}
|
|
94
140
|
|
|
95
141
|
// src/db.ts
|
|
@@ -123,8 +169,7 @@ function createDbNamespace(config) {
|
|
|
123
169
|
if (config.tenantId) headers["x-neetru-tenant"] = config.tenantId;
|
|
124
170
|
return {
|
|
125
171
|
async list(opts) {
|
|
126
|
-
|
|
127
|
-
let path = `/sdk/v1/datastore/${name}`;
|
|
172
|
+
let path = `/api/sdk/v1/datastore/${name}`;
|
|
128
173
|
const params = new URLSearchParams();
|
|
129
174
|
if (opts?.limit !== void 0) params.set("limit", String(opts.limit));
|
|
130
175
|
if (opts?.where && opts.where.length > 0) {
|
|
@@ -156,7 +201,7 @@ function createDbNamespace(config) {
|
|
|
156
201
|
try {
|
|
157
202
|
const raw = await httpRequest(config, {
|
|
158
203
|
method: "GET",
|
|
159
|
-
path: `/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,
|
|
204
|
+
path: `/api/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,
|
|
160
205
|
requireAuth: true,
|
|
161
206
|
headers
|
|
162
207
|
});
|
|
@@ -172,7 +217,7 @@ function createDbNamespace(config) {
|
|
|
172
217
|
}
|
|
173
218
|
const raw = await httpRequest(config, {
|
|
174
219
|
method: "POST",
|
|
175
|
-
path: `/sdk/v1/datastore/${name}`,
|
|
220
|
+
path: `/api/sdk/v1/datastore/${name}`,
|
|
176
221
|
body: { data },
|
|
177
222
|
requireAuth: true,
|
|
178
223
|
headers
|
|
@@ -188,7 +233,7 @@ function createDbNamespace(config) {
|
|
|
188
233
|
}
|
|
189
234
|
await httpRequest(config, {
|
|
190
235
|
method: "PUT",
|
|
191
|
-
path: `/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,
|
|
236
|
+
path: `/api/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,
|
|
192
237
|
body: { data },
|
|
193
238
|
requireAuth: true,
|
|
194
239
|
headers
|
|
@@ -201,7 +246,7 @@ function createDbNamespace(config) {
|
|
|
201
246
|
}
|
|
202
247
|
await httpRequest(config, {
|
|
203
248
|
method: "PATCH",
|
|
204
|
-
path: `/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,
|
|
249
|
+
path: `/api/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,
|
|
205
250
|
body: { data },
|
|
206
251
|
requireAuth: true,
|
|
207
252
|
headers
|
|
@@ -214,7 +259,7 @@ function createDbNamespace(config) {
|
|
|
214
259
|
}
|
|
215
260
|
await httpRequest(config, {
|
|
216
261
|
method: "DELETE",
|
|
217
|
-
path: `/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,
|
|
262
|
+
path: `/api/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,
|
|
218
263
|
requireAuth: true,
|
|
219
264
|
headers
|
|
220
265
|
});
|
package/dist/db.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/db.ts"],"names":[],"mappings":"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","file":"db.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 * Datastore namespace (v0.3.1) — Sprint 8.\n *\n * `client.db.collection(name)` retorna um `DbCollectionRef` que mapeia para\n * `tenant_{tid}_{name}` no Core. Endpoints REST disponíveis (Sprint 8 LIVE):\n * - `GET /sdk/v1/datastore/{collection}?limit&where`\n * - `POST /sdk/v1/datastore/{collection}` (add)\n * - `GET /sdk/v1/datastore/{collection}/{id}`\n * - `PATCH /sdk/v1/datastore/{collection}/{id}` (update merge)\n * - `PUT /sdk/v1/datastore/{collection}/{id}` (set replace)\n * - `DELETE /sdk/v1/datastore/{collection}/{id}`\n *\n * O Core resolve `tenantId` via Bearer token. SDK passa `x-neetru-tenant`\n * pra dar visibilidade explícita; backend valida match com o token.\n *\n * Em dev (NEETRU_ENV=dev), `client.db` é `MockDb` (in-memory).\n */\nimport { httpRequest } from './http';\nimport { NeetruError } from './errors';\nimport type {\n DbCollectionRef,\n DbListOptions,\n DbNamespace,\n DbWhereFilter,\n ResolvedConfig,\n} from './types';\n\nconst COLL_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/;\n\nfunction assertValidCollection(name: string): void {\n if (!COLL_RE.test(name)) {\n throw new NeetruError(\n 'validation_failed',\n `Invalid collection name: \"${name}\". Must match ${COLL_RE}.`,\n );\n }\n}\n\n/** Serializa filtro pro formato `field:op:value` aceito pelo backend. */\nfunction serializeWhere(filter: DbWhereFilter): string {\n const { field, op, value } = filter;\n if (op === 'in') {\n if (!Array.isArray(value)) {\n throw new NeetruError(\n 'validation_failed',\n `where op=\"in\" requer value array (recebido: ${typeof value})`,\n );\n }\n return `${field}:in:${value.map((v) => String(v)).join(',')}`;\n }\n return `${field}:${op}:${String(value)}`;\n}\n\n/**\n * Constrói o namespace `db` real (HTTP) com binding ao tenantId resolvido.\n */\nexport function createDbNamespace(config: ResolvedConfig): DbNamespace {\n return {\n collection(name: string): DbCollectionRef {\n assertValidCollection(name);\n\n const headers: Record<string, string> = {};\n if (config.tenantId) headers['x-neetru-tenant'] = config.tenantId;\n\n return {\n async list<T = Record<string, unknown>>(\n opts?: DbListOptions,\n ): Promise<T[]> {\n const query: Record<string, string | number> = {};\n if (opts?.limit !== undefined) query.limit = opts.limit;\n\n // multi-where → request URL múltiplo `where=...&where=...`. Como\n // `httpRequest.query` é Record<>, monta path manualmente quando há\n // filtros pra preservar repetição da chave.\n let path = `/sdk/v1/datastore/${name}`;\n const params = new URLSearchParams();\n if (opts?.limit !== undefined) params.set('limit', String(opts.limit));\n if (opts?.where && opts.where.length > 0) {\n for (const f of opts.where) {\n params.append('where', serializeWhere(f));\n }\n }\n if (config.tenantId) params.set('tenantId', config.tenantId);\n const qs = params.toString();\n if (qs) path += `?${qs}`;\n\n const raw = await httpRequest<{ items?: unknown[] }>(config, {\n method: 'GET',\n path,\n requireAuth: true,\n headers,\n });\n if (!raw || !Array.isArray(raw.items)) {\n throw new NeetruError(\n 'invalid_response',\n 'datastore.list missing items[]',\n );\n }\n return raw.items as T[];\n },\n\n async get<T = Record<string, unknown>>(id: string): Promise<T | null> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n try {\n const raw = await httpRequest<{ item?: T | null }>(config, {\n method: 'GET',\n path: `/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n requireAuth: true,\n headers,\n });\n return raw?.item ?? null;\n } catch (err) {\n if (err instanceof NeetruError && err.code === 'not_found') return null;\n throw err;\n }\n },\n\n async add(data: Record<string, unknown>): Promise<{ ok: true; id: string }> {\n if (!data || typeof data !== 'object') {\n throw new NeetruError('validation_failed', 'data object required');\n }\n const raw = await httpRequest<{ ok?: boolean; id?: string }>(config, {\n method: 'POST',\n path: `/sdk/v1/datastore/${name}`,\n body: { data },\n requireAuth: true,\n headers,\n });\n if (!raw || typeof raw.id !== 'string') {\n throw new NeetruError('invalid_response', 'datastore.add missing id');\n }\n return { ok: true, id: raw.id };\n },\n\n async set(id: string, data: Record<string, unknown>): Promise<{ ok: true }> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n await httpRequest(config, {\n method: 'PUT',\n path: `/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n body: { data },\n requireAuth: true,\n headers,\n });\n return { ok: true };\n },\n\n async update(id: string, data: Record<string, unknown>): Promise<{ ok: true }> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n await httpRequest(config, {\n method: 'PATCH',\n path: `/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n body: { data },\n requireAuth: true,\n headers,\n });\n return { ok: true };\n },\n\n async remove(id: string): Promise<{ ok: true }> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n await httpRequest(config, {\n method: 'DELETE',\n path: `/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n requireAuth: true,\n headers,\n });\n return { ok: true };\n },\n };\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/db.ts"],"names":["err","message"],"mappings":"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","file":"db.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 * Datastore namespace (v0.3.1) — Sprint 8.\n *\n * `client.db.collection(name)` retorna um `DbCollectionRef` que mapeia para\n * `tenant_{tid}_{name}` no Core. Endpoints REST disponíveis (Sprint 8 LIVE):\n * - `GET /api/sdk/v1/datastore/{collection}?limit&where`\n * - `POST /api/sdk/v1/datastore/{collection}` (add)\n * - `GET /api/sdk/v1/datastore/{collection}/{id}`\n * - `PATCH /api/sdk/v1/datastore/{collection}/{id}` (update merge)\n * - `PUT /api/sdk/v1/datastore/{collection}/{id}` (set replace)\n * - `DELETE /api/sdk/v1/datastore/{collection}/{id}`\n *\n * O Core resolve `tenantId` via Bearer token. SDK passa `x-neetru-tenant`\n * pra dar visibilidade explícita; backend valida match com o token.\n *\n * Em dev (NEETRU_ENV=dev), `client.db` é `MockDb` (in-memory).\n */\nimport { httpRequest } from './http';\nimport { NeetruError } from './errors';\nimport type {\n DbCollectionRef,\n DbListOptions,\n DbNamespace,\n DbWhereFilter,\n ResolvedConfig,\n} from './types';\n\nconst COLL_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/;\n\nfunction assertValidCollection(name: string): void {\n if (!COLL_RE.test(name)) {\n throw new NeetruError(\n 'validation_failed',\n `Invalid collection name: \"${name}\". Must match ${COLL_RE}.`,\n );\n }\n}\n\n/** Serializa filtro pro formato `field:op:value` aceito pelo backend. */\nfunction serializeWhere(filter: DbWhereFilter): string {\n const { field, op, value } = filter;\n if (op === 'in') {\n if (!Array.isArray(value)) {\n throw new NeetruError(\n 'validation_failed',\n `where op=\"in\" requer value array (recebido: ${typeof value})`,\n );\n }\n return `${field}:in:${value.map((v) => String(v)).join(',')}`;\n }\n return `${field}:${op}:${String(value)}`;\n}\n\n/**\n * Constrói o namespace `db` real (HTTP) com binding ao tenantId resolvido.\n */\nexport function createDbNamespace(config: ResolvedConfig): DbNamespace {\n return {\n collection(name: string): DbCollectionRef {\n assertValidCollection(name);\n\n const headers: Record<string, string> = {};\n if (config.tenantId) headers['x-neetru-tenant'] = config.tenantId;\n\n return {\n async list<T = Record<string, unknown>>(\n opts?: DbListOptions,\n ): Promise<T[]> {\n // multi-where → URL múltiplo `where=...&where=...`. Como\n // `httpRequest.query` é Record<>, monta path manualmente quando há\n // filtros pra preservar repetição da chave.\n let path = `/api/sdk/v1/datastore/${name}`;\n const params = new URLSearchParams();\n if (opts?.limit !== undefined) params.set('limit', String(opts.limit));\n if (opts?.where && opts.where.length > 0) {\n for (const f of opts.where) {\n params.append('where', serializeWhere(f));\n }\n }\n if (config.tenantId) params.set('tenantId', config.tenantId);\n const qs = params.toString();\n if (qs) path += `?${qs}`;\n\n const raw = await httpRequest<{ items?: unknown[] }>(config, {\n method: 'GET',\n path,\n requireAuth: true,\n headers,\n });\n if (!raw || !Array.isArray(raw.items)) {\n throw new NeetruError(\n 'invalid_response',\n 'datastore.list missing items[]',\n );\n }\n return raw.items as T[];\n },\n\n async get<T = Record<string, unknown>>(id: string): Promise<T | null> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n try {\n const raw = await httpRequest<{ item?: T | null }>(config, {\n method: 'GET',\n path: `/api/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n requireAuth: true,\n headers,\n });\n return raw?.item ?? null;\n } catch (err) {\n if (err instanceof NeetruError && err.code === 'not_found') return null;\n throw err;\n }\n },\n\n async add(data: Record<string, unknown>): Promise<{ ok: true; id: string }> {\n if (!data || typeof data !== 'object') {\n throw new NeetruError('validation_failed', 'data object required');\n }\n const raw = await httpRequest<{ ok?: boolean; id?: string }>(config, {\n method: 'POST',\n path: `/api/sdk/v1/datastore/${name}`,\n body: { data },\n requireAuth: true,\n headers,\n });\n if (!raw || typeof raw.id !== 'string') {\n throw new NeetruError('invalid_response', 'datastore.add missing id');\n }\n return { ok: true, id: raw.id };\n },\n\n async set(id: string, data: Record<string, unknown>): Promise<{ ok: true }> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n await httpRequest(config, {\n method: 'PUT',\n path: `/api/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n body: { data },\n requireAuth: true,\n headers,\n });\n return { ok: true };\n },\n\n async update(id: string, data: Record<string, unknown>): Promise<{ ok: true }> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n await httpRequest(config, {\n method: 'PATCH',\n path: `/api/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n body: { data },\n requireAuth: true,\n headers,\n });\n return { ok: true };\n },\n\n async remove(id: string): Promise<{ ok: true }> {\n if (!id || typeof id !== 'string') {\n throw new NeetruError('validation_failed', 'id required');\n }\n await httpRequest(config, {\n method: 'DELETE',\n path: `/api/sdk/v1/datastore/${name}/${encodeURIComponent(id)}`,\n requireAuth: true,\n headers,\n });\n return { ok: true };\n },\n };\n },\n };\n}\n"]}
|
package/dist/entitlements.cjs
CHANGED
|
@@ -16,6 +16,31 @@ var NeetruError = class _NeetruError extends Error {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
// src/http.ts
|
|
19
|
+
var DEFAULT_RETRIES = 2;
|
|
20
|
+
var RETRYABLE_CODES = /* @__PURE__ */ new Set([
|
|
21
|
+
"rate_limited",
|
|
22
|
+
"server_error",
|
|
23
|
+
"network_error"
|
|
24
|
+
]);
|
|
25
|
+
function backoffMs(attempt) {
|
|
26
|
+
const base = 200 * Math.pow(4, attempt);
|
|
27
|
+
const jitter = base * 0.2 * (Math.random() * 2 - 1);
|
|
28
|
+
return Math.max(50, Math.round(base + jitter));
|
|
29
|
+
}
|
|
30
|
+
function parseRetryAfter(value) {
|
|
31
|
+
if (!value) return null;
|
|
32
|
+
const secs = Number(value);
|
|
33
|
+
if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1e3);
|
|
34
|
+
const dateMs = Date.parse(value);
|
|
35
|
+
if (Number.isFinite(dateMs)) {
|
|
36
|
+
const delta = dateMs - Date.now();
|
|
37
|
+
if (delta > 0) return delta;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function sleep(ms) {
|
|
42
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
43
|
+
}
|
|
19
44
|
function statusToCode(status) {
|
|
20
45
|
if (status === 401) return "unauthorized";
|
|
21
46
|
if (status === 403) return "forbidden";
|
|
@@ -49,6 +74,7 @@ async function safeJson(res) {
|
|
|
49
74
|
async function httpRequest(config, opts) {
|
|
50
75
|
const method = opts.method ?? "GET";
|
|
51
76
|
const url = buildUrl(config.baseUrl, opts.path, opts.query);
|
|
77
|
+
const maxRetries = opts.retries ?? DEFAULT_RETRIES;
|
|
52
78
|
const headers = {
|
|
53
79
|
accept: "application/json",
|
|
54
80
|
...opts.headers
|
|
@@ -62,20 +88,32 @@ async function httpRequest(config, opts) {
|
|
|
62
88
|
}
|
|
63
89
|
headers.authorization = `Bearer ${config.apiKey}`;
|
|
64
90
|
}
|
|
65
|
-
const
|
|
66
|
-
if (
|
|
91
|
+
const bodyString = opts.body !== void 0 && method !== "GET" && method !== "DELETE" ? JSON.stringify(opts.body) : void 0;
|
|
92
|
+
if (bodyString !== void 0) {
|
|
67
93
|
headers["content-type"] = "application/json";
|
|
68
|
-
init.body = JSON.stringify(opts.body);
|
|
69
94
|
}
|
|
70
|
-
let
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
95
|
+
let lastError = null;
|
|
96
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
97
|
+
const init = { method, headers };
|
|
98
|
+
if (bodyString !== void 0) init.body = bodyString;
|
|
99
|
+
init.signal = AbortSignal.timeout(3e4);
|
|
100
|
+
let res;
|
|
101
|
+
try {
|
|
102
|
+
res = await config.fetch(url, init);
|
|
103
|
+
} catch (err2) {
|
|
104
|
+
const message2 = err2 instanceof DOMException && err2.name === "TimeoutError" ? "Network error: timeout after 30s" : `Network error: ${err2 instanceof Error ? err2.message : "fetch failed"}`;
|
|
105
|
+
lastError = new NeetruError("network_error", message2);
|
|
106
|
+
if (attempt < maxRetries) {
|
|
107
|
+
await sleep(backoffMs(attempt));
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
throw lastError;
|
|
111
|
+
}
|
|
112
|
+
const requestId = res.headers.get("x-request-id") ?? res.headers.get("x-correlation-id") ?? void 0;
|
|
113
|
+
if (res.ok) {
|
|
114
|
+
const parsed = await safeJson(res);
|
|
115
|
+
return parsed;
|
|
116
|
+
}
|
|
79
117
|
const body = await safeJson(res);
|
|
80
118
|
let code = statusToCode(res.status);
|
|
81
119
|
let message = `HTTP ${res.status}`;
|
|
@@ -88,10 +126,18 @@ async function httpRequest(config, opts) {
|
|
|
88
126
|
if (typeof errField.message === "string") message = errField.message;
|
|
89
127
|
}
|
|
90
128
|
}
|
|
91
|
-
|
|
129
|
+
const err = new NeetruError(code, message, res.status, requestId);
|
|
130
|
+
lastError = err;
|
|
131
|
+
const isRetryable = RETRYABLE_CODES.has(code);
|
|
132
|
+
if (isRetryable && attempt < maxRetries) {
|
|
133
|
+
const retryAfter = parseRetryAfter(res.headers.get("retry-after"));
|
|
134
|
+
const delay = retryAfter ?? backoffMs(attempt);
|
|
135
|
+
await sleep(delay);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
throw err;
|
|
92
139
|
}
|
|
93
|
-
|
|
94
|
-
return parsed;
|
|
140
|
+
throw lastError ?? new NeetruError("unknown", "unexpected httpRequest exit");
|
|
95
141
|
}
|
|
96
142
|
|
|
97
143
|
// src/entitlements.ts
|
|
@@ -110,28 +156,63 @@ function toEntitlementCheck(raw) {
|
|
|
110
156
|
reason: typeof r.reason === "string" ? r.reason : void 0
|
|
111
157
|
};
|
|
112
158
|
}
|
|
159
|
+
var CACHE_TTL_MS = 6e4;
|
|
160
|
+
var CACHE_MAX = 100;
|
|
113
161
|
function createEntitlementsNamespace(config) {
|
|
114
|
-
|
|
162
|
+
const cache = /* @__PURE__ */ new Map();
|
|
163
|
+
function cacheKey(productSlug, feature) {
|
|
164
|
+
return `${productSlug}::${feature}`;
|
|
165
|
+
}
|
|
166
|
+
function readCache(key) {
|
|
167
|
+
const entry = cache.get(key);
|
|
168
|
+
if (!entry) return null;
|
|
169
|
+
if (entry.expiresAt < Date.now()) {
|
|
170
|
+
cache.delete(key);
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
cache.delete(key);
|
|
174
|
+
cache.set(key, entry);
|
|
175
|
+
return entry.value;
|
|
176
|
+
}
|
|
177
|
+
function writeCache(key, value) {
|
|
178
|
+
if (cache.size >= CACHE_MAX) {
|
|
179
|
+
const oldest = cache.keys().next().value;
|
|
180
|
+
if (oldest !== void 0) cache.delete(oldest);
|
|
181
|
+
}
|
|
182
|
+
cache.set(key, { value, expiresAt: Date.now() + CACHE_TTL_MS });
|
|
183
|
+
}
|
|
184
|
+
async function checkDetailed(productSlug, feature, opts = {}) {
|
|
115
185
|
if (!productSlug) throw new NeetruError("validation_failed", "productSlug is required");
|
|
116
186
|
if (!feature) throw new NeetruError("validation_failed", "feature is required");
|
|
187
|
+
const key = cacheKey(productSlug, feature);
|
|
188
|
+
if (!opts.cacheBust) {
|
|
189
|
+
const cached = readCache(key);
|
|
190
|
+
if (cached) return cached;
|
|
191
|
+
}
|
|
117
192
|
const raw = await httpRequest(config, {
|
|
118
193
|
method: "GET",
|
|
119
194
|
path: "/api/v1/sdk/entitlements/check",
|
|
120
195
|
query: { slug: productSlug, feature }});
|
|
121
|
-
|
|
196
|
+
const result = toEntitlementCheck(raw);
|
|
197
|
+
writeCache(key, result);
|
|
198
|
+
return result;
|
|
122
199
|
}
|
|
123
200
|
return {
|
|
124
201
|
/**
|
|
125
202
|
* Verifica se o caller pode usar `feature` no produto `productSlug`.
|
|
126
|
-
* Retorno simples: `true` libera, `false` bloqueia.
|
|
203
|
+
* Retorno simples: `true` libera, `false` bloqueia. Cache 60s automático.
|
|
127
204
|
*
|
|
128
205
|
* Use `checkDetailed` se precisar do `reason` pra mensagem de upgrade.
|
|
129
206
|
*/
|
|
130
|
-
async check(productSlug, feature) {
|
|
131
|
-
const result = await checkDetailed(productSlug, feature);
|
|
207
|
+
async check(productSlug, feature, opts) {
|
|
208
|
+
const result = await checkDetailed(productSlug, feature, opts);
|
|
132
209
|
return result.allowed;
|
|
133
210
|
},
|
|
134
|
-
checkDetailed
|
|
211
|
+
checkDetailed,
|
|
212
|
+
/** Test helper: limpa o cache LRU. */
|
|
213
|
+
__resetCache() {
|
|
214
|
+
cache.clear();
|
|
215
|
+
}
|
|
135
216
|
};
|
|
136
217
|
}
|
|
137
218
|
|