@vahidkaargar/customized-api-client 0.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/README.md +639 -0
- package/dist/index.cjs +1171 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +317 -0
- package/dist/index.d.ts +317 -0
- package/dist/index.js +1087 -0
- package/dist/index.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../package.json","../src/create-api-client.ts","../src/types/config.ts","../src/headers/jsonapi-headers.ts","../src/headers/auth.ts","../src/headers/locale.ts","../src/headers/idempotency.ts","../src/headers/if-match.ts","../src/headers/resolve-url.ts","../src/retry/policy.ts","../src/retry/retry-after.ts","../src/http/header-utils.ts","../src/retry/execute-with-retry.ts","../src/parse/success.ts","../src/security/redact.ts","../src/types/api-client-error.ts","../src/parse/errors.ts","../src/parse/bulk-207.ts","../src/parse/accepted-202.ts","../src/helpers/transform-keys.ts","../src/http/normalize-response.ts","../src/helpers/deprecation.ts","../src/guards.ts","../src/parse/pagination.ts","../src/helpers/query.ts","../src/helpers/included-index.ts","../src/helpers/version.ts","../src/helpers/form-errors.ts","../src/helpers/health.ts","../src/poll-async.ts"],"sourcesContent":["import pkg from '../package.json' with { type: 'json' };\n\nexport const PACKAGE_VERSION = pkg.version;\n\nexport { createApiClient } from './create-api-client.ts';\nexport type { ApiClient, RequestCallOptions } from './create-api-client.ts';\n\nexport type {\n ApiClientConfig,\n AuthConfig,\n BaseUrlMode,\n DeprecationInfo,\n IdempotencyReplayContext,\n RetryOptions,\n TokenProvider,\n TransformResponseKeysMode,\n} from './types/config.ts';\nexport { DEFAULT_PAGE_SIZE_CAP, DEFAULT_TIMEOUT_MS } from './types/config.ts';\n\nexport type {\n AcceptedBody,\n ClientSuccess,\n JsonApiSuccessBody,\n MultiStatusBody,\n MultiStatusItem,\n NoContentBody,\n NormalizedResponseHeaders,\n} from './types/results.ts';\nexport type { ErrResult, OkResult, Result } from './types/results.ts';\n\nexport type {\n JsonApiDocument,\n JsonApiErrorDocument,\n JsonApiErrorObject,\n JsonApiPrimaryData,\n JsonApiResourceLinkage,\n JsonApiResourceObject,\n} from './types/jsonapi.ts';\n\nexport { ApiClientError, isApiClientError } from './types/api-client-error.ts';\n\nexport {\n isAuthenticationError,\n isConflictError,\n isForbiddenError,\n isPayloadTooLargeError,\n isPreconditionFailedError,\n isPreconditionRequiredError,\n isRetryablePerPolicy,\n isValidationError,\n} from './guards.ts';\n\nexport { redactHeaderRecord, truncateForLog } from './security/redact.ts';\n\nexport { applyJsonApiHeaders } from './headers/jsonapi-headers.ts';\nexport {\n assertValidIdempotencyKey,\n defaultIdempotencyKey,\n IDEMPOTENCY_MAX_LENGTH,\n isMutationMethod,\n} from './headers/idempotency.ts';\nexport { formatIfMatch } from './headers/if-match.ts';\nexport { resolveAcceptLanguage } from './headers/locale.ts';\nexport { resolveAuthorizationHeader } from './headers/auth.ts';\nexport { resolveResourcePath, normalizeHttpUrl } from './headers/resolve-url.ts';\n\nexport { parseJsonApiDocument } from './parse/success.ts';\nexport { parseJsonApiErrorBody } from './parse/errors.ts';\nexport { parseMultiStatusBody } from './parse/bulk-207.ts';\nexport { resolveAcceptedLocation } from './parse/accepted-202.ts';\nexport {\n getNextPageUrl,\n parsePaginationKind,\n} from './parse/pagination.ts';\nexport type {\n CursorPagination,\n OffsetPagination,\n UnknownPagination,\n} from './parse/pagination.ts';\n\nexport { normalizeAxiosResponse } from './http/normalize-response.ts';\nexport { flattenAxiosHeaders, getHeader } from './http/header-utils.ts';\n\nexport { retryAllowed } from './retry/policy.ts';\nexport { parseRetryAfterSeconds } from './retry/retry-after.ts';\nexport { dispatchWithRetry } from './retry/execute-with-retry.ts';\n\nexport {\n buildCursorPageParams,\n buildJsonApiQuery,\n buildOffsetPageParams,\n} from './helpers/query.ts';\nexport type { JsonApiQueryInput } from './helpers/query.ts';\n\nexport { indexIncluded, resolveIncluded } from './helpers/included-index.ts';\nexport type { IncludedIndex } from './helpers/included-index.ts';\n\nexport { etagFromResponseHeaders, readResourceVersion } from './helpers/version.ts';\n\nexport { groupValidationErrorsByPointer } from './helpers/form-errors.ts';\nexport type { ValidationGroups } from './helpers/form-errors.ts';\n\nexport { createHealthCheck } from './helpers/health.ts';\n\nexport { parseDeprecationHeaders } from './helpers/deprecation.ts';\n\nexport { applyTransformKeys } from './helpers/transform-keys.ts';\n\nexport { pollAsyncResult } from './poll-async.ts';\nexport type { PollOptions } from './poll-async.ts';\n","{\n \"name\": \"@vahidkaargar/customized-api-client\",\n \"version\": \"0.2.0\",\n \"description\": \"TypeScript Axios client for JSON:API v1.1 with idempotency, retries, and normalized results\",\n \"type\": \"module\",\n \"engines\": {\n \"node\": \">=20\"\n },\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"scripts\": {\n \"build\": \"tsup src/index.ts --dts --format esm,cjs --clean --sourcemap\",\n \"prepublishOnly\": \"npm run build\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\",\n \"lint\": \"eslint \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\" && npm run lint:md\",\n \"lint:md\": \"markdownlint-cli2\",\n \"lint:md:fix\": \"markdownlint-cli2 --fix\",\n \"format\": \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"dependencies\": {\n \"axios\": \"^1.7.9\",\n \"ulid\": \"^2.3.0\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.17.0\",\n \"@types/node\": \"^22.10.2\",\n \"@vitest/coverage-v8\": \"^2.1.8\",\n \"eslint\": \"^9.17.0\",\n \"eslint-config-prettier\": \"^9.1.0\",\n \"eslint-plugin-import\": \"^2.31.0\",\n \"markdownlint-cli2\": \"^0.22.1\",\n \"msw\": \"^2.7.0\",\n \"prettier\": \"^3.4.2\",\n \"tsup\": \"^8.3.5\",\n \"typescript\": \"^5.7.2\",\n \"typescript-eslint\": \"^8.18.2\",\n \"vitest\": \"^2.1.8\"\n },\n \"keywords\": [\n \"jsonapi\",\n \"axios\",\n \"typescript\",\n \"api-client\"\n ],\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/vahidkaargar/customized-api-client.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/vahidkaargar/customized-api-client/issues\"\n },\n \"homepage\": \"https://github.com/vahidkaargar/customized-api-client#readme\",\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import axios, {\n type AxiosInstance,\n type AxiosRequestConfig,\n type AxiosResponse,\n isAxiosError,\n} from 'axios';\nimport type { ApiClientConfig, BaseUrlMode } from './types/config.ts';\nimport { DEFAULT_TIMEOUT_MS } from './types/config.ts';\nimport { applyJsonApiHeaders } from './headers/jsonapi-headers.ts';\nimport { resolveAuthorizationHeader } from './headers/auth.ts';\nimport { resolveAcceptLanguage } from './headers/locale.ts';\nimport {\n assertValidIdempotencyKey,\n defaultIdempotencyKey,\n isMutationMethod,\n} from './headers/idempotency.ts';\nimport { formatIfMatch } from './headers/if-match.ts';\nimport { resolveResourcePath } from './headers/resolve-url.ts';\nimport { dispatchWithRetry } from './retry/execute-with-retry.ts';\nimport { normalizeAxiosResponse } from './http/normalize-response.ts';\nimport type { ClientSuccess } from './types/results.ts';\nimport type { Result } from './types/results.ts';\nimport { ApiClientError } from './types/api-client-error.ts';\nimport { flattenAxiosHeaders } from './http/header-utils.ts';\nimport { parseDeprecationHeaders } from './helpers/deprecation.ts';\n\nexport interface RequestCallOptions {\n readonly idempotencyKey?: string;\n readonly ifMatchVersion?: number;\n}\n\nexport interface ApiClient {\n readonly get: (path: string, opts?: RequestCallOptions) => Promise<ClientSuccess>;\n readonly head: (path: string, opts?: RequestCallOptions) => Promise<ClientSuccess>;\n readonly post: (path: string, data?: unknown, opts?: RequestCallOptions) => Promise<ClientSuccess>;\n readonly patch: (path: string, data?: unknown, opts?: RequestCallOptions) => Promise<ClientSuccess>;\n readonly put: (path: string, data?: unknown, opts?: RequestCallOptions) => Promise<ClientSuccess>;\n readonly delete: (path: string, opts?: RequestCallOptions) => Promise<ClientSuccess>;\n readonly request: (\n ax: AxiosRequestConfig,\n opts?: RequestCallOptions,\n ) => Promise<ClientSuccess>;\n readonly getByUrl: (fullUrl: string, opts?: RequestCallOptions) => Promise<ClientSuccess>;\n readonly patchWithVersion: (\n path: string,\n data: unknown,\n version: number,\n opts?: Omit<RequestCallOptions, 'ifMatchVersion'>,\n ) => Promise<ClientSuccess>;\n readonly safeGet: (\n path: string,\n opts?: RequestCallOptions,\n ) => Promise<Result<ClientSuccess, ApiClientError>>;\n readonly safePost: (\n path: string,\n data?: unknown,\n opts?: RequestCallOptions,\n ) => Promise<Result<ClientSuccess, ApiClientError>>;\n readonly safePatch: (\n path: string,\n data?: unknown,\n opts?: RequestCallOptions,\n ) => Promise<Result<ClientSuccess, ApiClientError>>;\n readonly safePut: (\n path: string,\n data?: unknown,\n opts?: RequestCallOptions,\n ) => Promise<Result<ClientSuccess, ApiClientError>>;\n readonly safeDelete: (\n path: string,\n opts?: RequestCallOptions,\n ) => Promise<Result<ClientSuccess, ApiClientError>>;\n readonly safeHead: (\n path: string,\n opts?: RequestCallOptions,\n ) => Promise<Result<ClientSuccess, ApiClientError>>;\n readonly safeRequest: (\n ax: AxiosRequestConfig,\n opts?: RequestCallOptions,\n ) => Promise<Result<ClientSuccess, ApiClientError>>;\n}\n\nfunction readHeader(ax: AxiosRequestConfig, name: string): string | undefined {\n const h = ax.headers as Record<string, string | string[] | undefined> | undefined;\n /* v8 ignore next -- axios always provides a headers object on configs we pass */\n if (!h) return undefined;\n const v = h[name] ?? h[name.toLowerCase()];\n if (Array.isArray(v)) return v[0];\n /* v8 ignore next -- non-string header values are ignored */\n return typeof v === 'string' ? v : undefined;\n}\n\nfunction buildRequestUrl(cfg: AxiosRequestConfig, fallback: string): string {\n if (typeof cfg.url === 'string' && /^https?:\\/\\//i.test(cfg.url)) {\n return cfg.url;\n }\n const base = cfg.baseURL ?? '';\n const p = cfg.url ?? '';\n try {\n return new URL(p, base).href;\n } catch {\n return fallback;\n }\n}\n\nfunction warnInsecureBaseUrl(baseURL: string): void {\n try {\n const u = new URL(baseURL);\n if (u.protocol !== 'http:') return;\n const host = u.hostname.toLowerCase();\n if (host === 'localhost' || host === '127.0.0.1') return;\n console.warn(\n '[@vahidkaargar/customized-api-client] baseURL uses HTTP outside localhost; prefer HTTPS in production.',\n );\n } catch {\n /* invalid URL — skip */\n }\n}\n\nasync function safe(\n fn: () => Promise<ClientSuccess>,\n): Promise<Result<ClientSuccess, ApiClientError>> {\n try {\n const value = await fn();\n return { ok: true, value };\n } catch (e) {\n if (e instanceof ApiClientError) {\n return { ok: false, error: e };\n }\n throw e;\n }\n}\n\nexport function createApiClient(config: ApiClientConfig): ApiClient {\n const mode: BaseUrlMode = config.baseUrlMode ?? 'modeB';\n const genKey = config.generateIdempotencyKey ?? defaultIdempotencyKey;\n warnInsecureBaseUrl(config.baseURL);\n\n const instance: AxiosInstance = axios.create({\n baseURL: config.baseURL,\n timeout: config.timeout ?? DEFAULT_TIMEOUT_MS,\n validateStatus: () => true,\n headers: {\n Accept: 'application/vnd.api+json',\n ...config.defaultHeaders,\n },\n });\n\n instance.interceptors.request.use(async (req) => {\n /* v8 ignore next -- axios sets method on InternalAxiosRequestConfig */\n const method = (req.method ?? 'get').toUpperCase();\n const next = applyJsonApiHeaders(req, method);\n const authHeader = await resolveAuthorizationHeader(config.auth);\n if (authHeader) {\n (next.headers as Record<string, string>).Authorization = authHeader;\n }\n const lang = await resolveAcceptLanguage(config.getAcceptLanguage);\n if (lang) {\n (next.headers as Record<string, string>)['Accept-Language'] = lang;\n }\n if (isMutationMethod(method)) {\n const h = next.headers as Record<string, string | undefined>;\n const existing = h['Idempotency-Key'] ?? h['idempotency-key'];\n const key = typeof existing === 'string' && existing.length > 0 ? existing : genKey();\n assertValidIdempotencyKey(key);\n (next.headers as Record<string, string>)['Idempotency-Key'] = key;\n }\n return next;\n });\n\n instance.interceptors.response.use(\n (res) => {\n const flat = flattenAxiosHeaders(res.headers);\n if (flat['idempotent-replayed'] === 'true' && config.onIdempotencyReplay) {\n config.onIdempotencyReplay({\n /* v8 ignore next 2 -- config url/method are strings from axios */\n url: typeof res.config.url === 'string' ? res.config.url : undefined,\n method: typeof res.config.method === 'string' ? res.config.method : undefined,\n });\n }\n const dep = parseDeprecationHeaders(res.headers);\n if (dep && config.onDeprecated) {\n config.onDeprecated(dep);\n }\n return res;\n },\n (err: unknown) =>\n Promise.reject(\n /* v8 ignore next -- axios rejects with Error; non-Error is defensive */\n err instanceof Error ? err : new Error(String(err)),\n ),\n );\n\n function resolvePath(path: string): string {\n return resolveResourcePath(config.baseURL, path, mode);\n }\n\n async function perform(\n method: string,\n url: string,\n options: RequestCallOptions & { readonly data?: unknown },\n ): Promise<ClientSuccess> {\n const headers: Record<string, string> = {};\n if (options.idempotencyKey !== undefined) {\n assertValidIdempotencyKey(options.idempotencyKey);\n headers['Idempotency-Key'] = options.idempotencyKey;\n }\n if (options.ifMatchVersion !== undefined) {\n headers['If-Match'] = formatIfMatch(options.ifMatchVersion);\n }\n\n const axConfig: AxiosRequestConfig = {\n method,\n url,\n data: options.data,\n headers: { ...headers },\n };\n\n try {\n const response = await dispatchWithRetry(instance, axConfig, {\n retry: config.retry,\n });\n try {\n return normalizeAxiosResponse(response, {\n transformResponseKeys: config.transformResponseKeys,\n requestUrl: buildRequestUrl(response.config, url),\n requestMethod: method.toUpperCase(),\n });\n } catch (e: unknown) {\n if (e instanceof ApiClientError && e.status === 401 && config.onUnauthorized) {\n await config.onUnauthorized(e);\n }\n throw e;\n }\n } catch (err: unknown) {\n if (isAxiosError(err) && err.response) {\n const res = err.response as AxiosResponse<unknown>;\n try {\n return normalizeAxiosResponse(res, {\n transformResponseKeys: config.transformResponseKeys,\n requestUrl: buildRequestUrl(res.config, url),\n requestMethod: method.toUpperCase(),\n });\n } catch (e: unknown) {\n if (e instanceof ApiClientError && e.status === 401 && config.onUnauthorized) {\n await config.onUnauthorized(e);\n }\n throw e;\n }\n }\n throw err;\n }\n }\n\n const client: ApiClient = {\n async get(path: string, opts?: RequestCallOptions): Promise<ClientSuccess> {\n return perform('GET', resolvePath(path), opts ?? {});\n },\n async head(path: string, opts?: RequestCallOptions): Promise<ClientSuccess> {\n return perform('HEAD', resolvePath(path), opts ?? {});\n },\n async post(path: string, data?: unknown, opts?: RequestCallOptions): Promise<ClientSuccess> {\n return perform('POST', resolvePath(path), { ...opts, data });\n },\n async patch(path: string, data?: unknown, opts?: RequestCallOptions): Promise<ClientSuccess> {\n return perform('PATCH', resolvePath(path), { ...opts, data });\n },\n async put(path: string, data?: unknown, opts?: RequestCallOptions): Promise<ClientSuccess> {\n return perform('PUT', resolvePath(path), { ...opts, data });\n },\n async delete(path: string, opts?: RequestCallOptions): Promise<ClientSuccess> {\n return perform('DELETE', resolvePath(path), opts ?? {});\n },\n async request(ax: AxiosRequestConfig, opts?: RequestCallOptions): Promise<ClientSuccess> {\n /* v8 ignore next 2 -- method/url defaults match axios when omitted */\n const method = (ax.method ?? 'GET').toUpperCase();\n const rawUrl = ax.url ?? '/';\n const u =\n /* v8 ignore next -- axios types url as string; non-string is defensive */\n typeof rawUrl === 'string' && /^https?:\\/\\//i.test(rawUrl)\n ? rawUrl\n : resolvePath(rawUrl);\n return perform(method, u, {\n ...opts,\n data: ax.data,\n idempotencyKey: opts?.idempotencyKey ?? readHeader(ax, 'Idempotency-Key'),\n });\n },\n async getByUrl(fullUrl: string, opts?: RequestCallOptions): Promise<ClientSuccess> {\n return perform('GET', fullUrl, opts ?? {});\n },\n async patchWithVersion(\n path: string,\n data: unknown,\n version: number,\n opts?: Omit<RequestCallOptions, 'ifMatchVersion'>,\n ): Promise<ClientSuccess> {\n return perform('PATCH', resolvePath(path), {\n ...opts,\n data,\n ifMatchVersion: version,\n });\n },\n safeGet: (path, opts) => safe(() => client.get(path, opts)),\n safePost: (path, data, opts) => safe(() => client.post(path, data, opts)),\n safePatch: (path, data, opts) => safe(() => client.patch(path, data, opts)),\n safePut: (path, data, opts) => safe(() => client.put(path, data, opts)),\n safeDelete: (path, opts) => safe(() => client.delete(path, opts)),\n safeHead: (path, opts) => safe(() => client.head(path, opts)),\n safeRequest: (ax, opts) => safe(() => client.request(ax, opts)),\n };\n\n return client;\n}\n","/** Mode B (default): `baseURL` already includes `/api/v1`. Mode A: origin only; client prefixes `/api/v1`. */\nexport type BaseUrlMode = 'modeB' | 'modeA';\n\nexport type AuthConfig =\n | { readonly type: 'bearer'; readonly getToken: TokenProvider }\n | { readonly type: 'partner-bearer'; readonly getSecret: TokenProvider };\n\nexport type TokenProvider = () =>\n | string\n | null\n | undefined\n | Promise<string | null | undefined>;\n\nexport type TransformResponseKeysMode = 'none' | 'camelCase-attributes-meta';\n\nexport interface RetryOptions {\n readonly maxAttempts?: number;\n readonly baseDelayMs?: number;\n readonly maxDelayMs?: number;\n readonly jitterRatio?: number;\n}\n\nexport interface IdempotencyReplayContext {\n readonly url?: string;\n readonly method?: string;\n}\n\nexport interface ApiClientConfig {\n readonly baseURL: string;\n /** Default Mode B — see `BaseUrlMode`. */\n readonly baseUrlMode?: BaseUrlMode;\n readonly auth?: AuthConfig;\n readonly getAcceptLanguage?: () => string | null | undefined | Promise<string | null | undefined>;\n readonly defaultHeaders?: Readonly<Record<string, string>>;\n readonly timeout?: number;\n readonly retry?: RetryOptions;\n readonly generateIdempotencyKey?: () => string;\n readonly onIdempotencyReplay?: (ctx: Readonly<IdempotencyReplayContext>) => void;\n readonly onUnauthorized?: (error: unknown) => void | Promise<void>;\n readonly onDeprecated?: (info: Readonly<DeprecationInfo>) => void;\n readonly transformResponseKeys?: TransformResponseKeysMode;\n readonly maxBodyLogLength?: number;\n}\n\nexport interface DeprecationInfo {\n readonly deprecation?: string;\n readonly sunset?: string;\n readonly rawHeaders: Readonly<Record<string, string>>;\n}\n\nexport const DEFAULT_TIMEOUT_MS = 30_000;\nexport const DEFAULT_PAGE_SIZE_CAP = 100;\n","import type { InternalAxiosRequestConfig } from 'axios';\n\nconst JSON_API = 'application/vnd.api+json';\n\nexport function applyJsonApiHeaders(\n config: InternalAxiosRequestConfig,\n method: string,\n): InternalAxiosRequestConfig {\n const m = method.toUpperCase();\n const headers = { ...(config.headers as Record<string, string> | undefined) };\n headers.Accept = headers.Accept ?? JSON_API;\n if (hasJsonBody(m, config)) {\n headers['Content-Type'] = headers['Content-Type'] ?? JSON_API;\n }\n return { ...config, headers } as InternalAxiosRequestConfig;\n}\n\nfunction hasJsonBody(method: string, config: InternalAxiosRequestConfig): boolean {\n if (!['POST', 'PATCH', 'PUT'].includes(method)) return false;\n return config.data !== undefined && config.data !== null;\n}\n","import type { AuthConfig } from '../types/config.ts';\n\nexport async function resolveAuthorizationHeader(auth: AuthConfig | undefined): Promise<\n string | undefined\n> {\n if (!auth) return undefined;\n if (auth.type === 'bearer') {\n const t = await auth.getToken();\n if (!t) return undefined;\n return `Bearer ${t}`;\n }\n const s = await auth.getSecret();\n if (!s) return undefined;\n return `Bearer ${s}`;\n}\n","export async function resolveAcceptLanguage(\n provider?: () =>\n | string\n | null\n | undefined\n | Promise<string | null | undefined>,\n): Promise<string | undefined> {\n if (!provider) return undefined;\n const v = await provider();\n return v ?? undefined;\n}\n","import { ulid } from 'ulid';\n\nexport const IDEMPOTENCY_MAX_LENGTH = 64;\n\nexport function defaultIdempotencyKey(): string {\n return ulid();\n}\n\nexport function assertValidIdempotencyKey(key: string): void {\n if (!key || key.trim().length === 0) {\n throw new Error('Idempotency-Key must be non-empty');\n }\n if (key.length > IDEMPOTENCY_MAX_LENGTH) {\n throw new Error(`Idempotency-Key exceeds ${String(IDEMPOTENCY_MAX_LENGTH)} characters`);\n }\n}\n\nexport function isMutationMethod(method: string): boolean {\n const m = method.toUpperCase();\n return m === 'POST' || m === 'PATCH' || m === 'PUT' || m === 'DELETE';\n}\n","export function formatIfMatch(version: number): string {\n if (!Number.isFinite(version) || version < 0) {\n throw new Error('If-Match version must be a non-negative finite number');\n }\n return `\"v=${String(version)}\"`;\n}\n","import type { BaseUrlMode } from '../types/config.ts';\n\n/**\n * Path for axios `url` (combined with `baseURL`). No duplicate `/api/v1`, no `//`.\n */\nexport function resolveResourcePath(baseURL: string, path: string, mode: BaseUrlMode): string {\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n const base = baseURL.replace(/\\/+$/, '');\n\n if (mode === 'modeB') {\n if (normalizedPath.startsWith('/api/v1/') && base.endsWith('/api/v1')) {\n const rest = normalizedPath.slice('/api/v1'.length);\n /* v8 ignore next -- rest is always non-empty when path starts with /api/v1/ */\n return rest.length > 0 ? rest : '/';\n }\n return normalizedPath;\n }\n\n return normalizedPath.startsWith('/api/v1') ? normalizedPath : `/api/v1${normalizedPath}`;\n}\n\n/**\n * Prepare request URL for axios — if `fullUrl` is absolute http(s), return as-is for getByUrl.\n */\nexport function normalizeHttpUrl(fullUrl: string): string {\n return fullUrl;\n}\n","export interface RetryPolicyContext {\n readonly method: string;\n readonly status?: number;\n /** First JSON:API error `code` when present */\n readonly primaryErrorCode?: string;\n readonly isNetworkError: boolean;\n}\n\n/** Pure policy per [.cursor/tasks/project-plan.md §7](../tasks/project-plan.md). */\nexport function retryAllowed(ctx: RetryPolicyContext): boolean {\n const m = ctx.method.toUpperCase();\n const isRead = m === 'GET' || m === 'HEAD';\n\n if (ctx.isNetworkError) {\n return true;\n }\n\n const s = ctx.status;\n if (s === undefined) return false;\n\n if (s === 401 || s === 403 || s === 412 || s === 428) return false;\n if (s === 422 || s === 400 || s === 406 || s === 415 || s === 413) return false;\n\n if (s === 409) {\n if (ctx.primaryErrorCode === 'IDEMPOTENCY_KEY_REUSED') return false;\n if (ctx.primaryErrorCode === 'IDEMPOTENCY_REQUEST_IN_PROGRESS') return true;\n return false;\n }\n\n if (!isRead) {\n return false;\n }\n\n if (s === 408) return true;\n if (s === 429) return true;\n if (s >= 502 && s <= 504) return true;\n if (s >= 500 && s < 600) return true;\n\n return false;\n}\n","/** Parse Retry-After header: delta-seconds or HTTP-date. */\nexport function parseRetryAfterSeconds(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const n = Number.parseInt(value, 10);\n if (!Number.isNaN(n)) return n;\n const ms = Date.parse(value);\n if (!Number.isNaN(ms)) {\n return Math.max(0, Math.ceil((ms - Date.now()) / 1000));\n }\n return undefined;\n}\n","export type HeadersLike = Headers | Record<string, string | undefined>;\n\nexport function flattenAxiosHeaders(\n headers: unknown,\n): Record<string, string> {\n if (!headers) return {};\n if (typeof (headers as Headers).forEach === 'function') {\n const out: Record<string, string> = {};\n (headers as Headers).forEach((value, key) => {\n out[key.toLowerCase()] = value;\n });\n return out;\n }\n const o = headers as Record<string, string | string[] | undefined>;\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(o)) {\n if (typeof v === 'string') out[k.toLowerCase()] = v;\n else if (Array.isArray(v) && v[0]) out[k.toLowerCase()] = v[0];\n }\n return out;\n}\n\nexport function getHeader(headers: Record<string, string>, name: string): string | undefined {\n return headers[name.toLowerCase()];\n}\n","import type {\n AxiosError,\n AxiosInstance,\n AxiosRequestConfig,\n AxiosResponse,\n InternalAxiosRequestConfig,\n} from 'axios';\nimport { retryAllowed } from './policy.ts';\nimport type { RetryOptions } from '../types/config.ts';\nimport { parseRetryAfterSeconds } from './retry-after.ts';\nimport { flattenAxiosHeaders } from '../http/header-utils.ts';\n\nexport interface DispatchOptions {\n readonly retry?: RetryOptions;\n readonly getPrimaryErrorCodeFromBody?: (body: unknown) => string | undefined;\n}\n\nconst DEFAULT_MAX_ATTEMPTS = 4;\nconst DEFAULT_BASE_MS = 200;\n\nexport async function dispatchWithRetry<TData = unknown>(\n instance: AxiosInstance,\n config: AxiosRequestConfig,\n options: DispatchOptions,\n): Promise<AxiosResponse<TData>> {\n const max = options.retry?.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n const baseDelay = options.retry?.baseDelayMs ?? DEFAULT_BASE_MS;\n const maxDelay = options.retry?.maxDelayMs ?? 10_000;\n const jitterRatio = options.retry?.jitterRatio ?? 0.2;\n\n let attempt = 0;\n let lastResponse: AxiosResponse<TData> | undefined;\n\n while (attempt < max) {\n try {\n const res = await instance.request<TData>(config as InternalAxiosRequestConfig);\n lastResponse = res;\n const status = res.status;\n const flat = flattenAxiosHeaders(res.headers);\n const primary =\n status >= 400\n ? extractPrimaryCode(res.data, options.getPrimaryErrorCodeFromBody)\n : undefined;\n const allowed = retryAllowed({\n method: String(config.method ?? 'GET'),\n status,\n primaryErrorCode: primary,\n isNetworkError: false,\n });\n if (allowed && attempt < max - 1) {\n const retryAfter = parseRetryAfterSeconds(flat['retry-after']);\n const delayMs = computeDelay(\n attempt,\n baseDelay,\n maxDelay,\n jitterRatio,\n retryAfter,\n );\n await sleep(delayMs);\n attempt += 1;\n continue;\n }\n return res;\n } catch (err: unknown) {\n const isNet = isAxiosNetworkError(err);\n const allowed = retryAllowed({\n method: String(config.method ?? 'GET'),\n isNetworkError: isNet,\n });\n if (!allowed || attempt >= max - 1) {\n throw err;\n }\n const delayMs = computeDelay(attempt, baseDelay, maxDelay, jitterRatio, undefined);\n await sleep(delayMs);\n attempt += 1;\n }\n }\n\n /* v8 ignore next 2 -- loop always returns or throws before attempt reaches max */\n if (lastResponse) return lastResponse;\n throw new Error('dispatchWithRetry: exhausted without response');\n}\n\nfunction extractPrimaryCode(\n body: unknown,\n fn?: (b: unknown) => string | undefined,\n): string | undefined {\n if (fn) return fn(body);\n if (body && typeof body === 'object' && 'errors' in body) {\n const errors = (body as { errors?: { code?: string }[] }).errors;\n if (Array.isArray(errors) && errors[0]?.code) {\n return errors[0].code;\n }\n }\n return undefined;\n}\n\nfunction isAxiosNetworkError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Partial<AxiosError>;\n return e.isAxiosError === true && !e.response;\n}\n\nfunction computeDelay(\n attempt: number,\n base: number,\n max: number,\n jitterRatio: number,\n retryAfterSec: number | undefined,\n): number {\n let exp = Math.min(max, base * 2 ** attempt);\n if (retryAfterSec !== undefined) {\n exp = Math.min(max, Math.max(exp, retryAfterSec * 1000));\n }\n const jitter = exp * jitterRatio * (Math.random() * 2 - 1);\n return Math.max(0, Math.round(exp + jitter));\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","import type { JsonApiDocument } from '../types/jsonapi.ts';\n\nexport function parseJsonApiDocument(payload: unknown): JsonApiDocument {\n if (!payload || typeof payload !== 'object') {\n throw new TypeError('JSON:API document must be an object');\n }\n const o = payload as Record<string, unknown>;\n if (!('data' in o)) {\n throw new TypeError('JSON:API document must include \"data\"');\n }\n return payload as JsonApiDocument;\n}\n","const DEFAULT_MAX_BODY_LOG = 2048;\n\n/**\n * Truncate a value for safe logging (respects `maxBodyLogLength` from config when passed).\n */\nexport function truncateForLog(body: unknown, maxLen = DEFAULT_MAX_BODY_LOG): string {\n let s: string;\n try {\n s = typeof body === 'string' ? body : JSON.stringify(body);\n } catch {\n s = '[Unserializable]';\n }\n if (s.length <= maxLen) return s;\n return `${s.slice(0, maxLen)}…`;\n}\n\n/**\n * Redact sensitive header values for logging and error surfaces.\n */\nexport function redactHeaderRecord(headers: Record<string, string>): Record<string, string> {\n const out: Record<string, string> = { ...headers };\n for (const key of Object.keys(out)) {\n const lower = key.toLowerCase();\n if (lower === 'authorization' || lower === 'idempotency-key') {\n out[key] = '[REDACTED]';\n }\n }\n return out;\n}\n","import type { JsonApiErrorObject } from './jsonapi.ts';\nimport { redactHeaderRecord } from '../security/redact.ts';\n\nexport class ApiClientError extends Error {\n readonly name = 'ApiClientError';\n\n constructor(\n readonly status: number,\n readonly errors: readonly JsonApiErrorObject[],\n readonly primaryCode?: string,\n readonly responseHeaders?: Readonly<Record<string, string>>,\n readonly retryAfterSeconds?: number,\n readonly requestMethod?: string,\n options?: ErrorOptions,\n ) {\n super(ApiClientError.#messageFrom(errors, status), options);\n }\n\n static #messageFrom(errors: readonly JsonApiErrorObject[], status: number): string {\n const first = errors[0];\n const code = first?.code ?? '';\n const detail = first?.detail ?? first?.title ?? '';\n const base = detail || code || `HTTP ${String(status)}`;\n return `[ApiClientError ${String(status)}] ${base}`;\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n status: this.status,\n errors: this.errors,\n primaryCode: this.primaryCode,\n retryAfterSeconds: this.retryAfterSeconds,\n requestMethod: this.requestMethod,\n responseHeaders: this.responseHeaders\n ? redactHeaderRecord({ ...this.responseHeaders })\n : undefined,\n };\n }\n}\n\nexport function isApiClientError(value: unknown): value is ApiClientError {\n return value instanceof ApiClientError;\n}\n","import { ApiClientError } from '../types/api-client-error.ts';\nimport type { JsonApiErrorDocument, JsonApiErrorObject } from '../types/jsonapi.ts';\n\nexport function parseJsonApiErrorBody(\n status: number,\n rawBody: unknown,\n headers: Readonly<Record<string, string>>,\n requestMethod?: string,\n): ApiClientError {\n const retryAfterSeconds = headers['retry-after']\n ? parseRetryAfterHeader(headers['retry-after'])\n : undefined;\n\n if (rawBody === null || rawBody === undefined || rawBody === '') {\n return new ApiClientError(\n status,\n [{ detail: `HTTP ${String(status)}`, code: 'EMPTY_ERROR_BODY' }],\n 'EMPTY_ERROR_BODY',\n headers,\n retryAfterSeconds,\n requestMethod,\n );\n }\n\n if (typeof rawBody === 'string') {\n try {\n const parsed: unknown = JSON.parse(rawBody);\n return parseFromObject(status, parsed, headers, retryAfterSeconds, requestMethod);\n } catch {\n return syntheticError(status, 'INVALID_JSON', 'Response body is not valid JSON', requestMethod);\n }\n }\n\n if (typeof rawBody === 'object') {\n return parseFromObject(status, rawBody, headers, retryAfterSeconds, requestMethod);\n }\n\n return syntheticError(\n status,\n 'INVALID_ERROR_DOCUMENT',\n 'Unknown error payload shape',\n requestMethod,\n );\n}\n\nfunction parseFromObject(\n status: number,\n body: unknown,\n headers: Readonly<Record<string, string>>,\n retryAfterSeconds: number | undefined,\n requestMethod?: string,\n): ApiClientError {\n if (!body || typeof body !== 'object') {\n return syntheticError(\n status,\n 'INVALID_ERROR_DOCUMENT',\n 'Error payload must be an object',\n requestMethod,\n );\n }\n const doc = body as Partial<JsonApiErrorDocument>;\n const errors = doc.errors;\n if (!Array.isArray(errors) || errors.length === 0) {\n return syntheticError(\n status,\n 'MISSING_ERRORS_ARRAY',\n 'errors[] missing or empty',\n requestMethod,\n );\n }\n const list = errors as JsonApiErrorObject[];\n const primaryCode = list[0]?.code;\n return new ApiClientError(status, list, primaryCode, headers, retryAfterSeconds, requestMethod);\n}\n\nfunction syntheticError(\n status: number,\n code: string,\n detail: string,\n requestMethod?: string,\n): ApiClientError {\n return new ApiClientError(status, [{ code, detail }], code, undefined, undefined, requestMethod);\n}\n\nfunction parseRetryAfterHeader(v: string): number | undefined {\n const n = Number.parseInt(v, 10);\n if (!Number.isNaN(n)) return n;\n const ms = Date.parse(v);\n if (!Number.isNaN(ms)) {\n const delta = Math.max(0, Math.ceil((ms - Date.now()) / 1000));\n return delta;\n }\n return undefined;\n}\n","import type { MultiStatusItem } from '../types/results.ts';\n\n/**\n * Best-effort normalization for 207 bodies — structure varies by backend.\n */\nexport function parseMultiStatusBody(raw: unknown): readonly MultiStatusItem[] {\n if (raw && typeof raw === 'object' && 'items' in raw) {\n const items = (raw as { items?: unknown }).items;\n if (Array.isArray(items)) {\n return items.map((it) => normalizeItem(it));\n }\n }\n if (Array.isArray(raw)) {\n return raw.map((it) => normalizeItem(it));\n }\n return [{ httpStatus: 500, body: raw }];\n}\n\nfunction normalizeItem(it: unknown): MultiStatusItem {\n if (it && typeof it === 'object') {\n const o = it as Record<string, unknown>;\n const s = o.httpStatus ?? o.status;\n const httpStatus = typeof s === 'number' && Number.isFinite(s) ? s : 500;\n return { httpStatus, body: o.body ?? o.response ?? it };\n }\n return { httpStatus: 500, body: it };\n}\n","import { flattenAxiosHeaders, getHeader } from '../http/header-utils.ts';\nimport type { HeadersLike } from '../http/header-utils.ts';\n\n/**\n * Resolve absolute Location for 202 per project-plan (relative to response URL when needed).\n */\nexport function resolveAcceptedLocation(headers: HeadersLike, requestUrl: string): string {\n const flat = flattenAxiosHeaders(headers);\n const loc = getHeader(flat, 'location');\n if (!loc) return requestUrl;\n try {\n return new URL(loc, requestUrl).href;\n } catch {\n return loc;\n }\n}\n","import type { JsonApiDocument } from '../types/jsonapi.ts';\nimport type { TransformResponseKeysMode } from '../types/config.ts';\n\n/** Shallow camelCase keys for `attributes` and `meta` only — copies document where needed. */\nexport function applyTransformKeys(\n doc: JsonApiDocument,\n mode: TransformResponseKeysMode,\n): JsonApiDocument {\n if (mode === 'none') return doc;\n\n const data = doc.data;\n const mapResource = (r: object): object => {\n const o = { ...r } as Record<string, unknown>;\n if (o.attributes && typeof o.attributes === 'object') {\n o.attributes = camelKeys(o.attributes as Record<string, unknown>);\n }\n if (o.meta && typeof o.meta === 'object') {\n o.meta = camelKeys(o.meta as Record<string, unknown>);\n }\n return o;\n };\n\n if (data === null) {\n return {\n ...doc,\n meta: doc.meta ? camelKeys(doc.meta) : doc.meta,\n };\n }\n\n if (Array.isArray(data)) {\n return {\n ...doc,\n data: data.map((r) => mapResource(r as object)) as JsonApiDocument['data'],\n meta: doc.meta ? camelKeys(doc.meta) : doc.meta,\n };\n }\n\n return {\n ...doc,\n data: mapResource(data) as JsonApiDocument['data'],\n /* v8 ignore next -- document meta absent on single-resource responses */\n meta: doc.meta ? camelKeys(doc.meta) : doc.meta,\n };\n}\n\nfunction camelKeys(obj: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(obj)) {\n out[toCamelCase(k)] = v;\n }\n return out;\n}\n\nfunction toCamelCase(s: string): string {\n return s.replace(/_([a-z])/g, (_, c: string) => c.toUpperCase());\n}\n","import type { AxiosResponse } from 'axios';\nimport { parseJsonApiDocument } from '../parse/success.ts';\nimport { parseJsonApiErrorBody } from '../parse/errors.ts';\nimport { parseMultiStatusBody } from '../parse/bulk-207.ts';\nimport { resolveAcceptedLocation } from '../parse/accepted-202.ts';\nimport { ApiClientError } from '../types/api-client-error.ts';\nimport { flattenAxiosHeaders, getHeader } from './header-utils.ts';\nimport type { TransformResponseKeysMode } from '../types/config.ts';\nimport { applyTransformKeys } from '../helpers/transform-keys.ts';\nimport type { ClientSuccess, JsonApiSuccessBody, NormalizedResponseHeaders } from '../types/results.ts';\nimport type { JsonApiDocument } from '../types/jsonapi.ts';\nimport { parseRetryAfterSeconds } from '../retry/retry-after.ts';\n\nexport interface NormalizeOptions {\n readonly transformResponseKeys?: TransformResponseKeysMode;\n readonly requestUrl: string;\n readonly requestMethod?: string;\n}\n\nexport function normalizeAxiosResponse(\n response: AxiosResponse<unknown>,\n options: NormalizeOptions,\n): ClientSuccess {\n const status = response.status;\n const headers = flattenAxiosHeaders(response.headers);\n\n if (status >= 400) {\n throw parseJsonApiErrorBody(status, response.data, headers, options.requestMethod);\n }\n\n const normHeaders = normalizeHeaders(headers);\n\n if (status === 204) {\n return { kind: 'no-content', status: 204, headers: normHeaders };\n }\n\n if (status === 202) {\n const location = resolveAcceptedLocation(headers, options.requestUrl);\n return {\n kind: 'accepted',\n status: 202,\n location,\n rawBody: response.data,\n headers: normHeaders,\n };\n }\n\n if (status === 207) {\n return {\n kind: 'multi-status',\n status: 207,\n items: parseMultiStatusBody(response.data),\n headers: normHeaders,\n };\n }\n\n if (status === 200 || status === 201) {\n const doc = parseJsonApiDocument(response.data);\n const transformed = applyTransformResponse(\n doc,\n options.transformResponseKeys ?? 'none',\n );\n const body: JsonApiSuccessBody = {\n kind: 'jsonapi-success',\n status: status,\n headers: normHeaders,\n document: transformed,\n };\n return body;\n }\n\n throw new ApiClientError(\n status,\n [{ code: 'UNSUPPORTED_SUCCESS_STATUS', detail: String(status) }],\n 'UNSUPPORTED_SUCCESS_STATUS',\n headers,\n parseRetryAfterSeconds(getHeader(headers, 'retry-after')),\n options.requestMethod,\n );\n}\n\nfunction normalizeHeaders(headers: Record<string, string>): NormalizedResponseHeaders {\n const idem = getHeader(headers, 'idempotent-replayed');\n return {\n etag: getHeader(headers, 'etag'),\n contentLanguage: getHeader(headers, 'content-language'),\n idempotentReplayed: idem === 'true' || idem === 'True',\n retryAfterSeconds: parseRetryAfterSeconds(getHeader(headers, 'retry-after')),\n };\n}\n\nfunction applyTransformResponse(\n doc: JsonApiDocument,\n mode: TransformResponseKeysMode,\n): JsonApiDocument {\n if (mode === 'none') return doc;\n return applyTransformKeys(doc, mode);\n}\n","import { flattenAxiosHeaders } from '../http/header-utils.ts';\nimport type { DeprecationInfo } from '../types/config.ts';\n\nexport function parseDeprecationHeaders(headerBag: unknown): DeprecationInfo | null {\n const flat = flattenAxiosHeaders(headerBag);\n const dep = flat.deprecation;\n const sunset = flat.sunset;\n if (!dep && !sunset) return null;\n return {\n deprecation: dep,\n sunset,\n rawHeaders: flat,\n };\n}\n","import { ApiClientError } from './types/api-client-error.ts';\nimport { retryAllowed } from './retry/policy.ts';\n\nexport function isAuthenticationError(e: unknown): boolean {\n return isApiErr(e, 401);\n}\n\nexport function isForbiddenError(e: unknown): boolean {\n return isApiErr(e, 403);\n}\n\nexport function isPreconditionRequiredError(e: unknown): boolean {\n return isApiErr(e, 428);\n}\n\nexport function isPreconditionFailedError(e: unknown): boolean {\n return isApiErr(e, 412);\n}\n\nexport function isValidationError(e: unknown): boolean {\n return isApiErr(e, 422);\n}\n\nexport function isConflictError(e: unknown): boolean {\n return isApiErr(e, 409);\n}\n\nexport function isPayloadTooLargeError(e: unknown): boolean {\n return isApiErr(e, 413);\n}\n\nexport function isRetryablePerPolicy(e: unknown): boolean {\n if (!(e instanceof ApiClientError)) return false;\n return retryAllowed({\n method: e.requestMethod ?? 'GET',\n status: e.status,\n primaryErrorCode: e.primaryCode,\n isNetworkError: false,\n });\n}\n\nfunction isApiErr(e: unknown, status: number): boolean {\n return e instanceof ApiClientError && e.status === status;\n}\n","export interface OffsetPagination {\n readonly kind: 'offset';\n readonly page: number;\n readonly totalPages?: number;\n readonly total?: number;\n}\n\nexport interface CursorPagination {\n readonly kind: 'cursor';\n readonly hasMore: boolean;\n readonly nextCursor?: string;\n}\n\nexport interface UnknownPagination { readonly kind: 'unknown' }\n\nexport function parsePaginationKind(\n meta: Readonly<Record<string, unknown>> | undefined,\n links: Readonly<Record<string, string | null | undefined>> | undefined,\n): OffsetPagination | CursorPagination | UnknownPagination {\n const m = meta ?? {};\n const linksNext = typeof links?.next === 'string' ? links.next : undefined;\n\n if (linksNext) {\n const fromCursor =\n extractQueryParam(linksNext, 'page[cursor]') ??\n extractQueryParam(linksNext, 'page%5Bcursor%5D');\n if (fromCursor) {\n return { kind: 'cursor', hasMore: true, nextCursor: fromCursor };\n }\n\n const legacy = parseLegacyOffsetFromUrl(linksNext);\n if (legacy) return legacy;\n }\n\n const lastPage = num(m.last_page);\n const current = num(m.current_page) ?? num(m.page);\n const total = num(m.total);\n const hasMore = bool(m.has_more);\n\n if (lastPage !== undefined || current !== undefined || total !== undefined) {\n return {\n kind: 'offset',\n page: current ?? 1,\n totalPages: lastPage,\n total,\n };\n }\n\n if (hasMore !== undefined) {\n return {\n kind: 'cursor',\n hasMore,\n nextCursor: typeof m.next_cursor === 'string' ? m.next_cursor : undefined,\n };\n }\n\n return { kind: 'unknown' };\n}\n\nexport function getNextPageUrl(\n links: Readonly<Record<string, string | null | undefined>> | undefined,\n): string | undefined {\n const n = links?.next;\n return typeof n === 'string' ? n : undefined;\n}\n\nfunction parseLegacyOffsetFromUrl(url: string): OffsetPagination | undefined {\n try {\n const u = new URL(url, 'http://local.test');\n const hasPerPage = u.searchParams.has('per_page');\n const pagePlain = u.searchParams.get('page');\n const pageBracket = u.searchParams.get('page[number]');\n if (!hasPerPage && !pagePlain && !pageBracket) return undefined;\n const pageNum = num(pagePlain) ?? num(pageBracket) ?? 1;\n return { kind: 'offset', page: pageNum, totalPages: undefined, total: undefined };\n } catch {\n return undefined;\n }\n}\n\nfunction num(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string' && /^-?\\d+$/.test(v)) return Number.parseInt(v, 10);\n return undefined;\n}\n\nfunction bool(v: unknown): boolean | undefined {\n if (typeof v === 'boolean') return v;\n return undefined;\n}\n\nfunction extractQueryParam(url: string, key: string): string | null {\n try {\n const u = new URL(url, 'http://local.test');\n return u.searchParams.get(key) ?? u.searchParams.get(key.replace(/\\[/g, '').replace(/\\]/g, ''));\n } catch {\n return null;\n }\n}\n","import { DEFAULT_PAGE_SIZE_CAP } from '../types/config.ts';\n\nexport interface JsonApiQueryInput {\n readonly filter?: Readonly<Record<string, string | number | boolean | undefined>>;\n readonly sort?: readonly string[];\n readonly fields?: Readonly<Record<string, readonly string[]>>;\n readonly include?: readonly string[];\n}\n\nexport function buildJsonApiQuery(input: JsonApiQueryInput): Record<string, string> {\n const params: Record<string, string> = {};\n if (input.filter) {\n for (const [k, v] of Object.entries(input.filter)) {\n if (v === undefined) continue;\n params[`filter[${k}]`] = String(v);\n }\n }\n if (input.sort?.length) {\n params.sort = input.sort.join(',');\n }\n if (input.fields) {\n for (const [type, fields] of Object.entries(input.fields)) {\n params[`fields[${type}]`] = fields.join(',');\n }\n }\n if (input.include?.length) {\n params.include = input.include.join(',');\n }\n return params;\n}\n\nexport function buildOffsetPageParams(input: {\n readonly number: number;\n readonly size: number;\n}): Record<string, string | number> {\n const size = Math.min(Math.max(1, input.size), DEFAULT_PAGE_SIZE_CAP);\n return {\n 'page[number]': input.number,\n 'page[size]': size,\n };\n}\n\nexport function buildCursorPageParams(input: {\n readonly cursor: string;\n readonly size: number;\n}): Record<string, string | number> {\n const size = Math.min(Math.max(1, input.size), DEFAULT_PAGE_SIZE_CAP);\n return {\n 'page[cursor]': input.cursor,\n 'page[size]': size,\n };\n}\n","import type { JsonApiResourceLinkage, JsonApiResourceObject } from '../types/jsonapi.ts';\n\nexport type IncludedIndex = ReadonlyMap<string, JsonApiResourceObject>;\n\nexport function indexIncluded(\n included: readonly JsonApiResourceObject[] | undefined,\n): IncludedIndex {\n const map = new Map<string, JsonApiResourceObject>();\n if (!included) return map;\n for (const r of included) {\n map.set(`${r.type}:${r.id}`, r);\n }\n return map;\n}\n\nexport function resolveIncluded(\n ref: JsonApiResourceLinkage,\n index: IncludedIndex,\n): JsonApiResourceObject | undefined {\n return index.get(`${ref.type}:${ref.id}`);\n}\n","import type { JsonApiResourceObject } from '../types/jsonapi.ts';\nimport { flattenAxiosHeaders, getHeader } from '../http/header-utils.ts';\n\nexport function readResourceVersion(\n resource: JsonApiResourceObject,\n etagHeader?: string ,\n): number | undefined {\n const meta = resource.meta;\n const mv = meta?.version;\n const fromMeta = coerceUnsigned(mv);\n if (fromMeta !== undefined) return fromMeta;\n\n const etag = etagHeader;\n if (typeof etag === 'string') {\n const m = /v=(\\d+)/i.exec(etag);\n if (m?.[1]) return Number.parseInt(m[1], 10);\n }\n return undefined;\n}\n\nfunction coerceUnsigned(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v) && v >= 0) return v;\n if (typeof v === 'string' && /^\\d+$/.test(v)) return Number.parseInt(v, 10);\n return undefined;\n}\n\nexport function etagFromResponseHeaders(headerBag: unknown): string | undefined {\n const h = flattenAxiosHeaders(headerBag);\n return getHeader(h, 'etag');\n}\n","import type { JsonApiErrorObject } from '../types/jsonapi.ts';\n\nexport type ValidationGroups = Record<string, readonly string[]>;\n\nexport function groupValidationErrorsByPointer(\n errors: readonly JsonApiErrorObject[],\n): ValidationGroups {\n const out: Record<string, string[]> = {};\n for (const e of errors) {\n const ptr = e.source?.pointer ?? '/';\n /* v8 ignore next -- detail/title/code chain; exhaustive cases covered in tests */\n const msg = e.detail ?? e.title ?? e.code ?? 'Error';\n out[ptr] ??= [];\n out[ptr].push(msg);\n }\n return out;\n}\n","import type { ApiClientConfig } from '../types/config.ts';\nimport { createApiClient } from '../create-api-client.ts';\n\nexport function createHealthCheck(\n target: ApiClientConfig | Pick<HealthGettable, 'get'>,\n): () => Promise<boolean> {\n const client = isGettable(target) ? target : createApiClient(target);\n\n return async () => {\n try {\n await client.get('/health/live');\n return true;\n } catch {\n return false;\n }\n };\n}\n\ninterface HealthGettable {\n get: (path: string) => Promise<unknown>;\n}\n\nfunction isGettable(\n target: ApiClientConfig | Pick<HealthGettable, 'get'>,\n): target is Pick<HealthGettable, 'get'> {\n return typeof (target as HealthGettable).get === 'function';\n}\n","import type { ClientSuccess } from './types/results.ts';\nimport type { ApiClient } from './create-api-client.ts';\n\nexport interface PollOptions {\n readonly maxAttempts?: number;\n readonly delayMs?: number;\n}\n\nexport async function pollAsyncResult(\n client: ApiClient,\n initial: Extract<ClientSuccess, { kind: 'accepted' }>,\n options?: PollOptions,\n): Promise<ClientSuccess> {\n const max = options?.maxAttempts ?? 10;\n const delay = options?.delayMs ?? 200;\n let url = initial.location;\n for (let i = 0; i < max; i += 1) {\n const res = await client.getByUrl(url);\n if (res.kind !== 'accepted') return res;\n url = res.location;\n await sleep(delay);\n }\n throw new Error('pollAsyncResult: max attempts exceeded');\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,aAAe;AAAA,EACf,MAAQ;AAAA,EACR,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,OAAS;AAAA,IACP;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAW;AAAA,IACT,KAAK;AAAA,MACH,OAAS;AAAA,MACT,QAAU;AAAA,MACV,SAAW;AAAA,IACb;AAAA,EACF;AAAA,EACA,MAAQ;AAAA,EACR,QAAU;AAAA,EACV,OAAS;AAAA,EACT,SAAW;AAAA,IACT,OAAS;AAAA,IACT,gBAAkB;AAAA,IAClB,MAAQ;AAAA,IACR,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,MAAQ;AAAA,IACR,WAAW;AAAA,IACX,eAAe;AAAA,IACf,QAAU;AAAA,IACV,gBAAgB;AAAA,IAChB,WAAa;AAAA,EACf;AAAA,EACA,cAAgB;AAAA,IACd,OAAS;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,iBAAmB;AAAA,IACjB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,uBAAuB;AAAA,IACvB,QAAU;AAAA,IACV,0BAA0B;AAAA,IAC1B,wBAAwB;AAAA,IACxB,qBAAqB;AAAA,IACrB,KAAO;AAAA,IACP,UAAY;AAAA,IACZ,MAAQ;AAAA,IACR,YAAc;AAAA,IACd,qBAAqB;AAAA,IACrB,QAAU;AAAA,EACZ;AAAA,EACA,UAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAW;AAAA,EACX,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,EACT;AAAA,EACA,MAAQ;AAAA,IACN,KAAO;AAAA,EACT;AAAA,EACA,UAAY;AAAA,EACZ,eAAiB;AAAA,IACf,QAAU;AAAA,EACZ;AACF;;;ACxEA,mBAKO;;;AC6CA,IAAM,qBAAqB;AAC3B,IAAM,wBAAwB;;;ACjDrC,IAAM,WAAW;AAEV,SAAS,oBACd,QACA,QAC4B;AAC5B,QAAM,IAAI,OAAO,YAAY;AAC7B,QAAM,UAAU,EAAE,GAAI,OAAO,QAA+C;AAC5E,UAAQ,SAAS,QAAQ,UAAU;AACnC,MAAI,YAAY,GAAG,MAAM,GAAG;AAC1B,YAAQ,cAAc,IAAI,QAAQ,cAAc,KAAK;AAAA,EACvD;AACA,SAAO,EAAE,GAAG,QAAQ,QAAQ;AAC9B;AAEA,SAAS,YAAY,QAAgB,QAA6C;AAChF,MAAI,CAAC,CAAC,QAAQ,SAAS,KAAK,EAAE,SAAS,MAAM,EAAG,QAAO;AACvD,SAAO,OAAO,SAAS,UAAa,OAAO,SAAS;AACtD;;;AClBA,eAAsB,2BAA2B,MAE/C;AACA,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,KAAK,SAAS,UAAU;AAC1B,UAAM,IAAI,MAAM,KAAK,SAAS;AAC9B,QAAI,CAAC,EAAG,QAAO;AACf,WAAO,UAAU,CAAC;AAAA,EACpB;AACA,QAAM,IAAI,MAAM,KAAK,UAAU;AAC/B,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,UAAU,CAAC;AACpB;;;ACdA,eAAsB,sBACpB,UAK6B;AAC7B,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,IAAI,MAAM,SAAS;AACzB,SAAO,KAAK;AACd;;;ACVA,kBAAqB;AAEd,IAAM,yBAAyB;AAE/B,SAAS,wBAAgC;AAC9C,aAAO,kBAAK;AACd;AAEO,SAAS,0BAA0B,KAAmB;AAC3D,MAAI,CAAC,OAAO,IAAI,KAAK,EAAE,WAAW,GAAG;AACnC,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AACA,MAAI,IAAI,SAAS,wBAAwB;AACvC,UAAM,IAAI,MAAM,2BAA2B,OAAO,sBAAsB,CAAC,aAAa;AAAA,EACxF;AACF;AAEO,SAAS,iBAAiB,QAAyB;AACxD,QAAM,IAAI,OAAO,YAAY;AAC7B,SAAO,MAAM,UAAU,MAAM,WAAW,MAAM,SAAS,MAAM;AAC/D;;;ACpBO,SAAS,cAAc,SAAyB;AACrD,MAAI,CAAC,OAAO,SAAS,OAAO,KAAK,UAAU,GAAG;AAC5C,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AACA,SAAO,MAAM,OAAO,OAAO,CAAC;AAC9B;;;ACAO,SAAS,oBAAoB,SAAiB,MAAc,MAA2B;AAC5F,QAAM,iBAAiB,KAAK,WAAW,GAAG,IAAI,OAAO,IAAI,IAAI;AAC7D,QAAM,OAAO,QAAQ,QAAQ,QAAQ,EAAE;AAEvC,MAAI,SAAS,SAAS;AACpB,QAAI,eAAe,WAAW,UAAU,KAAK,KAAK,SAAS,SAAS,GAAG;AACrE,YAAM,OAAO,eAAe,MAAM,UAAU,MAAM;AAElD,aAAO,KAAK,SAAS,IAAI,OAAO;AAAA,IAClC;AACA,WAAO;AAAA,EACT;AAEA,SAAO,eAAe,WAAW,SAAS,IAAI,iBAAiB,UAAU,cAAc;AACzF;AAKO,SAAS,iBAAiB,SAAyB;AACxD,SAAO;AACT;;;ACjBO,SAAS,aAAa,KAAkC;AAC7D,QAAM,IAAI,IAAI,OAAO,YAAY;AACjC,QAAM,SAAS,MAAM,SAAS,MAAM;AAEpC,MAAI,IAAI,gBAAgB;AACtB,WAAO;AAAA,EACT;AAEA,QAAM,IAAI,IAAI;AACd,MAAI,MAAM,OAAW,QAAO;AAE5B,MAAI,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM,IAAK,QAAO;AAC7D,MAAI,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM,IAAK,QAAO;AAE1E,MAAI,MAAM,KAAK;AACb,QAAI,IAAI,qBAAqB,yBAA0B,QAAO;AAC9D,QAAI,IAAI,qBAAqB,kCAAmC,QAAO;AACvE,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,IAAK,QAAO;AACtB,MAAI,MAAM,IAAK,QAAO;AACtB,MAAI,KAAK,OAAO,KAAK,IAAK,QAAO;AACjC,MAAI,KAAK,OAAO,IAAI,IAAK,QAAO;AAEhC,SAAO;AACT;;;ACtCO,SAAS,uBAAuB,OAA+C;AACpF,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,IAAI,OAAO,SAAS,OAAO,EAAE;AACnC,MAAI,CAAC,OAAO,MAAM,CAAC,EAAG,QAAO;AAC7B,QAAM,KAAK,KAAK,MAAM,KAAK;AAC3B,MAAI,CAAC,OAAO,MAAM,EAAE,GAAG;AACrB,WAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,KAAK,IAAI,KAAK,GAAI,CAAC;AAAA,EACxD;AACA,SAAO;AACT;;;ACRO,SAAS,oBACd,SACwB;AACxB,MAAI,CAAC,QAAS,QAAO,CAAC;AACtB,MAAI,OAAQ,QAAoB,YAAY,YAAY;AACtD,UAAMA,OAA8B,CAAC;AACrC,IAAC,QAAoB,QAAQ,CAAC,OAAO,QAAQ;AAC3C,MAAAA,KAAI,IAAI,YAAY,CAAC,IAAI;AAAA,IAC3B,CAAC;AACD,WAAOA;AAAA,EACT;AACA,QAAM,IAAI;AACV,QAAM,MAA8B,CAAC;AACrC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,CAAC,GAAG;AACtC,QAAI,OAAO,MAAM,SAAU,KAAI,EAAE,YAAY,CAAC,IAAI;AAAA,aACzC,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAG,KAAI,EAAE,YAAY,CAAC,IAAI,EAAE,CAAC;AAAA,EAC/D;AACA,SAAO;AACT;AAEO,SAAS,UAAU,SAAiC,MAAkC;AAC3F,SAAO,QAAQ,KAAK,YAAY,CAAC;AACnC;;;ACPA,IAAM,uBAAuB;AAC7B,IAAM,kBAAkB;AAExB,eAAsB,kBACpB,UACA,QACA,SAC+B;AAC/B,QAAM,MAAM,QAAQ,OAAO,eAAe;AAC1C,QAAM,YAAY,QAAQ,OAAO,eAAe;AAChD,QAAM,WAAW,QAAQ,OAAO,cAAc;AAC9C,QAAM,cAAc,QAAQ,OAAO,eAAe;AAElD,MAAI,UAAU;AACd,MAAI;AAEJ,SAAO,UAAU,KAAK;AACpB,QAAI;AACF,YAAM,MAAM,MAAM,SAAS,QAAe,MAAoC;AAC9E,qBAAe;AACf,YAAM,SAAS,IAAI;AACnB,YAAM,OAAO,oBAAoB,IAAI,OAAO;AAC5C,YAAM,UACJ,UAAU,MACN,mBAAmB,IAAI,MAAM,QAAQ,2BAA2B,IAChE;AACN,YAAM,UAAU,aAAa;AAAA,QAC3B,QAAQ,OAAO,OAAO,UAAU,KAAK;AAAA,QACrC;AAAA,QACA,kBAAkB;AAAA,QAClB,gBAAgB;AAAA,MAClB,CAAC;AACD,UAAI,WAAW,UAAU,MAAM,GAAG;AAChC,cAAM,aAAa,uBAAuB,KAAK,aAAa,CAAC;AAC7D,cAAM,UAAU;AAAA,UACd;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,cAAM,MAAM,OAAO;AACnB,mBAAW;AACX;AAAA,MACF;AACA,aAAO;AAAA,IACT,SAAS,KAAc;AACrB,YAAM,QAAQ,oBAAoB,GAAG;AACrC,YAAM,UAAU,aAAa;AAAA,QAC3B,QAAQ,OAAO,OAAO,UAAU,KAAK;AAAA,QACrC,gBAAgB;AAAA,MAClB,CAAC;AACD,UAAI,CAAC,WAAW,WAAW,MAAM,GAAG;AAClC,cAAM;AAAA,MACR;AACA,YAAM,UAAU,aAAa,SAAS,WAAW,UAAU,aAAa,MAAS;AACjF,YAAM,MAAM,OAAO;AACnB,iBAAW;AAAA,IACb;AAAA,EACF;AAGA,MAAI,aAAc,QAAO;AACzB,QAAM,IAAI,MAAM,+CAA+C;AACjE;AAEA,SAAS,mBACP,MACA,IACoB;AACpB,MAAI,GAAI,QAAO,GAAG,IAAI;AACtB,MAAI,QAAQ,OAAO,SAAS,YAAY,YAAY,MAAM;AACxD,UAAM,SAAU,KAA0C;AAC1D,QAAI,MAAM,QAAQ,MAAM,KAAK,OAAO,CAAC,GAAG,MAAM;AAC5C,aAAO,OAAO,CAAC,EAAE;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,KAAuB;AAClD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,IAAI;AACV,SAAO,EAAE,iBAAiB,QAAQ,CAAC,EAAE;AACvC;AAEA,SAAS,aACP,SACA,MACA,KACA,aACA,eACQ;AACR,MAAI,MAAM,KAAK,IAAI,KAAK,OAAO,KAAK,OAAO;AAC3C,MAAI,kBAAkB,QAAW;AAC/B,UAAM,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,gBAAgB,GAAI,CAAC;AAAA,EACzD;AACA,QAAM,SAAS,MAAM,eAAe,KAAK,OAAO,IAAI,IAAI;AACxD,SAAO,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,MAAM,CAAC;AAC7C;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAC7C;;;ACtHO,SAAS,qBAAqB,SAAmC;AACtE,MAAI,CAAC,WAAW,OAAO,YAAY,UAAU;AAC3C,UAAM,IAAI,UAAU,qCAAqC;AAAA,EAC3D;AACA,QAAM,IAAI;AACV,MAAI,EAAE,UAAU,IAAI;AAClB,UAAM,IAAI,UAAU,uCAAuC;AAAA,EAC7D;AACA,SAAO;AACT;;;ACXA,IAAM,uBAAuB;AAKtB,SAAS,eAAe,MAAe,SAAS,sBAA8B;AACnF,MAAI;AACJ,MAAI;AACF,QAAI,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,IAAI;AAAA,EAC3D,QAAQ;AACN,QAAI;AAAA,EACN;AACA,MAAI,EAAE,UAAU,OAAQ,QAAO;AAC/B,SAAO,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;AAC9B;AAKO,SAAS,mBAAmB,SAAyD;AAC1F,QAAM,MAA8B,EAAE,GAAG,QAAQ;AACjD,aAAW,OAAO,OAAO,KAAK,GAAG,GAAG;AAClC,UAAM,QAAQ,IAAI,YAAY;AAC9B,QAAI,UAAU,mBAAmB,UAAU,mBAAmB;AAC5D,UAAI,GAAG,IAAI;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;;;ACzBO,IAAM,iBAAN,MAAM,wBAAuB,MAAM;AAAA,EAGxC,YACW,QACA,QACA,aACA,iBACA,mBACA,eACT,SACA;AACA,UAAM,gBAAe,aAAa,QAAQ,MAAM,GAAG,OAAO;AARjD;AACA;AACA;AACA;AACA;AACA;AAAA,EAIX;AAAA,EATW;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EARF,OAAO;AAAA,EAchB,OAAO,aAAa,QAAuC,QAAwB;AACjF,UAAM,QAAQ,OAAO,CAAC;AACtB,UAAM,OAAO,OAAO,QAAQ;AAC5B,UAAM,SAAS,OAAO,UAAU,OAAO,SAAS;AAChD,UAAM,OAAO,UAAU,QAAQ,QAAQ,OAAO,MAAM,CAAC;AACrD,WAAO,mBAAmB,OAAO,MAAM,CAAC,KAAK,IAAI;AAAA,EACnD;AAAA,EAEA,SAAkC;AAChC,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK;AAAA,MACb,aAAa,KAAK;AAAA,MAClB,mBAAmB,KAAK;AAAA,MACxB,eAAe,KAAK;AAAA,MACpB,iBAAiB,KAAK,kBAClB,mBAAmB,EAAE,GAAG,KAAK,gBAAgB,CAAC,IAC9C;AAAA,IACN;AAAA,EACF;AACF;AAEO,SAAS,iBAAiB,OAAyC;AACxE,SAAO,iBAAiB;AAC1B;;;ACxCO,SAAS,sBACd,QACA,SACA,SACA,eACgB;AAChB,QAAM,oBAAoB,QAAQ,aAAa,IAC3C,sBAAsB,QAAQ,aAAa,CAAC,IAC5C;AAEJ,MAAI,YAAY,QAAQ,YAAY,UAAa,YAAY,IAAI;AAC/D,WAAO,IAAI;AAAA,MACT;AAAA,MACA,CAAC,EAAE,QAAQ,QAAQ,OAAO,MAAM,CAAC,IAAI,MAAM,mBAAmB,CAAC;AAAA,MAC/D;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,YAAY,UAAU;AAC/B,QAAI;AACF,YAAM,SAAkB,KAAK,MAAM,OAAO;AAC1C,aAAO,gBAAgB,QAAQ,QAAQ,SAAS,mBAAmB,aAAa;AAAA,IAClF,QAAQ;AACN,aAAO,eAAe,QAAQ,gBAAgB,mCAAmC,aAAa;AAAA,IAChG;AAAA,EACF;AAEA,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO,gBAAgB,QAAQ,SAAS,SAAS,mBAAmB,aAAa;AAAA,EACnF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,gBACP,QACA,MACA,SACA,mBACA,eACgB;AAChB,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,QAAM,MAAM;AACZ,QAAM,SAAS,IAAI;AACnB,MAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,OAAO,WAAW,GAAG;AACjD,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,QAAM,OAAO;AACb,QAAM,cAAc,KAAK,CAAC,GAAG;AAC7B,SAAO,IAAI,eAAe,QAAQ,MAAM,aAAa,SAAS,mBAAmB,aAAa;AAChG;AAEA,SAAS,eACP,QACA,MACA,QACA,eACgB;AAChB,SAAO,IAAI,eAAe,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM,QAAW,QAAW,aAAa;AACjG;AAEA,SAAS,sBAAsB,GAA+B;AAC5D,QAAM,IAAI,OAAO,SAAS,GAAG,EAAE;AAC/B,MAAI,CAAC,OAAO,MAAM,CAAC,EAAG,QAAO;AAC7B,QAAM,KAAK,KAAK,MAAM,CAAC;AACvB,MAAI,CAAC,OAAO,MAAM,EAAE,GAAG;AACrB,UAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,KAAK,IAAI,KAAK,GAAI,CAAC;AAC7D,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;ACxFO,SAAS,qBAAqB,KAA0C;AAC7E,MAAI,OAAO,OAAO,QAAQ,YAAY,WAAW,KAAK;AACpD,UAAM,QAAS,IAA4B;AAC3C,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,aAAO,MAAM,IAAI,CAAC,OAAO,cAAc,EAAE,CAAC;AAAA,IAC5C;AAAA,EACF;AACA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IAAI,IAAI,CAAC,OAAO,cAAc,EAAE,CAAC;AAAA,EAC1C;AACA,SAAO,CAAC,EAAE,YAAY,KAAK,MAAM,IAAI,CAAC;AACxC;AAEA,SAAS,cAAc,IAA8B;AACnD,MAAI,MAAM,OAAO,OAAO,UAAU;AAChC,UAAM,IAAI;AACV,UAAM,IAAI,EAAE,cAAc,EAAE;AAC5B,UAAM,aAAa,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,IAAI,IAAI;AACrE,WAAO,EAAE,YAAY,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG;AAAA,EACxD;AACA,SAAO,EAAE,YAAY,KAAK,MAAM,GAAG;AACrC;;;ACpBO,SAAS,wBAAwB,SAAsB,YAA4B;AACxF,QAAM,OAAO,oBAAoB,OAAO;AACxC,QAAM,MAAM,UAAU,MAAM,UAAU;AACtC,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI;AACF,WAAO,IAAI,IAAI,KAAK,UAAU,EAAE;AAAA,EAClC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACXO,SAAS,mBACd,KACA,MACiB;AACjB,MAAI,SAAS,OAAQ,QAAO;AAE5B,QAAM,OAAO,IAAI;AACjB,QAAM,cAAc,CAAC,MAAsB;AACzC,UAAM,IAAI,EAAE,GAAG,EAAE;AACjB,QAAI,EAAE,cAAc,OAAO,EAAE,eAAe,UAAU;AACpD,QAAE,aAAa,UAAU,EAAE,UAAqC;AAAA,IAClE;AACA,QAAI,EAAE,QAAQ,OAAO,EAAE,SAAS,UAAU;AACxC,QAAE,OAAO,UAAU,EAAE,IAA+B;AAAA,IACtD;AACA,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,MAAM;AACjB,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM,IAAI,OAAO,UAAU,IAAI,IAAI,IAAI,IAAI;AAAA,IAC7C;AAAA,EACF;AAEA,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM,KAAK,IAAI,CAAC,MAAM,YAAY,CAAW,CAAC;AAAA,MAC9C,MAAM,IAAI,OAAO,UAAU,IAAI,IAAI,IAAI,IAAI;AAAA,IAC7C;AAAA,EACF;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM,YAAY,IAAI;AAAA;AAAA,IAEtB,MAAM,IAAI,OAAO,UAAU,IAAI,IAAI,IAAI,IAAI;AAAA,EAC7C;AACF;AAEA,SAAS,UAAU,KAAuD;AACxE,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,GAAG,GAAG;AACxC,QAAI,YAAY,CAAC,CAAC,IAAI;AAAA,EACxB;AACA,SAAO;AACT;AAEA,SAAS,YAAY,GAAmB;AACtC,SAAO,EAAE,QAAQ,aAAa,CAAC,GAAG,MAAc,EAAE,YAAY,CAAC;AACjE;;;ACpCO,SAAS,uBACd,UACA,SACe;AACf,QAAM,SAAS,SAAS;AACxB,QAAM,UAAU,oBAAoB,SAAS,OAAO;AAEpD,MAAI,UAAU,KAAK;AACjB,UAAM,sBAAsB,QAAQ,SAAS,MAAM,SAAS,QAAQ,aAAa;AAAA,EACnF;AAEA,QAAM,cAAc,iBAAiB,OAAO;AAE5C,MAAI,WAAW,KAAK;AAClB,WAAO,EAAE,MAAM,cAAc,QAAQ,KAAK,SAAS,YAAY;AAAA,EACjE;AAEA,MAAI,WAAW,KAAK;AAClB,UAAM,WAAW,wBAAwB,SAAS,QAAQ,UAAU;AACpE,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,MACR;AAAA,MACA,SAAS,SAAS;AAAA,MAClB,SAAS;AAAA,IACX;AAAA,EACF;AAEA,MAAI,WAAW,KAAK;AAClB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,OAAO,qBAAqB,SAAS,IAAI;AAAA,MACzC,SAAS;AAAA,IACX;AAAA,EACF;AAEA,MAAI,WAAW,OAAO,WAAW,KAAK;AACpC,UAAM,MAAM,qBAAqB,SAAS,IAAI;AAC9C,UAAM,cAAc;AAAA,MAClB;AAAA,MACA,QAAQ,yBAAyB;AAAA,IACnC;AACA,UAAM,OAA2B;AAAA,MAC/B,MAAM;AAAA,MACN;AAAA,MACA,SAAS;AAAA,MACT,UAAU;AAAA,IACZ;AACA,WAAO;AAAA,EACT;AAEA,QAAM,IAAI;AAAA,IACR;AAAA,IACA,CAAC,EAAE,MAAM,8BAA8B,QAAQ,OAAO,MAAM,EAAE,CAAC;AAAA,IAC/D;AAAA,IACA;AAAA,IACA,uBAAuB,UAAU,SAAS,aAAa,CAAC;AAAA,IACxD,QAAQ;AAAA,EACV;AACF;AAEA,SAAS,iBAAiB,SAA4D;AACpF,QAAM,OAAO,UAAU,SAAS,qBAAqB;AACrD,SAAO;AAAA,IACL,MAAM,UAAU,SAAS,MAAM;AAAA,IAC/B,iBAAiB,UAAU,SAAS,kBAAkB;AAAA,IACtD,oBAAoB,SAAS,UAAU,SAAS;AAAA,IAChD,mBAAmB,uBAAuB,UAAU,SAAS,aAAa,CAAC;AAAA,EAC7E;AACF;AAEA,SAAS,uBACP,KACA,MACiB;AACjB,MAAI,SAAS,OAAQ,QAAO;AAC5B,SAAO,mBAAmB,KAAK,IAAI;AACrC;;;AC9FO,SAAS,wBAAwB,WAA4C;AAClF,QAAM,OAAO,oBAAoB,SAAS;AAC1C,QAAM,MAAM,KAAK;AACjB,QAAM,SAAS,KAAK;AACpB,MAAI,CAAC,OAAO,CAAC,OAAQ,QAAO;AAC5B,SAAO;AAAA,IACL,aAAa;AAAA,IACb;AAAA,IACA,YAAY;AAAA,EACd;AACF;;;ApBqEA,SAAS,WAAW,IAAwB,MAAkC;AAC5E,QAAM,IAAI,GAAG;AAEb,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,IAAI,EAAE,IAAI,KAAK,EAAE,KAAK,YAAY,CAAC;AACzC,MAAI,MAAM,QAAQ,CAAC,EAAG,QAAO,EAAE,CAAC;AAEhC,SAAO,OAAO,MAAM,WAAW,IAAI;AACrC;AAEA,SAAS,gBAAgB,KAAyB,UAA0B;AAC1E,MAAI,OAAO,IAAI,QAAQ,YAAY,gBAAgB,KAAK,IAAI,GAAG,GAAG;AAChE,WAAO,IAAI;AAAA,EACb;AACA,QAAM,OAAO,IAAI,WAAW;AAC5B,QAAM,IAAI,IAAI,OAAO;AACrB,MAAI;AACF,WAAO,IAAI,IAAI,GAAG,IAAI,EAAE;AAAA,EAC1B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,oBAAoB,SAAuB;AAClD,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,OAAO;AACzB,QAAI,EAAE,aAAa,QAAS;AAC5B,UAAM,OAAO,EAAE,SAAS,YAAY;AACpC,QAAI,SAAS,eAAe,SAAS,YAAa;AAClD,YAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACF;AAEA,eAAe,KACb,IACgD;AAChD,MAAI;AACF,UAAM,QAAQ,MAAM,GAAG;AACvB,WAAO,EAAE,IAAI,MAAM,MAAM;AAAA,EAC3B,SAAS,GAAG;AACV,QAAI,aAAa,gBAAgB;AAC/B,aAAO,EAAE,IAAI,OAAO,OAAO,EAAE;AAAA,IAC/B;AACA,UAAM;AAAA,EACR;AACF;AAEO,SAAS,gBAAgB,QAAoC;AAClE,QAAM,OAAoB,OAAO,eAAe;AAChD,QAAM,SAAS,OAAO,0BAA0B;AAChD,sBAAoB,OAAO,OAAO;AAElC,QAAM,WAA0B,aAAAC,QAAM,OAAO;AAAA,IAC3C,SAAS,OAAO;AAAA,IAChB,SAAS,OAAO,WAAW;AAAA,IAC3B,gBAAgB,MAAM;AAAA,IACtB,SAAS;AAAA,MACP,QAAQ;AAAA,MACR,GAAG,OAAO;AAAA,IACZ;AAAA,EACF,CAAC;AAED,WAAS,aAAa,QAAQ,IAAI,OAAO,QAAQ;AAE/C,UAAM,UAAU,IAAI,UAAU,OAAO,YAAY;AACjD,UAAM,OAAO,oBAAoB,KAAK,MAAM;AAC5C,UAAM,aAAa,MAAM,2BAA2B,OAAO,IAAI;AAC/D,QAAI,YAAY;AACd,MAAC,KAAK,QAAmC,gBAAgB;AAAA,IAC3D;AACA,UAAM,OAAO,MAAM,sBAAsB,OAAO,iBAAiB;AACjE,QAAI,MAAM;AACR,MAAC,KAAK,QAAmC,iBAAiB,IAAI;AAAA,IAChE;AACA,QAAI,iBAAiB,MAAM,GAAG;AAC5B,YAAM,IAAI,KAAK;AACf,YAAM,WAAW,EAAE,iBAAiB,KAAK,EAAE,iBAAiB;AAC5D,YAAM,MAAM,OAAO,aAAa,YAAY,SAAS,SAAS,IAAI,WAAW,OAAO;AACpF,gCAA0B,GAAG;AAC7B,MAAC,KAAK,QAAmC,iBAAiB,IAAI;AAAA,IAChE;AACA,WAAO;AAAA,EACT,CAAC;AAED,WAAS,aAAa,SAAS;AAAA,IAC7B,CAAC,QAAQ;AACP,YAAM,OAAO,oBAAoB,IAAI,OAAO;AAC5C,UAAI,KAAK,qBAAqB,MAAM,UAAU,OAAO,qBAAqB;AACxE,eAAO,oBAAoB;AAAA;AAAA,UAEzB,KAAK,OAAO,IAAI,OAAO,QAAQ,WAAW,IAAI,OAAO,MAAM;AAAA,UAC3D,QAAQ,OAAO,IAAI,OAAO,WAAW,WAAW,IAAI,OAAO,SAAS;AAAA,QACtE,CAAC;AAAA,MACH;AACA,YAAM,MAAM,wBAAwB,IAAI,OAAO;AAC/C,UAAI,OAAO,OAAO,cAAc;AAC9B,eAAO,aAAa,GAAG;AAAA,MACzB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QACC,QAAQ;AAAA;AAAA,MAEN,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAAA,IACpD;AAAA,EACJ;AAEA,WAAS,YAAY,MAAsB;AACzC,WAAO,oBAAoB,OAAO,SAAS,MAAM,IAAI;AAAA,EACvD;AAEA,iBAAe,QACb,QACA,KACA,SACwB;AACxB,UAAM,UAAkC,CAAC;AACzC,QAAI,QAAQ,mBAAmB,QAAW;AACxC,gCAA0B,QAAQ,cAAc;AAChD,cAAQ,iBAAiB,IAAI,QAAQ;AAAA,IACvC;AACA,QAAI,QAAQ,mBAAmB,QAAW;AACxC,cAAQ,UAAU,IAAI,cAAc,QAAQ,cAAc;AAAA,IAC5D;AAEA,UAAM,WAA+B;AAAA,MACnC;AAAA,MACA;AAAA,MACA,MAAM,QAAQ;AAAA,MACd,SAAS,EAAE,GAAG,QAAQ;AAAA,IACxB;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,kBAAkB,UAAU,UAAU;AAAA,QAC3D,OAAO,OAAO;AAAA,MAChB,CAAC;AACD,UAAI;AACF,eAAO,uBAAuB,UAAU;AAAA,UACtC,uBAAuB,OAAO;AAAA,UAC9B,YAAY,gBAAgB,SAAS,QAAQ,GAAG;AAAA,UAChD,eAAe,OAAO,YAAY;AAAA,QACpC,CAAC;AAAA,MACH,SAAS,GAAY;AACnB,YAAI,aAAa,kBAAkB,EAAE,WAAW,OAAO,OAAO,gBAAgB;AAC5E,gBAAM,OAAO,eAAe,CAAC;AAAA,QAC/B;AACA,cAAM;AAAA,MACR;AAAA,IACF,SAAS,KAAc;AACrB,cAAI,2BAAa,GAAG,KAAK,IAAI,UAAU;AACrC,cAAM,MAAM,IAAI;AAChB,YAAI;AACF,iBAAO,uBAAuB,KAAK;AAAA,YACjC,uBAAuB,OAAO;AAAA,YAC9B,YAAY,gBAAgB,IAAI,QAAQ,GAAG;AAAA,YAC3C,eAAe,OAAO,YAAY;AAAA,UACpC,CAAC;AAAA,QACH,SAAS,GAAY;AACnB,cAAI,aAAa,kBAAkB,EAAE,WAAW,OAAO,OAAO,gBAAgB;AAC5E,kBAAM,OAAO,eAAe,CAAC;AAAA,UAC/B;AACA,gBAAM;AAAA,QACR;AAAA,MACF;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,SAAoB;AAAA,IACxB,MAAM,IAAI,MAAc,MAAmD;AACzE,aAAO,QAAQ,OAAO,YAAY,IAAI,GAAG,QAAQ,CAAC,CAAC;AAAA,IACrD;AAAA,IACA,MAAM,KAAK,MAAc,MAAmD;AAC1E,aAAO,QAAQ,QAAQ,YAAY,IAAI,GAAG,QAAQ,CAAC,CAAC;AAAA,IACtD;AAAA,IACA,MAAM,KAAK,MAAc,MAAgB,MAAmD;AAC1F,aAAO,QAAQ,QAAQ,YAAY,IAAI,GAAG,EAAE,GAAG,MAAM,KAAK,CAAC;AAAA,IAC7D;AAAA,IACA,MAAM,MAAM,MAAc,MAAgB,MAAmD;AAC3F,aAAO,QAAQ,SAAS,YAAY,IAAI,GAAG,EAAE,GAAG,MAAM,KAAK,CAAC;AAAA,IAC9D;AAAA,IACA,MAAM,IAAI,MAAc,MAAgB,MAAmD;AACzF,aAAO,QAAQ,OAAO,YAAY,IAAI,GAAG,EAAE,GAAG,MAAM,KAAK,CAAC;AAAA,IAC5D;AAAA,IACA,MAAM,OAAO,MAAc,MAAmD;AAC5E,aAAO,QAAQ,UAAU,YAAY,IAAI,GAAG,QAAQ,CAAC,CAAC;AAAA,IACxD;AAAA,IACA,MAAM,QAAQ,IAAwB,MAAmD;AAEvF,YAAM,UAAU,GAAG,UAAU,OAAO,YAAY;AAChD,YAAM,SAAS,GAAG,OAAO;AACzB,YAAM;AAAA;AAAA,QAEJ,OAAO,WAAW,YAAY,gBAAgB,KAAK,MAAM,IACrD,SACA,YAAY,MAAM;AAAA;AACxB,aAAO,QAAQ,QAAQ,GAAG;AAAA,QACxB,GAAG;AAAA,QACH,MAAM,GAAG;AAAA,QACT,gBAAgB,MAAM,kBAAkB,WAAW,IAAI,iBAAiB;AAAA,MAC1E,CAAC;AAAA,IACH;AAAA,IACA,MAAM,SAAS,SAAiB,MAAmD;AACjF,aAAO,QAAQ,OAAO,SAAS,QAAQ,CAAC,CAAC;AAAA,IAC3C;AAAA,IACA,MAAM,iBACJ,MACA,MACA,SACA,MACwB;AACxB,aAAO,QAAQ,SAAS,YAAY,IAAI,GAAG;AAAA,QACzC,GAAG;AAAA,QACH;AAAA,QACA,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,IACA,SAAS,CAAC,MAAM,SAAS,KAAK,MAAM,OAAO,IAAI,MAAM,IAAI,CAAC;AAAA,IAC1D,UAAU,CAAC,MAAM,MAAM,SAAS,KAAK,MAAM,OAAO,KAAK,MAAM,MAAM,IAAI,CAAC;AAAA,IACxE,WAAW,CAAC,MAAM,MAAM,SAAS,KAAK,MAAM,OAAO,MAAM,MAAM,MAAM,IAAI,CAAC;AAAA,IAC1E,SAAS,CAAC,MAAM,MAAM,SAAS,KAAK,MAAM,OAAO,IAAI,MAAM,MAAM,IAAI,CAAC;AAAA,IACtE,YAAY,CAAC,MAAM,SAAS,KAAK,MAAM,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,IAChE,UAAU,CAAC,MAAM,SAAS,KAAK,MAAM,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA,IAC5D,aAAa,CAAC,IAAI,SAAS,KAAK,MAAM,OAAO,QAAQ,IAAI,IAAI,CAAC;AAAA,EAChE;AAEA,SAAO;AACT;;;AqBtTO,SAAS,sBAAsB,GAAqB;AACzD,SAAO,SAAS,GAAG,GAAG;AACxB;AAEO,SAAS,iBAAiB,GAAqB;AACpD,SAAO,SAAS,GAAG,GAAG;AACxB;AAEO,SAAS,4BAA4B,GAAqB;AAC/D,SAAO,SAAS,GAAG,GAAG;AACxB;AAEO,SAAS,0BAA0B,GAAqB;AAC7D,SAAO,SAAS,GAAG,GAAG;AACxB;AAEO,SAAS,kBAAkB,GAAqB;AACrD,SAAO,SAAS,GAAG,GAAG;AACxB;AAEO,SAAS,gBAAgB,GAAqB;AACnD,SAAO,SAAS,GAAG,GAAG;AACxB;AAEO,SAAS,uBAAuB,GAAqB;AAC1D,SAAO,SAAS,GAAG,GAAG;AACxB;AAEO,SAAS,qBAAqB,GAAqB;AACxD,MAAI,EAAE,aAAa,gBAAiB,QAAO;AAC3C,SAAO,aAAa;AAAA,IAClB,QAAQ,EAAE,iBAAiB;AAAA,IAC3B,QAAQ,EAAE;AAAA,IACV,kBAAkB,EAAE;AAAA,IACpB,gBAAgB;AAAA,EAClB,CAAC;AACH;AAEA,SAAS,SAAS,GAAY,QAAyB;AACrD,SAAO,aAAa,kBAAkB,EAAE,WAAW;AACrD;;;AC5BO,SAAS,oBACd,MACA,OACyD;AACzD,QAAM,IAAI,QAAQ,CAAC;AACnB,QAAM,YAAY,OAAO,OAAO,SAAS,WAAW,MAAM,OAAO;AAEjE,MAAI,WAAW;AACb,UAAM,aACJ,kBAAkB,WAAW,cAAc,KAC3C,kBAAkB,WAAW,kBAAkB;AACjD,QAAI,YAAY;AACd,aAAO,EAAE,MAAM,UAAU,SAAS,MAAM,YAAY,WAAW;AAAA,IACjE;AAEA,UAAM,SAAS,yBAAyB,SAAS;AACjD,QAAI,OAAQ,QAAO;AAAA,EACrB;AAEA,QAAM,WAAW,IAAI,EAAE,SAAS;AAChC,QAAM,UAAU,IAAI,EAAE,YAAY,KAAK,IAAI,EAAE,IAAI;AACjD,QAAM,QAAQ,IAAI,EAAE,KAAK;AACzB,QAAM,UAAU,KAAK,EAAE,QAAQ;AAE/B,MAAI,aAAa,UAAa,YAAY,UAAa,UAAU,QAAW;AAC1E,WAAO;AAAA,MACL,MAAM;AAAA,MACN,MAAM,WAAW;AAAA,MACjB,YAAY;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAEA,MAAI,YAAY,QAAW;AACzB,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA,YAAY,OAAO,EAAE,gBAAgB,WAAW,EAAE,cAAc;AAAA,IAClE;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,UAAU;AAC3B;AAEO,SAAS,eACd,OACoB;AACpB,QAAM,IAAI,OAAO;AACjB,SAAO,OAAO,MAAM,WAAW,IAAI;AACrC;AAEA,SAAS,yBAAyB,KAA2C;AAC3E,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,KAAK,mBAAmB;AAC1C,UAAM,aAAa,EAAE,aAAa,IAAI,UAAU;AAChD,UAAM,YAAY,EAAE,aAAa,IAAI,MAAM;AAC3C,UAAM,cAAc,EAAE,aAAa,IAAI,cAAc;AACrD,QAAI,CAAC,cAAc,CAAC,aAAa,CAAC,YAAa,QAAO;AACtD,UAAM,UAAU,IAAI,SAAS,KAAK,IAAI,WAAW,KAAK;AACtD,WAAO,EAAE,MAAM,UAAU,MAAM,SAAS,YAAY,QAAW,OAAO,OAAU;AAAA,EAClF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,IAAI,GAAgC;AAC3C,MAAI,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,EAAG,QAAO;AACxD,MAAI,OAAO,MAAM,YAAY,UAAU,KAAK,CAAC,EAAG,QAAO,OAAO,SAAS,GAAG,EAAE;AAC5E,SAAO;AACT;AAEA,SAAS,KAAK,GAAiC;AAC7C,MAAI,OAAO,MAAM,UAAW,QAAO;AACnC,SAAO;AACT;AAEA,SAAS,kBAAkB,KAAa,KAA4B;AAClE,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,KAAK,mBAAmB;AAC1C,WAAO,EAAE,aAAa,IAAI,GAAG,KAAK,EAAE,aAAa,IAAI,IAAI,QAAQ,OAAO,EAAE,EAAE,QAAQ,OAAO,EAAE,CAAC;AAAA,EAChG,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACzFO,SAAS,kBAAkB,OAAkD;AAClF,QAAM,SAAiC,CAAC;AACxC,MAAI,MAAM,QAAQ;AAChB,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,MAAM,GAAG;AACjD,UAAI,MAAM,OAAW;AACrB,aAAO,UAAU,CAAC,GAAG,IAAI,OAAO,CAAC;AAAA,IACnC;AAAA,EACF;AACA,MAAI,MAAM,MAAM,QAAQ;AACtB,WAAO,OAAO,MAAM,KAAK,KAAK,GAAG;AAAA,EACnC;AACA,MAAI,MAAM,QAAQ;AAChB,eAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,MAAM,MAAM,GAAG;AACzD,aAAO,UAAU,IAAI,GAAG,IAAI,OAAO,KAAK,GAAG;AAAA,IAC7C;AAAA,EACF;AACA,MAAI,MAAM,SAAS,QAAQ;AACzB,WAAO,UAAU,MAAM,QAAQ,KAAK,GAAG;AAAA,EACzC;AACA,SAAO;AACT;AAEO,SAAS,sBAAsB,OAGF;AAClC,QAAM,OAAO,KAAK,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI,GAAG,qBAAqB;AACpE,SAAO;AAAA,IACL,gBAAgB,MAAM;AAAA,IACtB,cAAc;AAAA,EAChB;AACF;AAEO,SAAS,sBAAsB,OAGF;AAClC,QAAM,OAAO,KAAK,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI,GAAG,qBAAqB;AACpE,SAAO;AAAA,IACL,gBAAgB,MAAM;AAAA,IACtB,cAAc;AAAA,EAChB;AACF;;;AC/CO,SAAS,cACd,UACe;AACf,QAAM,MAAM,oBAAI,IAAmC;AACnD,MAAI,CAAC,SAAU,QAAO;AACtB,aAAW,KAAK,UAAU;AACxB,QAAI,IAAI,GAAG,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC;AAAA,EAChC;AACA,SAAO;AACT;AAEO,SAAS,gBACd,KACA,OACmC;AACnC,SAAO,MAAM,IAAI,GAAG,IAAI,IAAI,IAAI,IAAI,EAAE,EAAE;AAC1C;;;ACjBO,SAAS,oBACd,UACA,YACoB;AACpB,QAAM,OAAO,SAAS;AACtB,QAAM,KAAK,MAAM;AACjB,QAAM,WAAW,eAAe,EAAE;AAClC,MAAI,aAAa,OAAW,QAAO;AAEnC,QAAM,OAAO;AACb,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,IAAI,WAAW,KAAK,IAAI;AAC9B,QAAI,IAAI,CAAC,EAAG,QAAO,OAAO,SAAS,EAAE,CAAC,GAAG,EAAE;AAAA,EAC7C;AACA,SAAO;AACT;AAEA,SAAS,eAAe,GAAgC;AACtD,MAAI,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,KAAK,KAAK,EAAG,QAAO;AAClE,MAAI,OAAO,MAAM,YAAY,QAAQ,KAAK,CAAC,EAAG,QAAO,OAAO,SAAS,GAAG,EAAE;AAC1E,SAAO;AACT;AAEO,SAAS,wBAAwB,WAAwC;AAC9E,QAAM,IAAI,oBAAoB,SAAS;AACvC,SAAO,UAAU,GAAG,MAAM;AAC5B;;;ACzBO,SAAS,+BACd,QACkB;AAClB,QAAM,MAAgC,CAAC;AACvC,aAAW,KAAK,QAAQ;AACtB,UAAM,MAAM,EAAE,QAAQ,WAAW;AAEjC,UAAM,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ;AAC7C,QAAI,GAAG,MAAM,CAAC;AACd,QAAI,GAAG,EAAE,KAAK,GAAG;AAAA,EACnB;AACA,SAAO;AACT;;;ACbO,SAAS,kBACd,QACwB;AACxB,QAAM,SAAS,WAAW,MAAM,IAAI,SAAS,gBAAgB,MAAM;AAEnE,SAAO,YAAY;AACjB,QAAI;AACF,YAAM,OAAO,IAAI,cAAc;AAC/B,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAMA,SAAS,WACP,QACuC;AACvC,SAAO,OAAQ,OAA0B,QAAQ;AACnD;;;AClBA,eAAsB,gBACpB,QACA,SACA,SACwB;AACxB,QAAM,MAAM,SAAS,eAAe;AACpC,QAAM,QAAQ,SAAS,WAAW;AAClC,MAAI,MAAM,QAAQ;AAClB,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK,GAAG;AAC/B,UAAM,MAAM,MAAM,OAAO,SAAS,GAAG;AACrC,QAAI,IAAI,SAAS,WAAY,QAAO;AACpC,UAAM,IAAI;AACV,UAAMC,OAAM,KAAK;AAAA,EACnB;AACA,QAAM,IAAI,MAAM,wCAAwC;AAC1D;AAEA,SAASA,OAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAC7C;;;A9BzBO,IAAM,kBAAkB,gBAAI;","names":["out","axios","sleep"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { AxiosRequestConfig, InternalAxiosRequestConfig, AxiosResponse, AxiosInstance } from 'axios';
|
|
2
|
+
|
|
3
|
+
/** Mode B (default): `baseURL` already includes `/api/v1`. Mode A: origin only; client prefixes `/api/v1`. */
|
|
4
|
+
type BaseUrlMode = 'modeB' | 'modeA';
|
|
5
|
+
type AuthConfig = {
|
|
6
|
+
readonly type: 'bearer';
|
|
7
|
+
readonly getToken: TokenProvider;
|
|
8
|
+
} | {
|
|
9
|
+
readonly type: 'partner-bearer';
|
|
10
|
+
readonly getSecret: TokenProvider;
|
|
11
|
+
};
|
|
12
|
+
type TokenProvider = () => string | null | undefined | Promise<string | null | undefined>;
|
|
13
|
+
type TransformResponseKeysMode = 'none' | 'camelCase-attributes-meta';
|
|
14
|
+
interface RetryOptions {
|
|
15
|
+
readonly maxAttempts?: number;
|
|
16
|
+
readonly baseDelayMs?: number;
|
|
17
|
+
readonly maxDelayMs?: number;
|
|
18
|
+
readonly jitterRatio?: number;
|
|
19
|
+
}
|
|
20
|
+
interface IdempotencyReplayContext {
|
|
21
|
+
readonly url?: string;
|
|
22
|
+
readonly method?: string;
|
|
23
|
+
}
|
|
24
|
+
interface ApiClientConfig {
|
|
25
|
+
readonly baseURL: string;
|
|
26
|
+
/** Default Mode B — see `BaseUrlMode`. */
|
|
27
|
+
readonly baseUrlMode?: BaseUrlMode;
|
|
28
|
+
readonly auth?: AuthConfig;
|
|
29
|
+
readonly getAcceptLanguage?: () => string | null | undefined | Promise<string | null | undefined>;
|
|
30
|
+
readonly defaultHeaders?: Readonly<Record<string, string>>;
|
|
31
|
+
readonly timeout?: number;
|
|
32
|
+
readonly retry?: RetryOptions;
|
|
33
|
+
readonly generateIdempotencyKey?: () => string;
|
|
34
|
+
readonly onIdempotencyReplay?: (ctx: Readonly<IdempotencyReplayContext>) => void;
|
|
35
|
+
readonly onUnauthorized?: (error: unknown) => void | Promise<void>;
|
|
36
|
+
readonly onDeprecated?: (info: Readonly<DeprecationInfo>) => void;
|
|
37
|
+
readonly transformResponseKeys?: TransformResponseKeysMode;
|
|
38
|
+
readonly maxBodyLogLength?: number;
|
|
39
|
+
}
|
|
40
|
+
interface DeprecationInfo {
|
|
41
|
+
readonly deprecation?: string;
|
|
42
|
+
readonly sunset?: string;
|
|
43
|
+
readonly rawHeaders: Readonly<Record<string, string>>;
|
|
44
|
+
}
|
|
45
|
+
declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
46
|
+
declare const DEFAULT_PAGE_SIZE_CAP = 100;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Minimal JSON:API wire shapes used by the client (snake_case on wire).
|
|
50
|
+
*/
|
|
51
|
+
interface JsonApiResourceLinkage {
|
|
52
|
+
readonly type: string;
|
|
53
|
+
readonly id: string;
|
|
54
|
+
}
|
|
55
|
+
interface JsonApiResourceObject {
|
|
56
|
+
readonly type: string;
|
|
57
|
+
readonly id: string;
|
|
58
|
+
readonly attributes?: Record<string, unknown>;
|
|
59
|
+
readonly relationships?: Record<string, unknown>;
|
|
60
|
+
readonly meta?: Record<string, unknown>;
|
|
61
|
+
readonly links?: Record<string, string | null | undefined>;
|
|
62
|
+
}
|
|
63
|
+
type JsonApiPrimaryData = JsonApiResourceObject | readonly JsonApiResourceObject[] | null;
|
|
64
|
+
interface JsonApiDocument<TData extends JsonApiPrimaryData = JsonApiPrimaryData> {
|
|
65
|
+
readonly data: TData;
|
|
66
|
+
readonly included?: readonly JsonApiResourceObject[];
|
|
67
|
+
readonly meta?: Readonly<Record<string, unknown>>;
|
|
68
|
+
readonly links?: Readonly<Record<string, string | null | undefined>>;
|
|
69
|
+
}
|
|
70
|
+
interface JsonApiErrorObject {
|
|
71
|
+
readonly id?: string;
|
|
72
|
+
readonly status?: string;
|
|
73
|
+
readonly code?: string;
|
|
74
|
+
readonly title?: string;
|
|
75
|
+
readonly detail?: string;
|
|
76
|
+
readonly source?: {
|
|
77
|
+
readonly pointer?: string;
|
|
78
|
+
readonly parameter?: string;
|
|
79
|
+
};
|
|
80
|
+
readonly meta?: Readonly<Record<string, unknown>>;
|
|
81
|
+
}
|
|
82
|
+
interface JsonApiErrorDocument {
|
|
83
|
+
readonly errors: readonly JsonApiErrorObject[];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Normalized subset of interesting response headers */
|
|
87
|
+
interface NormalizedResponseHeaders {
|
|
88
|
+
readonly etag?: string;
|
|
89
|
+
readonly contentLanguage?: string;
|
|
90
|
+
readonly idempotentReplayed: boolean;
|
|
91
|
+
readonly retryAfterSeconds?: number;
|
|
92
|
+
}
|
|
93
|
+
interface JsonApiSuccessBody {
|
|
94
|
+
readonly kind: 'jsonapi-success';
|
|
95
|
+
readonly status: 200 | 201;
|
|
96
|
+
readonly headers: NormalizedResponseHeaders;
|
|
97
|
+
readonly document: JsonApiDocument;
|
|
98
|
+
}
|
|
99
|
+
interface NoContentBody {
|
|
100
|
+
readonly kind: 'no-content';
|
|
101
|
+
readonly status: 204;
|
|
102
|
+
readonly headers: NormalizedResponseHeaders;
|
|
103
|
+
}
|
|
104
|
+
interface AcceptedBody {
|
|
105
|
+
readonly kind: 'accepted';
|
|
106
|
+
readonly status: 202;
|
|
107
|
+
readonly location: string;
|
|
108
|
+
readonly rawBody?: unknown;
|
|
109
|
+
readonly headers: NormalizedResponseHeaders;
|
|
110
|
+
}
|
|
111
|
+
interface MultiStatusItem {
|
|
112
|
+
readonly httpStatus: number;
|
|
113
|
+
readonly body?: unknown;
|
|
114
|
+
}
|
|
115
|
+
interface MultiStatusBody {
|
|
116
|
+
readonly kind: 'multi-status';
|
|
117
|
+
readonly status: 207;
|
|
118
|
+
readonly items: readonly MultiStatusItem[];
|
|
119
|
+
readonly headers: NormalizedResponseHeaders;
|
|
120
|
+
}
|
|
121
|
+
type ClientSuccess = JsonApiSuccessBody | NoContentBody | AcceptedBody | MultiStatusBody;
|
|
122
|
+
interface OkResult<T extends ClientSuccess> {
|
|
123
|
+
readonly ok: true;
|
|
124
|
+
readonly value: T;
|
|
125
|
+
}
|
|
126
|
+
interface ErrResult<E> {
|
|
127
|
+
readonly ok: false;
|
|
128
|
+
readonly error: E;
|
|
129
|
+
}
|
|
130
|
+
type Result<T extends ClientSuccess, E> = OkResult<T> | ErrResult<E>;
|
|
131
|
+
|
|
132
|
+
declare class ApiClientError extends Error {
|
|
133
|
+
#private;
|
|
134
|
+
readonly status: number;
|
|
135
|
+
readonly errors: readonly JsonApiErrorObject[];
|
|
136
|
+
readonly primaryCode?: string | undefined;
|
|
137
|
+
readonly responseHeaders?: Readonly<Record<string, string>> | undefined;
|
|
138
|
+
readonly retryAfterSeconds?: number | undefined;
|
|
139
|
+
readonly requestMethod?: string | undefined;
|
|
140
|
+
readonly name = "ApiClientError";
|
|
141
|
+
constructor(status: number, errors: readonly JsonApiErrorObject[], primaryCode?: string | undefined, responseHeaders?: Readonly<Record<string, string>> | undefined, retryAfterSeconds?: number | undefined, requestMethod?: string | undefined, options?: ErrorOptions);
|
|
142
|
+
toJSON(): Record<string, unknown>;
|
|
143
|
+
}
|
|
144
|
+
declare function isApiClientError(value: unknown): value is ApiClientError;
|
|
145
|
+
|
|
146
|
+
interface RequestCallOptions {
|
|
147
|
+
readonly idempotencyKey?: string;
|
|
148
|
+
readonly ifMatchVersion?: number;
|
|
149
|
+
}
|
|
150
|
+
interface ApiClient {
|
|
151
|
+
readonly get: (path: string, opts?: RequestCallOptions) => Promise<ClientSuccess>;
|
|
152
|
+
readonly head: (path: string, opts?: RequestCallOptions) => Promise<ClientSuccess>;
|
|
153
|
+
readonly post: (path: string, data?: unknown, opts?: RequestCallOptions) => Promise<ClientSuccess>;
|
|
154
|
+
readonly patch: (path: string, data?: unknown, opts?: RequestCallOptions) => Promise<ClientSuccess>;
|
|
155
|
+
readonly put: (path: string, data?: unknown, opts?: RequestCallOptions) => Promise<ClientSuccess>;
|
|
156
|
+
readonly delete: (path: string, opts?: RequestCallOptions) => Promise<ClientSuccess>;
|
|
157
|
+
readonly request: (ax: AxiosRequestConfig, opts?: RequestCallOptions) => Promise<ClientSuccess>;
|
|
158
|
+
readonly getByUrl: (fullUrl: string, opts?: RequestCallOptions) => Promise<ClientSuccess>;
|
|
159
|
+
readonly patchWithVersion: (path: string, data: unknown, version: number, opts?: Omit<RequestCallOptions, 'ifMatchVersion'>) => Promise<ClientSuccess>;
|
|
160
|
+
readonly safeGet: (path: string, opts?: RequestCallOptions) => Promise<Result<ClientSuccess, ApiClientError>>;
|
|
161
|
+
readonly safePost: (path: string, data?: unknown, opts?: RequestCallOptions) => Promise<Result<ClientSuccess, ApiClientError>>;
|
|
162
|
+
readonly safePatch: (path: string, data?: unknown, opts?: RequestCallOptions) => Promise<Result<ClientSuccess, ApiClientError>>;
|
|
163
|
+
readonly safePut: (path: string, data?: unknown, opts?: RequestCallOptions) => Promise<Result<ClientSuccess, ApiClientError>>;
|
|
164
|
+
readonly safeDelete: (path: string, opts?: RequestCallOptions) => Promise<Result<ClientSuccess, ApiClientError>>;
|
|
165
|
+
readonly safeHead: (path: string, opts?: RequestCallOptions) => Promise<Result<ClientSuccess, ApiClientError>>;
|
|
166
|
+
readonly safeRequest: (ax: AxiosRequestConfig, opts?: RequestCallOptions) => Promise<Result<ClientSuccess, ApiClientError>>;
|
|
167
|
+
}
|
|
168
|
+
declare function createApiClient(config: ApiClientConfig): ApiClient;
|
|
169
|
+
|
|
170
|
+
declare function isAuthenticationError(e: unknown): boolean;
|
|
171
|
+
declare function isForbiddenError(e: unknown): boolean;
|
|
172
|
+
declare function isPreconditionRequiredError(e: unknown): boolean;
|
|
173
|
+
declare function isPreconditionFailedError(e: unknown): boolean;
|
|
174
|
+
declare function isValidationError(e: unknown): boolean;
|
|
175
|
+
declare function isConflictError(e: unknown): boolean;
|
|
176
|
+
declare function isPayloadTooLargeError(e: unknown): boolean;
|
|
177
|
+
declare function isRetryablePerPolicy(e: unknown): boolean;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Truncate a value for safe logging (respects `maxBodyLogLength` from config when passed).
|
|
181
|
+
*/
|
|
182
|
+
declare function truncateForLog(body: unknown, maxLen?: number): string;
|
|
183
|
+
/**
|
|
184
|
+
* Redact sensitive header values for logging and error surfaces.
|
|
185
|
+
*/
|
|
186
|
+
declare function redactHeaderRecord(headers: Record<string, string>): Record<string, string>;
|
|
187
|
+
|
|
188
|
+
declare function applyJsonApiHeaders(config: InternalAxiosRequestConfig, method: string): InternalAxiosRequestConfig;
|
|
189
|
+
|
|
190
|
+
declare const IDEMPOTENCY_MAX_LENGTH = 64;
|
|
191
|
+
declare function defaultIdempotencyKey(): string;
|
|
192
|
+
declare function assertValidIdempotencyKey(key: string): void;
|
|
193
|
+
declare function isMutationMethod(method: string): boolean;
|
|
194
|
+
|
|
195
|
+
declare function formatIfMatch(version: number): string;
|
|
196
|
+
|
|
197
|
+
declare function resolveAcceptLanguage(provider?: () => string | null | undefined | Promise<string | null | undefined>): Promise<string | undefined>;
|
|
198
|
+
|
|
199
|
+
declare function resolveAuthorizationHeader(auth: AuthConfig | undefined): Promise<string | undefined>;
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Path for axios `url` (combined with `baseURL`). No duplicate `/api/v1`, no `//`.
|
|
203
|
+
*/
|
|
204
|
+
declare function resolveResourcePath(baseURL: string, path: string, mode: BaseUrlMode): string;
|
|
205
|
+
/**
|
|
206
|
+
* Prepare request URL for axios — if `fullUrl` is absolute http(s), return as-is for getByUrl.
|
|
207
|
+
*/
|
|
208
|
+
declare function normalizeHttpUrl(fullUrl: string): string;
|
|
209
|
+
|
|
210
|
+
declare function parseJsonApiDocument(payload: unknown): JsonApiDocument;
|
|
211
|
+
|
|
212
|
+
declare function parseJsonApiErrorBody(status: number, rawBody: unknown, headers: Readonly<Record<string, string>>, requestMethod?: string): ApiClientError;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Best-effort normalization for 207 bodies — structure varies by backend.
|
|
216
|
+
*/
|
|
217
|
+
declare function parseMultiStatusBody(raw: unknown): readonly MultiStatusItem[];
|
|
218
|
+
|
|
219
|
+
type HeadersLike = Headers | Record<string, string | undefined>;
|
|
220
|
+
declare function flattenAxiosHeaders(headers: unknown): Record<string, string>;
|
|
221
|
+
declare function getHeader(headers: Record<string, string>, name: string): string | undefined;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Resolve absolute Location for 202 per project-plan (relative to response URL when needed).
|
|
225
|
+
*/
|
|
226
|
+
declare function resolveAcceptedLocation(headers: HeadersLike, requestUrl: string): string;
|
|
227
|
+
|
|
228
|
+
interface OffsetPagination {
|
|
229
|
+
readonly kind: 'offset';
|
|
230
|
+
readonly page: number;
|
|
231
|
+
readonly totalPages?: number;
|
|
232
|
+
readonly total?: number;
|
|
233
|
+
}
|
|
234
|
+
interface CursorPagination {
|
|
235
|
+
readonly kind: 'cursor';
|
|
236
|
+
readonly hasMore: boolean;
|
|
237
|
+
readonly nextCursor?: string;
|
|
238
|
+
}
|
|
239
|
+
interface UnknownPagination {
|
|
240
|
+
readonly kind: 'unknown';
|
|
241
|
+
}
|
|
242
|
+
declare function parsePaginationKind(meta: Readonly<Record<string, unknown>> | undefined, links: Readonly<Record<string, string | null | undefined>> | undefined): OffsetPagination | CursorPagination | UnknownPagination;
|
|
243
|
+
declare function getNextPageUrl(links: Readonly<Record<string, string | null | undefined>> | undefined): string | undefined;
|
|
244
|
+
|
|
245
|
+
interface NormalizeOptions {
|
|
246
|
+
readonly transformResponseKeys?: TransformResponseKeysMode;
|
|
247
|
+
readonly requestUrl: string;
|
|
248
|
+
readonly requestMethod?: string;
|
|
249
|
+
}
|
|
250
|
+
declare function normalizeAxiosResponse(response: AxiosResponse<unknown>, options: NormalizeOptions): ClientSuccess;
|
|
251
|
+
|
|
252
|
+
interface RetryPolicyContext {
|
|
253
|
+
readonly method: string;
|
|
254
|
+
readonly status?: number;
|
|
255
|
+
/** First JSON:API error `code` when present */
|
|
256
|
+
readonly primaryErrorCode?: string;
|
|
257
|
+
readonly isNetworkError: boolean;
|
|
258
|
+
}
|
|
259
|
+
/** Pure policy per [.cursor/tasks/project-plan.md §7](../tasks/project-plan.md). */
|
|
260
|
+
declare function retryAllowed(ctx: RetryPolicyContext): boolean;
|
|
261
|
+
|
|
262
|
+
/** Parse Retry-After header: delta-seconds or HTTP-date. */
|
|
263
|
+
declare function parseRetryAfterSeconds(value: string | undefined): number | undefined;
|
|
264
|
+
|
|
265
|
+
interface DispatchOptions {
|
|
266
|
+
readonly retry?: RetryOptions;
|
|
267
|
+
readonly getPrimaryErrorCodeFromBody?: (body: unknown) => string | undefined;
|
|
268
|
+
}
|
|
269
|
+
declare function dispatchWithRetry<TData = unknown>(instance: AxiosInstance, config: AxiosRequestConfig, options: DispatchOptions): Promise<AxiosResponse<TData>>;
|
|
270
|
+
|
|
271
|
+
interface JsonApiQueryInput {
|
|
272
|
+
readonly filter?: Readonly<Record<string, string | number | boolean | undefined>>;
|
|
273
|
+
readonly sort?: readonly string[];
|
|
274
|
+
readonly fields?: Readonly<Record<string, readonly string[]>>;
|
|
275
|
+
readonly include?: readonly string[];
|
|
276
|
+
}
|
|
277
|
+
declare function buildJsonApiQuery(input: JsonApiQueryInput): Record<string, string>;
|
|
278
|
+
declare function buildOffsetPageParams(input: {
|
|
279
|
+
readonly number: number;
|
|
280
|
+
readonly size: number;
|
|
281
|
+
}): Record<string, string | number>;
|
|
282
|
+
declare function buildCursorPageParams(input: {
|
|
283
|
+
readonly cursor: string;
|
|
284
|
+
readonly size: number;
|
|
285
|
+
}): Record<string, string | number>;
|
|
286
|
+
|
|
287
|
+
type IncludedIndex = ReadonlyMap<string, JsonApiResourceObject>;
|
|
288
|
+
declare function indexIncluded(included: readonly JsonApiResourceObject[] | undefined): IncludedIndex;
|
|
289
|
+
declare function resolveIncluded(ref: JsonApiResourceLinkage, index: IncludedIndex): JsonApiResourceObject | undefined;
|
|
290
|
+
|
|
291
|
+
declare function readResourceVersion(resource: JsonApiResourceObject, etagHeader?: string): number | undefined;
|
|
292
|
+
declare function etagFromResponseHeaders(headerBag: unknown): string | undefined;
|
|
293
|
+
|
|
294
|
+
type ValidationGroups = Record<string, readonly string[]>;
|
|
295
|
+
declare function groupValidationErrorsByPointer(errors: readonly JsonApiErrorObject[]): ValidationGroups;
|
|
296
|
+
|
|
297
|
+
declare function createHealthCheck(target: ApiClientConfig | Pick<HealthGettable, 'get'>): () => Promise<boolean>;
|
|
298
|
+
interface HealthGettable {
|
|
299
|
+
get: (path: string) => Promise<unknown>;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
declare function parseDeprecationHeaders(headerBag: unknown): DeprecationInfo | null;
|
|
303
|
+
|
|
304
|
+
/** Shallow camelCase keys for `attributes` and `meta` only — copies document where needed. */
|
|
305
|
+
declare function applyTransformKeys(doc: JsonApiDocument, mode: TransformResponseKeysMode): JsonApiDocument;
|
|
306
|
+
|
|
307
|
+
interface PollOptions {
|
|
308
|
+
readonly maxAttempts?: number;
|
|
309
|
+
readonly delayMs?: number;
|
|
310
|
+
}
|
|
311
|
+
declare function pollAsyncResult(client: ApiClient, initial: Extract<ClientSuccess, {
|
|
312
|
+
kind: 'accepted';
|
|
313
|
+
}>, options?: PollOptions): Promise<ClientSuccess>;
|
|
314
|
+
|
|
315
|
+
declare const PACKAGE_VERSION: string;
|
|
316
|
+
|
|
317
|
+
export { type AcceptedBody, type ApiClient, type ApiClientConfig, ApiClientError, type AuthConfig, type BaseUrlMode, type ClientSuccess, type CursorPagination, DEFAULT_PAGE_SIZE_CAP, DEFAULT_TIMEOUT_MS, type DeprecationInfo, type ErrResult, IDEMPOTENCY_MAX_LENGTH, type IdempotencyReplayContext, type IncludedIndex, type JsonApiDocument, type JsonApiErrorDocument, type JsonApiErrorObject, type JsonApiPrimaryData, type JsonApiQueryInput, type JsonApiResourceLinkage, type JsonApiResourceObject, type JsonApiSuccessBody, type MultiStatusBody, type MultiStatusItem, type NoContentBody, type NormalizedResponseHeaders, type OffsetPagination, type OkResult, PACKAGE_VERSION, type PollOptions, type RequestCallOptions, type Result, type RetryOptions, type TokenProvider, type TransformResponseKeysMode, type UnknownPagination, type ValidationGroups, applyJsonApiHeaders, applyTransformKeys, assertValidIdempotencyKey, buildCursorPageParams, buildJsonApiQuery, buildOffsetPageParams, createApiClient, createHealthCheck, defaultIdempotencyKey, dispatchWithRetry, etagFromResponseHeaders, flattenAxiosHeaders, formatIfMatch, getHeader, getNextPageUrl, groupValidationErrorsByPointer, indexIncluded, isApiClientError, isAuthenticationError, isConflictError, isForbiddenError, isMutationMethod, isPayloadTooLargeError, isPreconditionFailedError, isPreconditionRequiredError, isRetryablePerPolicy, isValidationError, normalizeAxiosResponse, normalizeHttpUrl, parseDeprecationHeaders, parseJsonApiDocument, parseJsonApiErrorBody, parseMultiStatusBody, parsePaginationKind, parseRetryAfterSeconds, pollAsyncResult, readResourceVersion, redactHeaderRecord, resolveAcceptLanguage, resolveAcceptedLocation, resolveAuthorizationHeader, resolveIncluded, resolveResourcePath, retryAllowed, truncateForLog };
|