@madewithremy/admin 0.1.35 → 0.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -4
- package/dist/index.js.map +1 -1
- package/dist/prod.js +2 -2
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ctx.ts","../src/config.ts","../src/parseJsonConfig.ts","../src/ops/agent.ts","../src/errors.ts","../src/http.ts","../src/ops/tasks.ts","../src/ops/analytics.ts","../src/ops/events.ts","../src/ops/crashes.ts","../src/ops/cron.ts","../src/ops/data.ts","../src/ops/dataSources.ts","../src/sleep.ts","../src/poll.ts","../src/output.ts","../src/upload.ts","../src/ops/dataSourceJobs.ts","../src/ops/dataSourceConnectors.ts","../src/ops/dataSourceEvals.ts","../src/ops/dataSourceMappers.ts","../src/ops/db.ts","../src/ops/diagnostics.ts","../src/ops/releases.ts","../src/ops/domains.ts","../src/ops/email.ts","../src/ops/files.ts","../src/ops/infra.ts","../src/ops/issues.ts","../src/ops/jewels.ts","../src/ops/methods.ts","../src/ops/prerender.ts","../src/ops/qaRecordings.ts","../src/ops/requests.ts","../src/ops/secrets.ts","../src/ops/settings.ts","../src/ops/users.ts","../src/ops/voice.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["/**\n * The bound context every operation runs against: which app, as whom, where.\n *\n * Ops in src/ops/ take this as their first argument and are otherwise pure —\n * no env reads, no process coupling — so the same functions serve both the\n * CLI (context from the environment, built once in prod.ts) and the importable\n * client (context from createAdminClient's options).\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { WORKSPACE_DIR } from './config.js';\nimport { parseJsonConfig } from './parseJsonConfig.js';\n\nexport interface AdminContext {\n /** Org-scoped `sk_` API key. */\n apiKey: string;\n /** The app every operation is scoped to. */\n appId: string;\n /**\n * Who is acting, when that is not `appId` itself — set only when the caller\n * has retargeted at another app (`--app`, or `forApp()`), and carrying the\n * app they came FROM.\n *\n * Writes that record authorship attach it, so a cross-app issue says which\n * app filed it without the caller having to remember a second flag. That\n * matters more than it sounds: the information was always available here and\n * being optional at the call site is precisely how it came to be omitted\n * everywhere.\n */\n originAppId?: string;\n /** API origin, no trailing slash. */\n baseUrl: string;\n}\n\nexport const DEFAULT_BASE_URL = 'https://api.mindstudio.ai';\n\n/**\n * Resolve the appId the way the CLI always has: `mindstudio.json` in the\n * workspace. Throws a plain Error with the CLI's historical message text —\n * prod.ts's catch turns it into `{error}` + exit 10, and the client surfaces\n * it as-is.\n */\nexport function loadWorkspaceAppId(workspaceDir = WORKSPACE_DIR): string {\n const manifestPath = path.join(workspaceDir, 'mindstudio.json');\n let raw: string;\n try {\n raw = fs.readFileSync(manifestPath, 'utf-8');\n } catch (err: any) {\n if (err.code === 'ENOENT') {\n throw new Error(`mindstudio.json not found at ${manifestPath}`);\n }\n throw new Error(`Failed to read mindstudio.json: ${err.message}`);\n }\n // Tolerant parse, but deliberately read-only: this is a short-lived process\n // and shouldn't mutate the workspace out from under the running sandbox.\n const result = parseJsonConfig<{ appId?: string }>(raw);\n if (!result.ok) {\n throw new Error(`Failed to parse mindstudio.json: ${result.error}`);\n }\n if (!result.value.appId) {\n throw new Error('mindstudio.json exists but has no appId');\n }\n return result.value.appId;\n}\n","/**\n * Local-environment locations for the commands that touch the box rather than\n * the management API: the workspace (files put/get, datasources add, releases\n * wait's git HEAD sniff) and the sandbox sidecar (qa-recordings export). API\n * credentials and appId resolution live in ctx.ts.\n */\n\n// The dev box sets `WORKSPACE_DIR`, so the fallback is only reached outside one. It names the box's\n// own layout rather than a stale provider path so that a caller without the env var lands somewhere\n// recognisable instead of on a directory that has not existed for two sandbox generations.\nexport const WORKSPACE_DIR =\n process.env['WORKSPACE_DIR'] || '/home/remy/workspace';\n\n// The sandbox's local sidecar, on a fixed port started by the sandbox\n// supervisor (mindstudio-sandbox/src/index.ts). Only `qa-recordings export` uses\n// it — the one operation needing the dev box's headless Chrome and ffmpeg\n// rather than the management API. Nothing answering is what running outside a\n// sandbox looks like, and that command says so.\nexport const SIDECAR_URL =\n process.env['REMY_SIDECAR_URL'] || 'http://127.0.0.1:4388';\n","/**\n * Pure parser for MindStudio-owned JSON config files. No I/O, no repair.\n *\n * App configs (`mindstudio.json`, interface configs like `web.json`) are\n * authored by remy, so they pick up the usual LLM-JSON slop — most often a\n * trailing comma left behind when an array entry is deleted.\n *\n * Strategy: strict JSON.parse first, JSON5 as a rescue. Strict-first means the\n * steady state is unaffected; the JSON5 path only engages for a file that would\n * otherwise have failed outright.\n *\n * Deliberately pure and read-only: this short-lived CLI must not mutate the\n * workspace out from under the running sandbox, whose own read path\n * (`jsonConfig.ts` in mindstudio-sandbox, where this module originated)\n * repairs the file on disk for the callers that DO write.\n */\n\nimport JSON5 from 'json5';\n\nexport type ParseResult<T> =\n | { ok: true; value: T; repaired: false }\n /** Strict parse failed; JSON5 rescued it. `error` is the strict failure. */\n | { ok: true; value: T; repaired: true; error: string }\n /** `notFound` separates \"no such file\" from \"file exists but is broken\" —\n * callers log those very differently. */\n | { ok: false; error: string; notFound: boolean };\n\nexport function msg(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * Parse a config string. Pure — no I/O, no repair. Use this when the caller\n * already holds the file contents, or must not write (e.g. the CLI).\n */\nexport function parseJsonConfig<T>(raw: string): ParseResult<T> {\n let strictError: string;\n try {\n return { ok: true, value: JSON.parse(raw) as T, repaired: false };\n } catch (err) {\n strictError = msg(err);\n }\n\n try {\n return {\n ok: true,\n value: JSON5.parse(raw) as T,\n repaired: true,\n error: strictError,\n };\n } catch (err) {\n // Report the JSON5 error, not the strict one. JSON5 got further — it\n // tolerated the slop and failed on whatever is genuinely broken (a\n // truncated write, say), so its position is the actionable one. The\n // strict error would point at the first trailing comma and mislead.\n return { ok: false, error: msg(err), notFound: false };\n }\n}\n","/**\n * Agent-chat thread log operations.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/agent.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n AgentThreadsListResult,\n AgentThreadsGetResult,\n} from '../types/agent.js';\n\nexport interface ThreadsListParams {\n /** Max threads per page (default 20, server clamps to 100). */\n limit?: number;\n /** Pagination cursor from a prior page's `nextCursor`. */\n cursor?: string;\n}\n\n/**\n * Every conversation the app's agent has had, newest activity first.\n *\n * Returns cursored pages; pass `nextCursor` from one page as `cursor` for the\n * next. Transcripts are not included — fetch a thread with `threadsGet`.\n *\n * `toolErrorCount` and `hasTurnError` are how you find the conversations worth\n * reading, and `devSession` separates your own test threads from real traffic.\n *\n * @example\n * const { threads } = await admin.agent.threadsList({ limit: 20 });\n * const broken = threads.filter((t) => t.toolErrorCount > 0 || t.hasTurnError);\n */\nexport function threadsList(ctx: AdminContext, params: ThreadsListParams = {}) {\n return call<AgentThreadsListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/agent-threads${qs(params)}`,\n );\n}\n\n/**\n * One thread with its full transcript: what the user said, what the agent\n * replied, which tools it called with which arguments, and what came back.\n *\n * This is the primary tool for iterating on an agent's system prompt and tool\n * descriptions — read what actually happened rather than guessing. Each method\n * tool call carries a `requestId`; pass it to `requests.get()` for that call's\n * input, output, stdout and error.\n *\n * @throws AdminApiError `thread_not_found` (404).\n * @example\n * const thread = await admin.agent.threadsGet('4f6c…');\n * console.log(thread.messages);\n */\nexport function threadsGet(ctx: AdminContext, threadId: string) {\n return call<AgentThreadsGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/agent-threads/${seg(threadId)}`,\n );\n}\n","/**\n * Error + exit-code vocabulary for the remy-admin CLI.\n *\n * Exit codes are a contract remy can branch on without parsing stdout. The\n * 0-4 range belongs to `releases wait` (see HELP_RELEASES) and predates this\n * module; `generic` is deliberately 10 so that a bad API key or an unparseable\n * mindstudio.json can never be mistaken for exit 1 = \"build failed\".\n */\n\nexport const EXIT = {\n /** live (or preview, for a feature branch) */\n ok: 0,\n /** `releases wait` only: the build failed */\n buildFailed: 1,\n /** `releases wait` only: still building when --timeout elapsed */\n timeout: 2,\n /** `releases wait` only: no release ever appeared for the commit */\n notFound: 3,\n /** `releases wait` only: built, but a newer release replaced it */\n superseded: 4,\n /** Any other failure: bad arguments, missing config, API error, timeout. */\n generic: 10,\n} as const;\n\n/**\n * A failure that should be reported as `{\"error\": ...}` on stdout.\n *\n * Thrown rather than exiting so that main()'s catch can print the message and\n * set `process.exitCode`, letting node flush stdout naturally. Calling\n * process.exit() here would truncate the message at one pipe buffer (64 KiB) —\n * which is exactly how remy invokes this CLI.\n */\nexport class CliError extends Error {\n constructor(\n message: string,\n readonly code: number = EXIT.generic,\n ) {\n super(message);\n this.name = 'CliError';\n }\n}\n\n/**\n * A failure caused by bad input. Carries the command's verbatim usage string\n * so the caller sees exactly what it should have typed.\n */\nexport class UsageError extends CliError {\n constructor(detail: string | null, usage: string) {\n super([detail, usage].filter(Boolean).join('\\n'));\n this.name = 'UsageError';\n }\n}\n\n/**\n * Report a failure and stop.\n *\n * Throws rather than calling process.exit(): exit() does not drain an async\n * stdout write, so a message larger than one pipe buffer (64 KiB) was truncated\n * mid-JSON — and a pipe is exactly how remy invokes this CLI. The entry point's\n * catch prints and sets process.exitCode, letting node flush on its own. Typed\n * `never`, so callers use it as a terminator.\n */\nexport function fatal(message: string): never {\n throw new CliError(message);\n}\n\n/**\n * A non-2xx API response, thrown by the ops core (src/http.ts) so both skins\n * share one error surface: the CLI's entry-point catch prints `.message`\n * (built to the CLI's historical string) and exits 10; an importing caller\n * gets the structured fields.\n */\nexport class AdminApiError extends Error {\n constructor(\n readonly method: string,\n readonly path: string,\n readonly status: number,\n readonly body: unknown,\n ) {\n super(`API ${method} ${path} returned ${status}: ${JSON.stringify(body)}`);\n this.name = 'AdminApiError';\n }\n}\n\n/** A request that exceeded its time bound before a response arrived. */\nexport class AdminTimeoutError extends Error {\n constructor(label: string, timeoutMs: number) {\n super(`${label} timed out after ${timeoutMs / 1000}s`);\n this.name = 'AdminTimeoutError';\n }\n}\n","/**\n * The authed HTTP core under every operation, context-bound and process-free:\n * it throws typed errors (AdminApiError / AdminTimeoutError) and never prints\n * or exits, so the same functions serve the CLI and the importable client.\n *\n * Two entry points, because ops need two failure shapes: `call` throws on a\n * bad status (most ops), `tryCall` returns the status so a caller can tolerate\n * one (releases waitForCommit polls through 404s). The CLI-only raw/SSE\n * passthroughs live in cliStream.ts — they are output devices, not API calls.\n */\n\nimport type { AdminContext } from './ctx.js';\nimport { AdminApiError, AdminTimeoutError } from './errors.js';\n\n/** Bound one request, so a hung API call can't hang the caller indefinitely. */\nexport const REQUEST_TIMEOUT_MS = 30_000;\n/**\n * How long a poll loop keeps retrying through transient failures before it\n * gives up. A `--wait` can run for many minutes over a tunnel; one 502 from a\n * gateway says nothing about the thing being waited on.\n */\nexport const TRANSIENT_GRACE_MS = 2 * 60_000;\n\n/**\n * A failure worth retrying inside a poll loop: the API answered 5xx (a gateway\n * or tunnel between the CLI and the platform hiccupped), the request timed out,\n * or the socket never connected. A 4xx is a real answer and is not.\n */\nexport function isTransientError(err: unknown): boolean {\n if (err instanceof AdminApiError) {\n return err.status >= 500;\n }\n if (err instanceof AdminTimeoutError) {\n return true;\n }\n // undici surfaces a failed connection as a TypeError('fetch failed').\n return err instanceof TypeError;\n}\n/** The raw Lighthouse report is a large artifact pulled from object storage. */\nexport const REPORT_TIMEOUT_MS = 60_000;\n\n/** Percent-encode one URL path segment. */\nexport function seg(value: string | number): string {\n return encodeURIComponent(String(value));\n}\n\n/**\n * Query string ('' or '?a=1&b=2') from a params object; undefined/null values\n * are skipped. The ops-side counterpart of the CLI's Args.query().\n *\n * Takes `object` rather than a Record so ops can pass their typed params\n * interfaces directly (interfaces lack index signatures, so a Record\n * constraint would force a cast at every call site).\n */\nexport function qs(params: object): string {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined || value === null) {\n continue;\n }\n // An array repeats the key (`?label=a&label=b`) rather than joining with a\n // comma, which is the form express parses back into an array.\n if (Array.isArray(value)) {\n for (const entry of value) {\n search.append(key, String(entry));\n }\n continue;\n }\n search.set(key, String(value));\n }\n const text = search.toString();\n return text ? `?${text}` : '';\n}\n\nfunction authHeaders(ctx: AdminContext): Record<string, string> {\n return {\n Authorization: `Bearer ${ctx.apiKey}`,\n 'Content-Type': 'application/json',\n };\n}\n\n/**\n * Read a response body without assuming it is JSON.\n *\n * A 204 or an empty body is a legitimate success for the DELETE endpoints\n * (`secrets delete`, `users revoke-api-key`). res.json() throws on those, which\n * turned a successful mutation into a reported failure.\n */\nexport async function readBody(res: Response): Promise<any> {\n if (res.status === 204) {\n return { ok: true, status: 204 };\n }\n const text = await res.text().catch(() => '');\n if (!text.trim()) {\n return { ok: true, status: res.status };\n }\n try {\n return JSON.parse(text);\n } catch {\n return { raw: text };\n }\n}\n\nexport async function fetchWithTimeout(\n url: string,\n init: RequestInit,\n timeoutMs: number,\n label: string,\n): Promise<Response> {\n try {\n return await fetch(url, {\n ...init,\n signal: AbortSignal.timeout(timeoutMs),\n });\n } catch (err: any) {\n if (err?.name === 'TimeoutError') {\n throw new AdminTimeoutError(label, timeoutMs);\n }\n throw err;\n }\n}\n\n/**\n * `T` is the endpoint's response shape, transcribed from the youai-api route\n * in `src/types/`. Defaults to `unknown` so an unannotated call site that\n * touches the result fails to compile rather than silently going untyped.\n * Note: 204/empty responses surface as `{ ok: true, status }` (see readBody) —\n * delete-style result types reflect that, not the route's (absent) JSON.\n */\nexport async function call<T = unknown>(\n ctx: AdminContext,\n method: string,\n apiPath: string,\n body?: Record<string, unknown>,\n // Ops that hold the request for a full method/jewel run (jewels resolve\n // --approve, jewels dryrun) pass their own bound.\n timeoutMs: number = REQUEST_TIMEOUT_MS,\n): Promise<T> {\n const res = await fetchWithTimeout(\n `${ctx.baseUrl}${apiPath}`,\n {\n method,\n headers: authHeaders(ctx),\n ...(body ? { body: JSON.stringify(body) } : {}),\n },\n timeoutMs,\n `API ${method} ${apiPath}`,\n );\n\n if (!res.ok) {\n throw new AdminApiError(method, apiPath, res.status, await readBody(res));\n }\n\n return readBody(res);\n}\n\n/**\n * Like `call`, but never throws on an HTTP status — returns a structured\n * result so a caller can react to one (e.g. tolerate a 404 while a release\n * row is still being created after a push).\n */\nexport async function tryCall<T = unknown>(\n ctx: AdminContext,\n method: string,\n apiPath: string,\n): Promise<{ ok: boolean; status: number; body: T }> {\n const res = await fetchWithTimeout(\n `${ctx.baseUrl}${apiPath}`,\n { method, headers: authHeaders(ctx) },\n REQUEST_TIMEOUT_MS,\n `API ${method} ${apiPath}`,\n );\n return { ok: res.ok, status: res.status, body: await readBody(res) };\n}\n\n/** @internal Exposed for cliStream.ts, which shares the auth header shape. */\nexport { authHeaders };\n","/**\n * Task log operations: every task agent (`runTask`) the app ran.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/tasks.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type { TasksListResult, TasksGetResult } from '../types/tasks.js';\n\nexport interface TasksListParams {\n /** Max traces per page (default 20, server clamps to 100). */\n limit?: number;\n /** Pagination cursor from a prior page's `nextCursor`. */\n cursor?: string;\n}\n\n/**\n * Every task the app ran, newest started first, kept for 90 days.\n *\n * Returns cursored pages; pass `nextCursor` from one page as `cursor` for the\n * next. Transcripts are not included — fetch one with `get`.\n *\n * `outcome`, `toolErrorCount` and `hasTurnError` are how you find the runs\n * worth reading, and `devSession` separates your own dev runs from real\n * traffic.\n *\n * @example\n * const { traces } = await admin.tasks.list({ limit: 10 });\n * const broken = traces.filter((t) => t.outcome !== 'answered' || t.toolErrorCount > 0);\n */\nexport function list(ctx: AdminContext, params: TasksListParams = {}) {\n return call<TasksListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/task-traces${qs(params)}`,\n );\n}\n\n/**\n * One task with its full transcript: the prompt and tools it was given, its\n * input, each turn's reply and reasoning, and every tool call with what came\n * back.\n *\n * This is the primary tool for iterating on a task agent's prompt and tool\n * descriptions — read what actually happened rather than guessing. A method\n * tool's result carries a `requestId`; pass it to `requests.get()` for that\n * call's input, output, stdout and error. `result.traceId` from `runTask()`\n * is the id.\n *\n * @throws AdminApiError `task_trace_not_found` (404).\n * @example\n * const trace = await admin.tasks.get('0b9e…');\n * console.log(trace.outcome, trace.messages);\n */\nexport function get(ctx: AdminContext, traceId: string) {\n return call<TasksGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/task-traces/${seg(traceId)}`,\n );\n}\n","/**\n * Analytics (insights) operations.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/analytics.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n AnalyticsAiSourcesResult,\n AnalyticsBatchResult,\n AnalyticsCrawlersResult,\n AnalyticsLiveResult,\n AnalyticsMapResult,\n AnalyticsQueryResult,\n AnalyticsSourcesResult,\n} from '../types/analytics.js';\n\n/** Scope + time-window + click-filter params accepted by `sources`. */\nexport interface SourcesParams {\n /** Scope to a specific release id. */\n releaseId?: string;\n /** ISO date string for the start of the query window. */\n start?: string;\n /** ISO date string for the end of the query window. */\n end?: string;\n /** Max rows to return (default 25). */\n limit?: number;\n /** Row offset for paging. */\n offset?: number;\n /** Click-filter: equality match on path. Per-event-table backed (90-day retention). */\n path?: string;\n /** Click-filter: equality match on referrer host. Per-event-table backed (90-day retention). */\n referrerHost?: string;\n /** Click-filter: equality match on country. Per-event-table backed (90-day retention). */\n country?: string;\n /** Click-filter: equality match on city. Per-event-table backed (90-day retention). */\n city?: string;\n /** Click-filter: equality match on device type. Per-event-table backed (90-day retention). */\n device?: string;\n /** Click-filter: equality match on browser. Per-event-table backed (90-day retention). */\n browser?: string;\n /** Click-filter: equality match on OS. Per-event-table backed (90-day retention). */\n os?: string;\n /** Click-filter: equality match on language. Per-event-table backed (90-day retention). */\n language?: string;\n /** Click-filter: equality match on UTM source. Per-event-table backed (90-day retention). */\n utmSource?: string;\n /** Click-filter: equality match on UTM medium. Per-event-table backed (90-day retention). */\n utmMedium?: string;\n /** Click-filter: equality match on UTM campaign. Per-event-table backed (90-day retention). */\n utmCampaign?: string;\n}\n\n/** Same click-filter + scope params as `SourcesParams`; accepted by `map`. */\nexport interface MapParams {\n /** Scope to a specific release id. */\n releaseId?: string;\n /** ISO date string for the start of the query window. */\n start?: string;\n /** ISO date string for the end of the query window. */\n end?: string;\n /** Max points to return (default 500). */\n limit?: number;\n /** Row offset for paging. */\n offset?: number;\n /** Click-filter: equality match on path. Per-event-table backed (90-day retention). */\n path?: string;\n /** Click-filter: equality match on referrer host. Per-event-table backed (90-day retention). */\n referrerHost?: string;\n /** Click-filter: equality match on country. Per-event-table backed (90-day retention). */\n country?: string;\n /** Click-filter: equality match on city. Per-event-table backed (90-day retention). */\n city?: string;\n /** Click-filter: equality match on device type. Per-event-table backed (90-day retention). */\n device?: string;\n /** Click-filter: equality match on browser. Per-event-table backed (90-day retention). */\n browser?: string;\n /** Click-filter: equality match on OS. Per-event-table backed (90-day retention). */\n os?: string;\n /** Click-filter: equality match on language. Per-event-table backed (90-day retention). */\n language?: string;\n /** Click-filter: equality match on UTM source. Per-event-table backed (90-day retention). */\n utmSource?: string;\n /** Click-filter: equality match on UTM medium. Per-event-table backed (90-day retention). */\n utmMedium?: string;\n /** Click-filter: equality match on UTM campaign. Per-event-table backed (90-day retention). */\n utmCampaign?: string;\n}\n\nexport interface AiSourcesParams {\n /** Scope to a specific release id. */\n releaseId?: string;\n /** ISO date string for the start of the query window. */\n start?: string;\n /** ISO date string for the end of the query window. */\n end?: string;\n /** Max vendor rows to return (default 50). */\n limit?: number;\n}\n\nexport interface CrawlersParams {\n /**\n * Sub-endpoint to dispatch to:\n * - `overview` — vendor totals + top-crawled pages.\n * - `timeseries` — stacked-per-vendor hit counts bucketed over time.\n * - `recent` — last N raw crawler hit rows (curiosity feed).\n */\n kind: 'overview' | 'timeseries' | 'recent';\n /** Scope to a specific release id. */\n releaseId?: string;\n /** ISO date string for the start of the query window. */\n start?: string;\n /** ISO date string for the end of the query window. */\n end?: string;\n /** Max rows to return (default varies by sub). */\n limit?: number;\n /** Number of time buckets for `timeseries` (default 24). */\n buckets?: number;\n /** Max top-pages rows for `overview` (default 20, max 100). */\n topPagesLimit?: number;\n}\n\n/**\n * Run a single analytics query: metrics × dimensions × filters × time.\n *\n * The query body shape (all fields optional except `metrics`):\n * ```\n * metrics [\"pageviews\" | \"visitors\" | \"visits\" | \"events\", ...]\n * dimensions at most ONE entity dimension OR \"time\" (not both):\n * path referrerHost sourceCategory country city deviceType\n * browser os language visitorType utmSource utmMedium\n * utmCampaign utmTerm utmContent eventName\n * granularity required with \"time\": \"5m\" | \"hour\" | \"day\" | \"week\" | \"month\"\n * timezone IANA zone for day/week/month boundaries (default UTC)\n * filters [[op, dimension, [values...]], ...]\n * ops: \"is\" (any of) | \"is_not\" (none of) | \"contains\"\n * dateRange \"1h\" | \"24h\" | \"7d\" | \"30d\" | \"90d\" | \"all\"\n * or [\"<startISO>\", \"<endISO>\"] (default \"24h\")\n * orderBy grouped only: [[\"pageviews\" | \"events\", \"asc\" | \"desc\"]]\n * limit grouped only; default 25, max 1000\n * offset paging\n * releaseId optional release scope\n * ```\n *\n * Routing (rollup vs per-event table), window clamping, and metric\n * availability are determined by the query shape; the response `meta`\n * reports `source`, `window.served`, `clamped`, and `metricsOmitted`.\n * Summary KPIs, timeseries, every top-N, and event stats are all query\n * compositions — no dedicated endpoints exist for them.\n *\n * @example\n * const { results, meta } = await admin.analytics.query({\n * metrics: ['pageviews', 'visitors'],\n * dimensions: ['path'],\n * dateRange: '30d',\n * limit: 10,\n * });\n */\nexport function query(ctx: AdminContext, body: Record<string, unknown>) {\n return call<AnalyticsQueryResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/insights/query`,\n body,\n );\n}\n\n/**\n * Run up to 10 independent query bodies in one round trip.\n *\n * Results are in request order; each entry is a full `AnalyticsQueryResult`\n * (with its own `meta`). Accepts a bare array of query bodies or the wire\n * shape `{ queries: [...] }`.\n *\n * @example\n * const { results } = await admin.analytics.batch([\n * { metrics: ['pageviews', 'visits', 'visitors'] },\n * { metrics: ['pageviews'], dimensions: ['path'], limit: 10 },\n * ]);\n */\nexport function batch(ctx: AdminContext, queries: unknown[] | undefined) {\n return call<AnalyticsBatchResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/insights/query-batch`,\n { queries },\n );\n}\n\n/**\n * Ranked traffic sources: per-session first source (UTM > referrer > direct),\n * with category and vendor classification applied server-side.\n *\n * Per-event-table backed — bounded by 90-day retention. Click-filter params\n * accept equality only; use `query` with `\"is_not\"` / `\"contains\"` filters or\n * multi-dimension grouping for richer analysis.\n *\n * @example\n * const { results, total } = await admin.analytics.sources({ limit: 10 });\n */\nexport function sources(ctx: AdminContext, params: SourcesParams = {}) {\n return call<AnalyticsSourcesResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/insights/sources${qs(params)}`,\n );\n}\n\n/**\n * City lat/lon points for geo rendering.\n *\n * When any click-filter is present the per-event table is queried (90-day\n * retention); without filters the rollup table is used (full history).\n *\n * @example\n * const { points, total } = await admin.analytics.map({ country: 'US' });\n */\nexport function map(ctx: AdminContext, params: MapParams = {}) {\n return call<AnalyticsMapResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/insights/map${qs(params)}`,\n );\n}\n\n/**\n * One-shot live visitor snapshot: current unique count, country breakdown,\n * and up to 60 one-minute sparkline samples from the last hour.\n *\n * Backed by Redis presence keys; no analytics-table query.\n *\n * @example\n * const { count, countries, sparkline } = await admin.analytics.live();\n */\nexport function live(ctx: AdminContext) {\n return call<AnalyticsLiveResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/insights/live`,\n );\n}\n\n/**\n * Per-vendor AI-referral breakdown.\n *\n * Filters referrer-host rows to known AI-assistant hosts and aggregates up\n * to vendor level at read time. Multiple hosts may map to the same vendor\n * (e.g. `chat.openai.com` + `chatgpt.com` → OpenAI). Returns both the\n * vendor-level aggregates and the raw host-level rows.\n *\n * @example\n * const { results, hosts } = await admin.analytics.aiSources();\n */\nexport function aiSources(ctx: AdminContext, params: AiSourcesParams = {}) {\n return call<AnalyticsAiSourcesResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/insights/ai-sources${qs(params)}`,\n );\n}\n\n/**\n * AI-crawler / bot ingestion views.\n *\n * Dispatches to one of three sub-endpoints via `kind`:\n * - `overview` — total hits + per-vendor breakdown + top-crawled pages.\n * - `timeseries` — stacked-per-vendor hit counts bucketed over time.\n * - `recent` — last N raw crawler hit rows.\n *\n * Covers all bot traffic (AI assistants, search-engine crawlers, and a\n * generic \"Other\" bucket), not just AI crawlers.\n *\n * @example\n * const overview = await admin.analytics.crawlers({ kind: 'overview', topPagesLimit: 10 });\n */\nexport function crawlers(ctx: AdminContext, params: CrawlersParams) {\n const { kind, ...rest } = params;\n return call<AnalyticsCrawlersResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/insights/crawlers/${seg(kind)}${qs(rest)}`,\n );\n}\n","/**\n * App-events observability operations.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. The live tail is CLI-only (src/cliStream.ts) — the\n * import layer stays non-streaming by design.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport type {\n EventsChannelsListResult,\n EventsPublishResult,\n} from '../types/events.js';\n\nexport interface EventsScopeParams {\n /**\n * Environment scope to inspect: `live` (the default for reads),\n * `preview:<releaseId>`, or `dev:<sessionId>` — publishes and subscriptions\n * never cross scopes, so a dev session's events are visible only under its\n * `dev:` scope. A publish without one goes to the caller's own dev session.\n */\n scope?: string;\n}\n\nexport interface EventsPublishParams extends EventsScopeParams {\n /** Exact channel name(s) — no wildcards anywhere in app events. */\n channels: string | string[];\n /** The payload subscribers receive (≤256k serialized characters). */\n data: unknown;\n}\n\n/**\n * Channels with a publish or a subscription in the last 24h, with live\n * subscriber counts — recency-sorted, capped at 200.\n *\n * The debugging read: a channel with subscribers but no publishes (or the\n * reverse) usually means the frontend and backend spell the channel\n * differently.\n *\n * @example\n * const { channels } = await admin.events.channelsList();\n * const mismatch = channels.filter((c) => c.subscribers > 0 && !c.lastPublishAt);\n */\nexport function channelsList(\n ctx: AdminContext,\n params: EventsScopeParams = {},\n) {\n return call<EventsChannelsListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/events/channels${qs(params)}`,\n );\n}\n\n/**\n * Publish a test event, exactly as the app's own `events.publish` would —\n * same validation, same delivery, same metering. Lets a frontend subscriber\n * be verified before the backend trigger exists.\n *\n * Without `scope` it goes to the caller's own dev session, the preview they\n * are building in; `scope: 'live'` reaches real users. The result's `scope`\n * says where it went. `delivered` counts live subscriber connections per\n * published channel; `0` is normal (nobody listening), never an error.\n *\n * @throws AdminApiError `invalid_channels` / `payload_too_large` (400), and\n * `no_dev_session` (400) with no `scope` when the caller has no dev session.\n * @example\n * const { delivered } = await admin.events.publish({\n * channels: 'jobs:usr_123',\n * data: { type: 'ping' },\n * });\n */\nexport function publish(ctx: AdminContext, params: EventsPublishParams) {\n return call<EventsPublishResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/events/publish`,\n { channels: params.channels, data: params.data, scope: params.scope },\n );\n}\n","/**\n * Crash (frontend-error) operations.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/crashes.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n CrashesGetResult,\n CrashesListResult,\n CrashesOccurrencesResult,\n CrashesStatsResult,\n} from '../types/crashes.js';\n\nexport interface CrashesListParams {\n /** Filter to a specific release id. */\n releaseId?: string;\n /** Sort order: `'recent'` (default) or `'frequent'`. */\n sort?: string;\n /** Maximum crash groups to return (default 50). */\n limit?: number;\n /** Window start as an ISO 8601 date string. Defaults to 7 days ago. */\n start?: string;\n /** Window end as an ISO 8601 date string. Defaults to now. */\n end?: string;\n}\n\nexport interface CrashesOccurrencesParams {\n /** Filter to a specific release id. */\n releaseId?: string;\n /** Pagination cursor from a prior response's `nextCursor`. */\n cursor?: string;\n /** Maximum events to return (default 50). */\n limit?: number;\n /** Window start as an ISO 8601 date string. */\n start?: string;\n /** Window end as an ISO 8601 date string. */\n end?: string;\n}\n\nexport interface CrashesStatsParams {\n /** Filter to a specific release id. */\n releaseId?: string;\n /** Window start as an ISO 8601 date string. */\n start?: string;\n /** Window end as an ISO 8601 date string. */\n end?: string;\n /** Number of time buckets to return (default 24). */\n buckets?: number;\n}\n\n/**\n * Crash groups (one row per fingerprint) with occurrence counts and affected users.\n *\n * Groups are Sentry-style fingerprints. Each row carries an `exampleEventId`\n * — pass it to `crashes.get()` for a quick drill-in without iterating\n * occurrences. Time window defaults to the last 7 days when `start`/`end`\n * are omitted.\n *\n * @example\n * const { errors } = await admin.crashes.list({ sort: 'frequent', limit: 10 });\n */\nexport function list(ctx: AdminContext, params: CrashesListParams = {}) {\n return call<CrashesListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/frontend-errors${qs(params)}`,\n );\n}\n\n/**\n * Individual crash events for one fingerprint, cursor-paginated.\n *\n * Pass `nextCursor` from a prior response as `cursor` to fetch the next page.\n *\n * @param fingerprint The fingerprint string from a `list` row.\n * @example\n * const { errors, nextCursor } = await admin.crashes.occurrences('abc123fingerprint', { limit: 25 });\n */\nexport function occurrences(\n ctx: AdminContext,\n fingerprint: string,\n params: CrashesOccurrencesParams = {},\n) {\n return call<CrashesOccurrencesResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/frontend-errors/${seg(fingerprint)}/events${qs(params)}`,\n );\n}\n\n/**\n * Full crash event detail — stack trace, source location, breadcrumbs, and browser context.\n *\n * @param eventId The event id (e.g. `exampleEventId` from a `list` row, or\n * any id from an `occurrences` response).\n * @throws AdminApiError `not_found` (404) — the event id does not exist or\n * belongs to a different app.\n * @example\n * const event = await admin.crashes.get('evt_xyz789');\n */\nexport function get(ctx: AdminContext, eventId: string) {\n return call<CrashesGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/frontend-errors/events/${seg(eventId)}`,\n );\n}\n\n/**\n * Bucketed time series of total crash occurrence volume for the app.\n *\n * Returns per-bucket counts and overall totals for the window. When\n * `start`/`end` are omitted the server applies its own default window.\n *\n * @example\n * const { buckets, totals } = await admin.crashes.stats({ buckets: 24 });\n */\nexport function stats(ctx: AdminContext, params: CrashesStatsParams = {}) {\n return call<CrashesStatsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/frontend-errors/metrics/summary${qs(params)}`,\n );\n}\n","/**\n * Cron (scheduled job) operations.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/cron.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type { CronOverviewResult, CronRunResult } from '../types/cron.js';\n\nexport interface CronListParams {\n /** Recent runs to include per job (default 15, clamped 1–120). */\n runs?: number;\n}\n\n/**\n * Every scheduled job with its status and recent runs.\n *\n * Job status is `active | paused | blocked` (`statusReason` says why); a run's\n * id doubles as its request-log id, so a failing job's story continues with\n * `requests.get(runId)`.\n *\n * @example\n * const { jobs } = await admin.cron.list({ runs: 50 });\n * const blocked = jobs.filter((j) => j.status === 'blocked');\n */\nexport function list(ctx: AdminContext, params: CronListParams = {}) {\n return call<CronOverviewResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/cron/overview${qs(params)}`,\n );\n}\n\n/**\n * Trigger a job now (does not affect its schedule).\n *\n * Returns 202 immediately — the run continues in the background; check the\n * outcome via `requests.get(requestId)`.\n *\n * @param route The job's method id, as shown by `list`.\n * @throws AdminApiError `cron_job_not_found` (404) — the route isn't a\n * scheduled method; `run_already_triggered` (429) — a manual run is in\n * flight, or within the 30s debounce; `creator_unavailable` (400) — the\n * creator account is gone.\n * @example\n * const { requestId } = await admin.cron.run('dailyDigest');\n */\nexport function run(ctx: AdminContext, route: string) {\n return call<CronRunResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/cron/${seg(route)}/run`,\n );\n}\n","/**\n * Database sync operations: lift dev→live and live→dev.\n *\n * Ops are pure: (ctx, params) → typed result. No printing, no process coupling.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call } from '../http.js';\nimport type {\n DataLiftFromDevResult,\n DataLiftFromLiveResult,\n} from '../types/data.js';\n\nexport interface LiftFromDevParams {\n /**\n * Which of YOUR dev sessions to lift from, by dev release id. An app has a dev session per\n * workspace (one per person's box, one per person's CLI), and a lift only ever touches the\n * caller's own: without this it takes your newest, and a colleague's id is refused\n * (`not_your_dev_session`). Name it when you have more than one open. The ids are on the\n * dashboard's `devSessions`.\n */\n releaseId?: string;\n}\n\n/**\n * Destructively copy every dev-release database over the live-release databases.\n *\n * Whole-DB overwrite by name match, including auth tables — wipes whatever\n * live had, including signed-up users. Intended for first-publish / pre-launch\n * data sync only; do not run on a production app with real users. Writes an\n * audit row tagged `lift-dev-to-live`. The CLI skin requires the literal appId\n * AND `--confirm` as a double-gate; the op always sends `{ confirm: true }`.\n *\n * @throws AdminApiError `no_dev_session` (404) — no dev release exists (start a dev session first);\n * `no_live_release` (404) — app has never been published (publish first, then lift);\n * `not_your_dev_session` (403) — `releaseId` names someone else's dev session.\n * @example\n * const result = await admin.data.liftFromDev();\n * console.log(`Lifted ${result.databasesAffected.length} databases to live`);\n * // With more than one of your dev sessions open, name the one you mean:\n * await admin.data.liftFromDev({ releaseId: '8f2c1e04-...' });\n */\nexport function liftFromDev(ctx: AdminContext, params: LiftFromDevParams = {}) {\n return call<DataLiftFromDevResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/manage/lift-dev-to-live`,\n {\n confirm: true,\n ...(params.releaseId ? { releaseId: params.releaseId } : {}),\n },\n );\n}\n\nexport interface LiftFromLiveParams {\n /**\n * Empty dev databases in place — clears all rows, keeps schema and IDs,\n * no data read from live. Defaults to false (full copy from live).\n */\n truncate?: boolean;\n /**\n * Which of your dev sessions to overwrite, by dev release id; your newest when absent. See\n * `LiftFromDevParams.releaseId`.\n */\n releaseId?: string;\n}\n\n/**\n * Destructively replace dev-release databases with the live-release databases,\n * or truncate dev databases without reading from live.\n *\n * Only dev is overwritten — live/prod data is never touched. Useful for\n * reproducing a prod bug against real data or re-syncing a stale sandbox.\n * With `truncate: true` it instead empties the dev databases (keeps schema\n * and IDs, no data read from live). Writes an audit row tagged\n * `lift-live-to-dev`.\n *\n * @throws AdminApiError `no_dev_session` (404) — no dev release exists (start a dev session first);\n * `no_live_release` (404) — no live release (copy mode only; not thrown when `truncate` is true);\n * `not_your_dev_session` (403) — `releaseId` names someone else's dev session.\n * @example\n * // Pull live data into dev for debugging:\n * await admin.data.liftFromLive();\n * // Or just empty dev without pulling from live:\n * await admin.data.liftFromLive({ truncate: true });\n */\nexport function liftFromLive(\n ctx: AdminContext,\n params: LiftFromLiveParams = {},\n) {\n return call<DataLiftFromLiveResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/manage/lift-live-to-dev`,\n {\n confirm: true,\n ...(params.truncate ? { mode: 'truncate' } : {}),\n ...(params.releaseId ? { releaseId: params.releaseId } : {}),\n },\n );\n}\n","/**\n * Data-sources operations: document ingestion, corpus search, pipeline\n * configuration, and version management.\n *\n * Ops are pure (ctx, params) → typed result; no printing, no process coupling.\n * The CLI skin in commands/dataSources.ts owns everything flag-shaped (path\n * resolution, parseKeyValuePairs, configFromFlags, out/progress calls,\n * process.exit for wait-path exit codes).\n */\n\nimport { createHash } from 'node:crypto';\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport { renderProgress } from '../output.js';\nimport { elapsedSeconds, pollUntil, timedOut } from '../poll.js';\nimport { uploadDirect } from '../upload.js';\nimport type {\n DataSourcesBuildProgress,\n DataSourcesConfigResult,\n DataSourcesConfigUpdateResult,\n DataSourcesCreateResult,\n DataSourcesDeleteResult,\n DataSourcesDocument,\n DataSourcesDocumentConfirmResult,\n DataSourcesDocumentDeleteManyResult,\n DataSourcesDocumentDeleteResult,\n DataSourcesDocumentSelector,\n DataSourcesDocumentsResult,\n DataSourcesDocumentStatus,\n DataSourcesDropResult,\n DataSourcesIngestUpdate,\n DataSourcesListEntry,\n DataSourcesListResult,\n DataSourcesMoveResult,\n DataSourcesPromoteResult,\n DataSourcesRetrievalUpdate,\n DataSourcesRevectorizeResult,\n DataSourcesSearchResult,\n DataSourcesCountResult,\n DataSourcesDictionaryPushResult,\n DataSourcesDictionaryStatus,\n DataSourcesLinkResult,\n DataSourcesEntitiesResult,\n DataSourcesPassagesResult,\n DataSourcesUploadTokenResult,\n} from '../types/dataSources.js';\nimport type { DataSourceJob } from '../types/dataSourceJobs.js';\n\n/** @internal Consumed by the CLI skin; waitForIngest documents the default. */\nexport const DEFAULT_WAIT_TIMEOUT_MS = 15 * 60 * 1000;\nconst POLL_MS = 3000;\n\nfunction base(appId: string): string {\n return `/_internal/v2/apps/${appId}/datasources`;\n}\n\n/**\n * The per-document summary projection used by waitForIngest, status, and the\n * revectorize watch loop in the skin. Exported so the skin can reuse it for\n * the revectorize path without re-implementing it.\n * @internal Presentation helper for the CLI skin, not client surface.\n */\nexport const summarize = (d: DataSourcesDocumentStatus) => ({\n id: d.id,\n filename: d.filename,\n status: d.status,\n chunks: d.chunkCount,\n pages: d.pageCount,\n ...(d.errorMessage ? { error: d.errorMessage } : {}),\n});\n\n// ─── addDocument ─────────────────────────────────────────────────────────────\n\nexport interface AddDocumentParams {\n /** Data source slug. Created on first use. */\n slug: string;\n /** Original filename — used as the key and for MIME-type inference. */\n filename: string;\n /** File bytes to upload. */\n content: Buffer;\n /**\n * Scalar tags filterable at search time (≤ 16 keys,\n * `string | number | boolean` values).\n */\n metadata?: Record<string, string | number | boolean>;\n /**\n * What the document is about, as the app's own ids (≤ 256, printable ASCII,\n * no whitespace or commas). Every passage carries them; `[]` clears them.\n */\n entities?: string[];\n /**\n * The budget in dollars of the job that takes the rest of a file mapping\n * to more than a thousand documents (`AddDocumentResult.job`).\n */\n budgetDollars?: number;\n /**\n * Receives the exact progress strings the CLI prints today:\n * - `${filename}: unchanged, skipped`\n * - `${filename}: uploading N MB…`\n */\n onProgress?: (message: string) => void;\n}\n\nexport interface AddDocumentResult {\n filename: string;\n skipped: boolean;\n queued?: boolean;\n /**\n * The document, or the first of them on a mapped source. Null only when the\n * source's mapper answered `deletes` for the file.\n */\n document: DataSourcesDocument | null;\n /**\n * Every document the file became — one on an unmapped source — or the\n * first thousand of a file that maps to more.\n */\n documents: DataSourcesDocument[];\n /** How many documents the file maps to in all. */\n documentCount: number;\n /** How the source took the file; absent when it was already current. */\n outcome?: 'unmapped' | 'documents' | 'passthrough' | 'deletes';\n /** Documents the mapper produced that failed validation and were not registered. */\n invalid?: {\n count: number;\n examples: { document: number; reason: string }[];\n } | null;\n /**\n * The job registering and building the rest of a file that maps to more\n * than a thousand documents; it plans and starts on its own.\n */\n job?: DataSourceJob | null;\n}\n\n/**\n * Add one document to a data source.\n *\n * Three-step flow: hash → token → (skip-if-current) → upload → confirm.\n * Re-adding an unchanged file short-circuits at the token step and moves no\n * bytes. Re-adding with different `metadata` updates the tags in-place, also\n * without a re-upload. The data source is created on first use.\n *\n * @throws AdminApiError `invalid_content_hash` (400) — malformed hash\n * (internal; `addDocument` computes this from `content`).\n * @example\n * const result = await admin.dataSources.addDocument({\n * slug: 'policies',\n * filename: 'contract.pdf',\n * content: pdfBuffer,\n * metadata: { department: 'legal', year: 2026 },\n * });\n */\nexport async function addDocument(\n ctx: AdminContext,\n params: AddDocumentParams,\n): Promise<AddDocumentResult> {\n const { slug, filename, content, metadata, entities, onProgress } = params;\n const { budgetDollars } = params;\n const contentHash = createHash('sha256').update(content).digest('hex');\n\n const token = await call<DataSourcesUploadTokenResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/upload-token`,\n {\n slug,\n filename,\n contentHash,\n ...(metadata ? { metadata } : {}),\n ...(entities ? { entities } : {}),\n },\n );\n\n if (token.alreadyCurrent) {\n onProgress?.(`${filename}: unchanged, skipped`);\n const documents = token.documents ?? [token.document];\n return {\n filename,\n skipped: true,\n document: token.document,\n documents,\n documentCount: token.documentCount ?? documents.length,\n };\n }\n\n onProgress?.(\n `${filename}: uploading ${(content.length / 1024 / 1024).toFixed(1)}MB…`,\n );\n await uploadDirect(token.upload, content, filename);\n\n const confirmed = await call<DataSourcesDocumentConfirmResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/documents`,\n {\n slug,\n filename,\n contentHash,\n contentType: token.contentType,\n size: content.length,\n ...(metadata ? { metadata } : {}),\n ...(entities ? { entities } : {}),\n ...(budgetDollars !== undefined ? { budgetDollars } : {}),\n },\n );\n\n const documents =\n confirmed.documents ?? (confirmed.document ? [confirmed.document] : []);\n return {\n filename,\n skipped: false,\n queued: confirmed.queued,\n document: confirmed.document,\n documents,\n documentCount: confirmed.documentCount ?? documents.length,\n outcome: confirmed.outcome,\n invalid: confirmed.invalid ?? null,\n job: confirmed.job ?? null,\n };\n}\n\n// ─── waitForIngest ────────────────────────────────────────────────────────────\n\nexport interface WaitForIngestParams {\n slug: string;\n documentIds: string[];\n /** How long without movement before giving up. Defaults to DEFAULT_WAIT_TIMEOUT_MS (15 min). */\n timeoutMs?: number;\n /**\n * Receives the exact progress strings the CLI prints today:\n * `ingesting… X/Y done (Ns)`\n */\n onProgress?: (message: string) => void;\n}\n\nexport type SummarizedDocument = ReturnType<typeof summarize>;\n\nexport interface WaitForIngestResult {\n status: 'up-to-date' | 'done' | 'error' | 'timeout';\n documents: SummarizedDocument[];\n /** Present only on status === 'timeout'. */\n error?: string;\n}\n\n/**\n * Poll until every queued document reaches a terminal state.\n *\n * Terminal states: `done` (all succeeded), `error` (at least one failed),\n * `timeout` (still processing after `timeoutMs`, default 15 minutes). Polls\n * every 3 seconds. Returns a typed result so the caller can branch on\n * `status` without parsing strings.\n *\n * The `dataSource: slug` envelope and exit-code handling stay in the CLI skin\n * so the printed JSON is byte-identical to the pre-refactor CLI.\n *\n * @example\n * const result = await admin.dataSources.waitForIngest({\n * slug: 'policies',\n * documentIds: [doc.id],\n * onProgress: console.error,\n * });\n * if (result.status === 'error') { ... }\n */\nexport async function waitForIngest(\n ctx: AdminContext,\n params: WaitForIngestParams,\n): Promise<WaitForIngestResult> {\n const { slug, documentIds, onProgress } = params;\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n\n if (documentIds.length === 0) {\n return { status: 'up-to-date', documents: [] };\n }\n\n const wanted = new Set(documentIds);\n const pendingOf = (docs: DataSourcesDocumentStatus[]) =>\n docs.filter((d) => d.status === 'processing');\n\n const outcome = await pollUntil(\n async () => {\n // Only the documents being waited on: the source may hold millions.\n const docs = await allDocuments(ctx, { slug, ids: documentIds });\n return (docs ?? []).filter((d) => wanted.has(d.id));\n },\n (tracked) => pendingOf(tracked).length === 0,\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (tracked, start) =>\n `ingesting… ${tracked.length - pendingOf(tracked).length}/${tracked.length} done (${elapsedSeconds(start)}s)`,\n progressKey: (tracked) => pendingOf(tracked).length,\n onProgress,\n },\n );\n const tracked = outcome.value;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n documents: tracked.map(summarize),\n error: timedOut(\n timeoutMs,\n `with ${pendingOf(tracked).length} document(s) still processing`,\n ),\n };\n }\n return {\n status: tracked.some((d) => d.status === 'error') ? 'error' : 'done',\n documents: tracked.map(summarize),\n };\n}\n\n// ─── waitForCandidate ─────────────────────────────────────────────────────────\n\nexport interface WaitForCandidateParams {\n slug: string;\n /** How long without movement before giving up. Defaults to DEFAULT_WAIT_TIMEOUT_MS (15 min). */\n timeoutMs?: number;\n /** Receives `rebuilding… X/Y done (Ns)`. */\n onProgress?: (message: string) => void;\n}\n\nexport interface WaitForCandidateResult {\n status: 'ready' | 'error' | 'timeout';\n /** The candidate's build counts when the wait ended; null when it had no candidate. */\n counts: DataSourcesBuildProgress | null;\n /** The failed documents, first page, when any failed. */\n documents: SummarizedDocument[];\n /** Present only on status === 'timeout'. */\n error?: string;\n}\n\n/** Failed documents fetched for a status or a candidate wait. */\nexport const FAILURES_PAGE = 50;\n\n/**\n * Poll a candidate version (`revectorize`) until every document has built.\n * Reads the candidate's counts from the source list — one row, whatever the\n * corpus holds — and fetches the failures only at the end. `error` means at\n * least one failed; `promote` with `force` accepts that.\n */\nexport async function waitForCandidate(\n ctx: AdminContext,\n params: WaitForCandidateParams,\n): Promise<WaitForCandidateResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n\n const outcome = await pollUntil(\n async () => {\n const { dataSources } = await list(ctx);\n const source = dataSources.find((s) => s.slug === params.slug);\n if (!source) {\n throw new Error(`Data source \"${params.slug}\" not found.`);\n }\n return source.candidate?.progress ?? null;\n },\n (progress) => progress === null || progress.processing === 0,\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (progress, start) =>\n progress\n ? `rebuilding… ${progress.done}/${progress.total} done (${elapsedSeconds(start)}s)`\n : `rebuilding… (${elapsedSeconds(start)}s)`,\n progressKey: (progress) => progress?.processing ?? null,\n onProgress: params.onProgress,\n },\n );\n const counts = outcome.value;\n const failed =\n counts && counts.error > 0\n ? (\n await documents(ctx, {\n slug: params.slug,\n candidate: true,\n status: 'error',\n limit: FAILURES_PAGE,\n })\n ).documents.map(summarize)\n : [];\n if (!outcome.settled) {\n return {\n status: 'timeout',\n counts,\n documents: failed,\n error: timedOut(\n timeoutMs,\n `with ${counts?.processing ?? 0} document(s) still building`,\n ),\n };\n }\n return {\n status: counts && counts.error > 0 ? 'error' : 'ready',\n counts,\n documents: failed,\n };\n}\n\n// ─── documents ───────────────────────────────────────────────────────────────\n\nexport interface DocumentsParams {\n /** Data source slug. */\n slug: string;\n /** true → watch a candidate pipeline (revectorize in progress). */\n candidate?: boolean;\n /** Only these documents (at most DOCUMENTS_IDS_MAX per request). */\n ids?: string[];\n /** Page size, 1..1000 (server default 500). */\n limit?: number;\n /** `nextCursor` from the previous page. */\n cursor?: string;\n /** By the time the document was added; oldest first unless said otherwise. */\n order?: 'oldest' | 'newest';\n /** The failed builds only, newest failure first. */\n status?: 'error';\n /** Filenames starting with this. */\n filename?: string;\n}\n\n/** The server's cap on `ids` per request; `allDocuments` chunks to it. */\nexport const DOCUMENTS_IDS_MAX = 200;\n\n/**\n * Fetch one page of per-document ingest state for one pipeline, oldest first\n * unless `order` says otherwise; `status: 'error'` narrows to the failures and\n * `filename` to a name prefix.\n *\n * Returns an empty document list when the data source does not exist yet.\n * Pass `candidate: true` to watch a revectorization in progress. Follow\n * `nextCursor` for the next page, or use `allDocuments` to walk them all.\n *\n * @example\n * const { documents, nextCursor } = await admin.dataSources.documents({ slug: 'policies' });\n * const failed = await admin.dataSources.documents({ slug: 'policies', status: 'error' });\n */\nexport function documents(ctx: AdminContext, params: DocumentsParams) {\n return call<DataSourcesDocumentsResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/documents${qs({\n slug: params.slug,\n candidate: params.candidate || undefined,\n ids: params.ids?.length ? params.ids.join(',') : undefined,\n limit: params.limit,\n cursor: params.cursor,\n order: params.order,\n status: params.status,\n filename: params.filename,\n })}`,\n );\n}\n\n/**\n * Every document (or every one of `ids`), following pages to the end.\n *\n * With `ids`, requests are chunked to the server's per-request cap, so a wait\n * over hundreds of just-added files stays a handful of small calls rather than\n * a walk of the whole source.\n *\n * @example\n * const docs = await admin.dataSources.allDocuments({ slug: 'policies' });\n */\nexport async function allDocuments(\n ctx: AdminContext,\n params: Omit<DocumentsParams, 'cursor' | 'limit'>,\n): Promise<DataSourcesDocumentStatus[]> {\n const groups: Array<string[] | undefined> = params.ids\n ? Array.from(\n { length: Math.ceil(params.ids.length / DOCUMENTS_IDS_MAX) },\n (_, i) =>\n params.ids!.slice(i * DOCUMENTS_IDS_MAX, (i + 1) * DOCUMENTS_IDS_MAX),\n )\n : [undefined];\n const out: DataSourcesDocumentStatus[] = [];\n for (const ids of groups) {\n let cursor: string | undefined;\n do {\n const page = await documents(ctx, {\n slug: params.slug,\n candidate: params.candidate,\n ids,\n limit: 1000,\n cursor,\n order: params.order,\n status: params.status,\n filename: params.filename,\n });\n out.push(...(page.documents ?? []));\n cursor = page.nextCursor ?? undefined;\n } while (cursor);\n }\n return out;\n}\n\n// ─── list ─────────────────────────────────────────────────────────────────────\n\n/**\n * List all data sources with document counts, build progress, and active\n * version metadata.\n *\n * @example\n * const { dataSources } = await admin.dataSources.list();\n */\nexport function list(ctx: AdminContext) {\n return call<DataSourcesListResult>(ctx, 'GET', base(ctx.appId));\n}\n\n// ─── search ──────────────────────────────────────────────────────────────────\n\nexport interface SearchParams {\n /** Data source slug. */\n slug: string;\n /** Natural-language or keyword query. */\n query: string;\n /** Results to return (default 5, max 50). */\n topK?: number;\n /** 'hybrid' (default) | 'semantic' | 'lexical'. */\n mode?: string;\n /** Metadata equality filter or the full filter grammar as a plain object. */\n filter?: Record<string, unknown>;\n /** Cap hits per document; backfills from others. */\n maxPerDocument?: number;\n /** Return query-term offsets per hit. */\n highlight?: boolean;\n /** Search the candidate version instead of the live one. */\n candidate?: boolean;\n /** Assembled from triState(a, 'rerank'/'hybrid') in the skin. */\n retrieval?: Record<string, boolean>;\n}\n\n/**\n * Query a data source and return ranked passages with citations.\n *\n * `mode` in the response reports what actually ran (e.g. `reranked: false`\n * after an adaptive skip) rather than what was requested, so measurements\n * attribute numbers to the right path. Pass `candidate: true` to evaluate a\n * candidate pipeline before promoting it.\n *\n * @throws AdminApiError `no_candidate_pipeline` (404) — `candidate: true` but\n * no revectorization is in flight; `invalid_query` (400); `invalid_mode`\n * (400).\n * @example\n * const { results } = await admin.dataSources.search({\n * slug: 'policies',\n * query: 'what are the payment terms?',\n * });\n */\nexport function search(ctx: AdminContext, params: SearchParams) {\n const {\n slug,\n query,\n topK,\n mode,\n filter,\n maxPerDocument,\n highlight,\n candidate,\n retrieval,\n } = params;\n return call<DataSourcesSearchResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/search`,\n {\n slug,\n query,\n ...(topK ? { topK } : {}),\n ...(mode ? { mode } : {}),\n ...(filter ? { filter } : {}),\n ...(maxPerDocument !== undefined ? { maxPerDocument } : {}),\n ...(highlight ? { highlight: true } : {}),\n ...(candidate ? { candidate: true } : {}),\n ...(retrieval && Object.keys(retrieval).length ? { retrieval } : {}),\n },\n );\n}\n\nexport interface CountParams {\n /** Data source slug. */\n slug: string;\n /** Same grammar as search's filter; absent counts the whole corpus. */\n filter?: Record<string, unknown>;\n /** Count the candidate version instead of the live one. */\n candidate?: boolean;\n}\n\n/**\n * How many chunks match a filter — exact, over the whole corpus.\n *\n * `count({ slug, filter: { contains: query } })` is how many passages contain\n * all the query's words: the honest figure to show beside a search's hits.\n * Not a relevance count (none exists) and not the set `search` returns.\n *\n * @throws AdminApiError `invalid_filter` (400); `no_candidate_pipeline` (404)\n * with `candidate: true` and no revectorization in flight; `index_warming` /\n * `index_building` (503) while the corpus is loading or building.\n * @example\n * const { chunks } = await admin.dataSources.count({ slug: 'policies', filter: { contains: 'notice period' } });\n */\nexport function count(ctx: AdminContext, params: CountParams) {\n const { slug, filter, candidate } = params;\n return call<DataSourcesCountResult>(ctx, 'POST', `${base(ctx.appId)}/count`, {\n slug,\n ...(filter ? { filter } : {}),\n ...(candidate ? { candidate: true } : {}),\n });\n}\n\nexport interface EntitiesParams {\n /** Data source slug. */\n slug: string;\n /** Same grammar as search's filter; absent covers the whole corpus. */\n filter?: Record<string, unknown>;\n /** Entities to return, most first (default 20, at most 1,000). */\n limit?: number;\n /** Read the candidate version instead of the live one. */\n candidate?: boolean;\n}\n\n/**\n * Which entities the passages matching a filter are about, most first.\n *\n * Filtered on one entity, it answers what appears beside it: a co-mention\n * graph. `chunks` counts passages carrying each id, not documents, and is\n * approximate.\n *\n * @throws AdminApiError `invalid_filter` (400); `no_candidate_pipeline` (404)\n * with `candidate: true` and no revectorization in flight; `index_warming` /\n * `index_building` (503) while the corpus is loading or building.\n * @example\n * const { entities } = await admin.dataSources.entities({ slug: 'manuals', filter: { entities: ['P-101A'] } });\n */\nexport function entities(ctx: AdminContext, params: EntitiesParams) {\n const { slug, filter, limit, candidate } = params;\n return call<DataSourcesEntitiesResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/entities`,\n {\n slug,\n ...(filter ? { filter } : {}),\n ...(limit !== undefined ? { limit } : {}),\n ...(candidate ? { candidate: true } : {}),\n },\n );\n}\n\nexport interface PassagesParams {\n /** Data source slug. */\n slug: string;\n /** Same grammar as search's filter; absent lists the whole corpus. */\n filter?: Record<string, unknown>;\n /** The previous page's `nextCursor`. */\n cursor?: string;\n /** Passages per page (default 50, at most 200). */\n limit?: number;\n /** Read the candidate version instead of the live one. */\n candidate?: boolean;\n}\n\n/**\n * One page of every passage matching a filter, unranked: all the pages that\n * mention an entity, rather than search's best few. Passages come document by\n * document, each document's in order.\n *\n * @throws AdminApiError `invalid_filter` (400); `invalid_cursor` (400);\n * `no_candidate_pipeline` (404); `index_warming` / `index_building` (503).\n * @example\n * const { passages, nextCursor } = await admin.dataSources.passages({ slug: 'manuals', filter: { entities: ['P-1004A'] } });\n */\nexport function passages(ctx: AdminContext, params: PassagesParams) {\n const { slug, filter, cursor, limit, candidate } = params;\n return call<DataSourcesPassagesResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/passages`,\n {\n slug,\n ...(filter ? { filter } : {}),\n ...(cursor ? { cursor } : {}),\n ...(limit !== undefined ? { limit } : {}),\n ...(candidate ? { candidate: true } : {}),\n },\n );\n}\n\n// ─── config ───────────────────────────────────────────────────────────────────\n\n/**\n * Read the full pipeline configuration for one data source.\n *\n * Returns `ingest` (pinned — requires a revectorize to change) and\n * `retrieval` (live — takes effect on the next query, no rebuild needed).\n *\n * @throws AdminApiError `data_source_not_found` (404).\n * @example\n * const { ingest, retrieval } = await admin.dataSources.configGet('policies');\n */\nexport function configGet(ctx: AdminContext, slug: string) {\n return call<DataSourcesConfigResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/config?slug=${encodeURIComponent(slug)}`,\n );\n}\n\nexport interface ConfigSetParams {\n /** Data source slug. */\n slug: string;\n /**\n * Ingest settings (pinned). Changes are rejected on a populated source —\n * use `revectorize` instead to rebuild alongside the live one.\n */\n ingest?: DataSourcesIngestUpdate;\n /**\n * Retrieval settings (live). Take effect on the next query; no rebuild\n * required.\n */\n retrieval?: DataSourcesRetrievalUpdate;\n /**\n * Where the corpus lives: a dedicated resource (see `admin.infra`) or the\n * shared pool. An empty source moves on the spot; a populated one starts a\n * background move (see `move`) and the response carries its `migration`.\n */\n placement?: { resourceId: string } | 'shared';\n}\n\n/**\n * Update pipeline configuration.\n *\n * `retrieval` changes take effect on the next query at no cost. `ingest`\n * changes are rejected once the source has documents — use `revectorize`\n * instead, which builds a new version alongside the live one so search never\n * degrades.\n *\n * @throws AdminApiError `data_source_not_found` (404),\n * `data_source_migrating` (422) while a move is in flight.\n * @example\n * await admin.dataSources.configSet({\n * slug: 'policies',\n * retrieval: { rerank: { enabled: true } },\n * });\n */\nexport function configSet(ctx: AdminContext, params: ConfigSetParams) {\n const { slug, ingest, retrieval, placement } = params;\n return call<DataSourcesConfigUpdateResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/config`,\n {\n slug,\n ...(ingest ? { ingest } : {}),\n ...(retrieval ? { retrieval } : {}),\n ...(placement !== undefined ? { placement } : {}),\n },\n );\n}\n\n// ─── create ──────────────────────────────────────────────────────────────────\n\nexport interface CreateParams {\n /** Data source slug: lowercase [a-z0-9_-], up to 64 characters. */\n slug: string;\n /** Display name. */\n name?: string;\n /** Pinned ingest settings for the new pipeline; platform defaults otherwise. */\n ingest?: DataSourcesIngestUpdate;\n /**\n * Where the corpus lives from the start: a dedicated resource (see\n * `admin.infra`) or the shared pool (the default).\n */\n placement?: { resourceId: string } | 'shared';\n}\n\n/**\n * Create an empty data source, optionally on dedicated capacity.\n *\n * The one-step way to start a corpus on a resource. `add` also creates a\n * source on first use, but on the shared pool. Calling this for a source that\n * already exists returns it; a placement given then follows `configSet`'s\n * rule — an empty source moves on the spot, a populated one starts a move.\n *\n * @throws AdminApiError `invalid_data_source` (400), `data_source_limit` (422),\n * `resource_not_found` (404), `resource_destroyed` (422),\n * `data_source_migrating` (422), `capacity_exceeded` (422).\n * @example\n * await admin.dataSources.create({ slug: 'archive', placement: { resourceId } });\n */\nexport function create(ctx: AdminContext, params: CreateParams) {\n const { slug, name, ingest, placement } = params;\n return call<DataSourcesCreateResult>(ctx, 'POST', base(ctx.appId), {\n slug,\n ...(name ? { name } : {}),\n ...(ingest ? { ingest } : {}),\n ...(placement !== undefined ? { placement } : {}),\n });\n}\n\n// ─── move ────────────────────────────────────────────────────────────────────\n\nexport interface MoveParams {\n /** Data source slug. */\n slug: string;\n /** A dedicated resource (see `admin.infra`) or the shared pool. */\n placement: { resourceId: string } | 'shared';\n /**\n * Start the copy over instead of resuming a move already under way to the\n * same target: fresh chains cut at the target's current count, progress so\n * far discarded (points already copied are written again, harmlessly).\n */\n restart?: boolean;\n /**\n * Parallel chains to copy with, instead of the target size's default (XL 32,\n * Large 16, Medium 8, Small 4; max 128). The platform runs four chains per\n * worker, so this is the worker count times four. Takes effect when the\n * copy's windows are cut: with a move already under way, pair it with\n * `restart`.\n */\n chains?: number;\n}\n\n/**\n * Halt a move under way. Its chains stop at their next checkpoint and the\n * record reads `error: \"Stopped by operator.\"`; a plain `move` to the same\n * target resumes from the chains' cursors.\n *\n * @throws AdminApiError `data_source_not_found` (404), `no_move_in_flight`\n * (422) when nothing is being moved.\n * @example\n * await admin.dataSources.stopMove({ slug: 'archive' });\n */\nexport function stopMove(ctx: AdminContext, params: { slug: string }) {\n return call<DataSourcesMoveResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/move/stop`,\n { slug: params.slug },\n );\n}\n\n/**\n * Move a data source between placements: shared → dedicated, dedicated →\n * shared, or one resource to another.\n *\n * A populated source is copied onto the target in the background from its\n * stored vectors — nothing is re-extracted or re-embedded — and flips when the\n * copy lands. Search keeps serving from the old placement meanwhile. Adding,\n * removing or reconfiguring documents is refused with `data_source_migrating`\n * until it finishes; `waitForMove` blocks on that. Moving to `'shared'` is how\n * a source leaves a resource that is about to be destroyed.\n *\n * @throws AdminApiError `data_source_not_found` (404), `same_placement` (400),\n * `data_source_busy` (422) while documents are still building or a\n * candidate version exists, `data_source_migrating` (422), `capacity_<phase>`\n * (422) when the target resource is not active, `capacity_exceeded` (422)\n * when the target is too small, `resource_not_found` (404).\n * @example\n * await admin.dataSources.move({ slug: 'archive', placement: { resourceId } });\n * const result = await admin.dataSources.waitForMove({ slug: 'archive' });\n */\nexport function move(ctx: AdminContext, params: MoveParams) {\n return call<DataSourcesMoveResult>(ctx, 'POST', `${base(ctx.appId)}/move`, {\n slug: params.slug,\n placement: params.placement,\n ...(params.restart ? { restart: true } : {}),\n ...(params.chains !== undefined ? { chains: params.chains } : {}),\n });\n}\n\nexport interface WaitForMoveParams {\n slug: string;\n /** How long without movement before giving up. Defaults to DEFAULT_WAIT_TIMEOUT_MS (15 min). */\n timeoutMs?: number;\n /** Receives `copying… X/Y documents · N/min · about M min left (Ns)`. */\n onProgress?: (message: string) => void;\n}\n\nexport type WaitForMoveResult =\n | { status: 'done'; source: DataSourcesListEntry }\n | { status: 'failed'; source: DataSourcesListEntry; error: string }\n | { status: 'timeout'; source: DataSourcesListEntry; error: string };\n\n/**\n * Poll until a source's move has landed, failed, or the timeout elapses.\n *\n * Reads the source from `list` each poll; done when no move is in flight. A\n * failed move returns immediately with the platform's error.\n *\n * @throws AdminApiError `data_source_not_found` (404).\n */\nexport async function waitForMove(\n ctx: AdminContext,\n params: WaitForMoveParams,\n): Promise<WaitForMoveResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const outcome = await pollUntil(\n async () => {\n const { dataSources } = await list(ctx);\n const source = dataSources.find((s) => s.slug === params.slug);\n if (!source) {\n throw new Error(`Data source \"${params.slug}\" not found.`);\n }\n return source;\n },\n (source) => !source.migration || source.migration.error !== null,\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (source, start) =>\n renderProgress(source.migration!.progress, start),\n // A corpus of any size moves as long as it keeps moving; the timeout\n // bounds silence. The settle moves without copying — it builds the\n // target's full-text index and reports coverage — so its sample time\n // counts as movement too.\n progressKey: (source) =>\n source.migration\n ? `${source.migration.copied}|${source.migration.progress.updatedAt ?? ''}`\n : null,\n onProgress: params.onProgress,\n },\n );\n const source = outcome.value;\n const migration = source.migration;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n source,\n error: timedOut(\n timeoutMs,\n `with ${migration!.copied}/${migration!.total} documents copied`,\n ),\n };\n }\n if (migration?.error) {\n return { status: 'failed', source, error: migration.error };\n }\n return { status: 'done', source };\n}\n\n// ─── revectorize ──────────────────────────────────────────────────────────────\n\nexport interface RevectorizeParams {\n /** Data source slug. */\n slug: string;\n /** Ingest settings for the new version. Omit to adopt platform defaults. */\n ingest?: DataSourcesIngestUpdate;\n}\n\n/**\n * Start a new candidate pipeline alongside the live one.\n *\n * Builds a new version with the supplied settings, or platform defaults when\n * none are given (the upgrade path for a source pinned to an older chunker).\n * Search keeps serving the active version throughout. Reuses stored\n * extractions, so changing chunking never re-runs document extraction — only\n * re-chunking and re-embedding. Call `promote` to cut over.\n *\n * @throws AdminApiError `data_source_not_found` (404).\n * @example\n * const { candidateVersion } = await admin.dataSources.revectorize({\n * slug: 'policies',\n * ingest: { chunking: { maxChars: 900 } },\n * });\n */\nexport function revectorize(ctx: AdminContext, params: RevectorizeParams) {\n const { slug, ingest } = params;\n return call<DataSourcesRevectorizeResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/revectorize`,\n {\n slug,\n ...(ingest ? { ingest } : {}),\n },\n );\n}\n\n// ─── promote ──────────────────────────────────────────────────────────────────\n\nexport interface PromoteParams {\n /** Data source slug. */\n slug: string;\n /** Promote even if some candidate documents failed. */\n force?: boolean;\n}\n\n/**\n * Make the candidate pipeline version live.\n *\n * Atomically swaps the candidate for the active version and retires the old\n * one. Without `force`, promotion is blocked when any candidate document\n * failed. The retired version is kept; discard it with `drop` once rollback\n * is no longer wanted.\n *\n * @throws AdminApiError `data_source_not_found` (404).\n * @example\n * const { activeVersion } = await admin.dataSources.promote({ slug: 'policies' });\n */\nexport function promote(ctx: AdminContext, params: PromoteParams) {\n return call<DataSourcesPromoteResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/promote`,\n {\n slug: params.slug,\n ...(params.force ? { force: true } : {}),\n },\n );\n}\n\n// ─── drop ─────────────────────────────────────────────────────────────────────\n\nexport interface DropParams {\n /** Data source slug. */\n slug: string;\n /** Version number to drop. Omitted → the candidate is dropped. */\n version?: number;\n}\n\n/**\n * Discard a candidate or retired pipeline version.\n *\n * Never touches the active version. Omit `version` to drop the candidate;\n * pass a specific number to drop a retired version once rollback is no longer\n * wanted.\n *\n * @throws AdminApiError `data_source_not_found` (404); `pipeline_not_found`\n * (404) — no candidate exists, or the version number is unknown.\n * @example\n * await admin.dataSources.drop({ slug: 'policies' }); // drops the candidate\n */\nexport function drop(ctx: AdminContext, params: DropParams) {\n return call<DataSourcesDropResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/versions/drop`,\n {\n slug: params.slug,\n ...(params.version !== undefined ? { version: params.version } : {}),\n },\n );\n}\n\n// ─── rm (document delete) ─────────────────────────────────────────────────────\n\nexport interface RmParams {\n /** Data source slug. */\n slug: string;\n /** UUID of the document to remove. */\n documentId: string;\n}\n\n/**\n * Remove one document and its vectors from a data source.\n *\n * Deletes across every pipeline version, not just the active one — a document\n * deleted mid-migration is gone from the candidate too.\n *\n * @throws AdminApiError `data_source_not_found` (404); `document_not_found`\n * (404).\n * @example\n * await admin.dataSources.rm({ slug: 'policies', documentId });\n */\nexport function rm(ctx: AdminContext, params: RmParams) {\n return call<DataSourcesDocumentDeleteResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/documents/delete`,\n {\n slug: params.slug,\n documentId: params.documentId,\n },\n );\n}\n\n// ─── rmWhere (documents by filter) ───────────────────────────────────────────\n\nexport interface RmWhereParams {\n /** Data source slug. */\n slug: string;\n filter: DataSourcesDocumentSelector;\n}\n\n/**\n * Remove one page (up to 1,000) of the documents matching a selector, across\n * every pipeline version, and report how many still match. Loop while\n * `remaining > 0`; `rmWhereAll` does that.\n *\n * @throws AdminApiError `data_source_not_found` (404), `invalid_filter` (400),\n * `data_source_busy` (422) while a job is in flight, `data_source_migrating`\n * (422) during a move.\n * @example\n * await admin.dataSources.rmWhere({ slug: 'archive', filter: { metadata: { year: 2019 } } });\n */\nexport function rmWhere(ctx: AdminContext, params: RmWhereParams) {\n return call<DataSourcesDocumentDeleteManyResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/documents/delete-many`,\n { slug: params.slug, filter: params.filter },\n );\n}\n\n/** `rmWhere` until nothing matches. Reports each page through `onProgress`. */\nexport async function rmWhereAll(\n ctx: AdminContext,\n params: RmWhereParams & { onProgress?: (message: string) => void },\n): Promise<{ deleted: number }> {\n let deleted = 0;\n while (true) {\n const page = await rmWhere(ctx, params);\n deleted += page.deleted;\n if (page.remaining === 0 || page.deleted === 0) {\n return { deleted };\n }\n params.onProgress?.(\n `removed ${deleted.toLocaleString()} so far, ${page.remaining.toLocaleString()} remaining…`,\n );\n }\n}\n\n// ─── deleteSource ─────────────────────────────────────────────────────────────\n\n/**\n * Delete a whole data source — every version, every document, and every byte.\n *\n * Extraction caches survive (shared across sources by content hash), so\n * re-ingesting the same files into a new source costs no re-extraction.\n * Manage-plane only: running app code has no equivalent.\n *\n * @throws AdminApiError `data_source_not_found` (404).\n * @example\n * const { documents, versions } = await admin.dataSources.deleteSource('policies');\n */\nexport function deleteSource(ctx: AdminContext, slug: string) {\n return call<DataSourcesDeleteResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/delete`,\n { slug },\n );\n}\n\n/** One dictionary entry: the app's id for a thing and the names it goes by. */\nexport interface DictionaryEntryInput {\n id: string;\n names: string[];\n}\n\n/** Entries per page, and the bytes one page's JSON may run to. */\nconst DICTIONARY_PAGE_ENTRIES = 10_000;\nconst DICTIONARY_PAGE_BYTES = 4_000_000;\n\n/**\n * Push a source's dictionary, replacing the one it had: a stage, its pages\n * (each retried alone), and the commit. A new version re-tags the source's\n * passages in the background; an unchanged one commits nothing.\n *\n * @throws AdminApiError `invalid_dictionary` / `dictionary_name_too_short` (400)\n * on a page, naming the entry; `dictionary_too_large` (400) at the commit.\n * @example\n * await admin.dataSources.pushDictionary({ slug: 'manuals', entries: [{ id: 'P-101A', names: ['P-101A', 'Main Feed Pump'] }] });\n */\nexport async function pushDictionary(\n ctx: AdminContext,\n params: {\n slug: string;\n entries: DictionaryEntryInput[];\n linkerVersion?: number;\n onProgress?: (sent: number, total: number) => void;\n },\n): Promise<DataSourcesDictionaryPushResult> {\n const { slug, entries } = params;\n const stage = await call<{ stageId: string; pageMaxEntries: number }>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/dictionary/stage`,\n {\n slug,\n ...(params.linkerVersion !== undefined\n ? { linkerVersion: params.linkerVersion }\n : {}),\n },\n );\n const perPage = Math.min(\n DICTIONARY_PAGE_ENTRIES,\n stage.pageMaxEntries || DICTIONARY_PAGE_ENTRIES,\n );\n let pages = 0;\n let start = 0;\n while (start < entries.length) {\n let end = start;\n let bytes = 0;\n while (end < entries.length && end - start < perPage) {\n const size = JSON.stringify(entries[end]).length;\n if (end > start && bytes + size > DICTIONARY_PAGE_BYTES) {\n break;\n }\n bytes += size;\n end += 1;\n }\n await call(ctx, 'POST', `${base(ctx.appId)}/dictionary/page`, {\n slug,\n stageId: stage.stageId,\n page: pages,\n entries: entries.slice(start, end),\n });\n pages += 1;\n start = end;\n params.onProgress?.(start, entries.length);\n }\n return call<DataSourcesDictionaryPushResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/dictionary/commit`,\n { slug, stageId: stage.stageId, pages },\n );\n}\n\n/**\n * A source's current dictionary, and the relinks re-tagging its versions\n * while they run.\n *\n * @throws AdminApiError `data_source_not_found` (404).\n */\nexport function dictionary(ctx: AdminContext, params: { slug: string }) {\n return call<DataSourcesDictionaryStatus>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/dictionary`,\n { slug: params.slug },\n );\n}\n\n/**\n * What the source's current dictionary finds in a piece of text: each\n * mention, in order, with the ids it tags.\n *\n * @throws AdminApiError `data_source_not_found` (404).\n * @example\n * const { mentions } = await admin.dataSources.link({ slug: 'manuals', text: 'Replaced the seal on P101A.' });\n */\nexport function link(\n ctx: AdminContext,\n params: { slug: string; text: string },\n) {\n return call<DataSourcesLinkResult>(ctx, 'POST', `${base(ctx.appId)}/link`, {\n slug: params.slug,\n text: params.text,\n });\n}\n","/**\n * Do NOT unref() this timer, and do not \"dedupe\" it against the identically\n * named helper in DraftSnapshotManager, which does.\n *\n * Inside the CLI's polling loops (`releases wait`, `releases status --wait`,\n * `diagnostics get --wait`) this timer is often the only live handle, so an\n * unref'd version lets node exit mid-wait: the poll silently abandons and never\n * reports a result. Verified — the process exits 13 and the code after the\n * sleep never runs. The server can unref safely because its sockets keep the\n * loop alive; a short-lived CLI cannot.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","/**\n * The one polling loop under every `--wait`: read the thing, ask whether it\n * has settled, sleep, repeat, with a bounded grace for gateway errors and a\n * timeout. The waits differ only in what they read, what \"settled\" means and\n * how they describe progress; none of them owns a loop.\n */\n\nimport { isTransientError, TRANSIENT_GRACE_MS } from './http.js';\nimport { sleep } from './sleep.js';\n\nexport interface PollOptions<T> {\n /**\n * How long the thing may go WITHOUT MOVING before the wait gives up. With\n * `progressKey`, every change of the key restarts this clock, so an\n * operation of any length is waited out as long as it keeps moving and the\n * timeout bounds silence, not duration. Without it, the whole wait.\n */\n timeoutMs: number;\n pollMs: number;\n /** One line of progress for a value that has not settled; `start` is when the wait began. */\n describe?: (value: T, start: number) => string;\n /** Something that changes when the operation moves: a count, a phase, a timestamp. */\n progressKey?: (value: T) => string | number | null | undefined;\n onProgress?: (message: string) => void;\n}\n\nexport type PollOutcome<T> =\n { settled: true; value: T } | { settled: false; value: T };\n\n/**\n * Poll `read` until `isSettled` says so or the timeout elapses. A wait can run\n * for minutes through a tunnel; one gateway error is not an answer about the\n * thing being waited on, so it is retried for `TRANSIENT_GRACE_MS` before it\n * counts. Any other error propagates.\n */\nexport async function pollUntil<T>(\n read: () => Promise<T>,\n isSettled: (value: T) => boolean,\n options: PollOptions<T>,\n): Promise<PollOutcome<T>> {\n const start = Date.now();\n let movedAt = start;\n let lastKey: string | number | null | undefined;\n let transientSince: number | null = null;\n\n while (true) {\n let value: T;\n try {\n value = await read();\n transientSince = null;\n } catch (err) {\n if (!isTransientError(err)) {\n throw err;\n }\n transientSince ??= Date.now();\n if (Date.now() - transientSince > TRANSIENT_GRACE_MS) {\n throw err;\n }\n options.onProgress?.(\n `retrying after a gateway error… (${elapsedSeconds(start)}s)`,\n );\n await sleep(options.pollMs);\n continue;\n }\n\n if (isSettled(value)) {\n return { settled: true, value };\n }\n if (options.progressKey) {\n const key = options.progressKey(value);\n if (key !== lastKey) {\n lastKey = key;\n movedAt = Date.now();\n }\n }\n if (Date.now() - movedAt > options.timeoutMs) {\n return { settled: false, value };\n }\n if (options.describe) {\n options.onProgress?.(options.describe(value, start));\n }\n await sleep(options.pollMs);\n }\n}\n\nexport function elapsedSeconds(start: number): number {\n return Math.round((Date.now() - start) / 1000);\n}\n\n/** The standard timeout line: how long, and where the thing still is. */\nexport function timedOut(timeoutMs: number, still: string): string {\n return `Timed out after ${Math.round(timeoutMs / 1000)}s ${still}`;\n}\n","/**\n * The CLI's output contract, both halves in one place:\n * results and errors go to stdout as JSON, human progress goes to stderr.\n *\n * That split is what lets a caller pipe stdout straight into a JSON parser\n * while a person watching a long poll still sees something happen.\n */\n\nimport { elapsedSeconds } from './poll.js';\nimport type { OperationProgress } from './types/progress.js';\n\n/**\n * Compact JSON for machine callers, indented for a human at a terminal. remy\n * always reads this through a pipe, so it gets one JSON value per line — which\n * is what makes `--stream` output parseable line by line.\n */\nconst PRETTY = process.stdout.isTTY === true;\n\nexport function out(data: unknown): void {\n process.stdout.write(`${JSON.stringify(data, null, PRETTY ? 2 : 0)}\\n`);\n}\n\n/** Progress to stderr so stdout stays a clean stream of JSON values. */\nexport function progress(message: string): void {\n process.stderr.write(`${message}\\n`);\n}\n\n/** \"about 12 min left\" or \"about 2.5 h left\"; null without an ETA. */\nexport function describeEta(\n eta: string | null,\n now = Date.now(),\n): string | null {\n if (!eta) {\n return null;\n }\n const minutes = Math.max(1, Math.round((Date.parse(eta) - now) / 60_000));\n if (minutes < 90) {\n return `about ${minutes} min left`;\n }\n const hours = Math.round((minutes / 60) * 10) / 10;\n return `about ${hours} h left`;\n}\n\n/**\n * The one progress line every `--wait` prints: the operation's phase, its\n * count, the platform's measured rate and ETA, and how long this wait has run.\n * `extra` is the operation's own addendum (a job's spend, say).\n */\nexport function renderProgress(\n p: OperationProgress,\n start?: number,\n extra?: string | null,\n): string {\n const count =\n p.total !== null\n ? `${p.done.toLocaleString()}/${p.total.toLocaleString()} ${p.unit}`\n : p.done > 0\n ? `${p.done.toLocaleString()} ${p.unit}`\n : null;\n const rate =\n p.ratePerMinute !== null && p.ratePerMinute > 0\n ? `${Math.round(p.ratePerMinute).toLocaleString()}/min`\n : null;\n const parts = [\n `${p.phase}…`,\n // The operation's own word on what it is doing when the count does not\n // say (a settle building its full-text index); a failure's note is its\n // error and prints on its own line instead.\n p.phase !== 'failed' ? p.note : null,\n count,\n rate,\n describeEta(p.etaAt),\n extra ?? null,\n p.stalled ? 'no progress for 30 min' : null,\n ].filter((part): part is string => Boolean(part));\n const elapsed = start !== undefined ? ` (${elapsedSeconds(start)}s)` : '';\n return `${parts.join(' · ')}${elapsed}`;\n}\n","/**\n * Presigned-POST upload — bytes go straight to storage, never through the API,\n * so size isn't bounded by the API's JSON body limit. Shared by `files put`\n * and `datasources add`; the server mints `{ uploadUrl, uploadFields }` scoped\n * to one key, and this submits the multipart form (no auth headers — the\n * signature is in the fields).\n */\n\nexport async function uploadDirect(\n upload: { uploadUrl: string; uploadFields: Record<string, string> },\n bytes: Buffer,\n filename: string,\n): Promise<void> {\n const form = new FormData();\n for (const [key, value] of Object.entries(upload.uploadFields)) {\n form.append(key, value);\n }\n // Zero-copy view (a pooled Buffer can sit at an offset in a larger\n // ArrayBuffer, so slice by view — matters for the 100MB+ uploads this\n // path exists for). The cast is safe: fs reads never yield SharedArrayBuffer.\n const view = new Uint8Array(\n bytes.buffer as ArrayBuffer,\n bytes.byteOffset,\n bytes.byteLength,\n );\n form.append('file', new Blob([view]), filename);\n\n const res = await fetch(upload.uploadUrl, { method: 'POST', body: form });\n if (!res.ok) {\n const detail = await res.text().catch(() => '');\n throw new Error(\n `Upload of \"${filename}\" failed: ${res.status} ${res.statusText}${\n detail ? ` — ${detail.slice(0, 300)}` : ''\n }`,\n );\n }\n}\n","/**\n * Bulk ingestion jobs: load a corpus into a data source from a file-store\n * prefix or a manifest of URLs, with a plan (cost, size, duration) shown\n * before anything is spent.\n *\n * Ops are pure (ctx, params) → typed result. The CLI skin in\n * commands/dataSourceJobs.ts owns flags, progress printing and exit codes.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport { renderProgress } from '../output.js';\nimport { pollUntil, timedOut } from '../poll.js';\nimport { uploadDirect } from '../upload.js';\nimport type {\n DataSourceJob,\n DataSourceJobGetResult,\n DataSourceJobManifestTokenResult,\n DataSourceJobResult,\n DataSourceJobsListResult,\n DataSourceJobSource,\n} from '../types/dataSourceJobs.js';\n\n/** @internal Consumed by the CLI skin. */\nexport const DEFAULT_WAIT_TIMEOUT_MS = 60 * 60 * 1000;\nconst POLL_MS = 5000;\n\nfunction base(appId: string): string {\n return `/_internal/v2/apps/${appId}/datasources/jobs`;\n}\n\n// ─── start ───────────────────────────────────────────────────────────────────\n\nexport interface StartParams {\n /** Data source slug. Created on first use, like `add`. */\n slug: string;\n source: DataSourceJobSource;\n /** Run as soon as the plan passes the gates, without a separate approve. */\n approve?: boolean;\n /** Stop when estimated spend reaches this; default 1.5× the projection. */\n budgetDollars?: number;\n /** Batches in flight at once (default 64, max 128). */\n concurrency?: number;\n /**\n * Embed at the provider's priority tier: calls are admitted ahead of the\n * provider's queue at 1.5x the embedding price. Off by default.\n */\n priority?: boolean;\n /** Process only the first N objects — a sample of the corpus. */\n limit?: number;\n}\n\n/**\n * Start a job. The platform enumerates the source, reads a sample, and writes\n * a plan; the job then waits in `planned` for `approve` unless `approve` was\n * set. Nothing is embedded until it runs.\n *\n * @throws AdminApiError `data_source_busy` (422) — a move, a candidate\n * version or another job is in flight; `invalid_source` (400).\n * @example\n * const { job } = await admin.dataSourceJobs.start({\n * slug: 'archive',\n * source: { type: 'store', store: 'raw', access: 'private', prefix: '2024/' },\n * });\n */\nexport function start(ctx: AdminContext, params: StartParams) {\n const { slug, source, approve, budgetDollars, concurrency, priority, limit } =\n params;\n return call<DataSourceJobResult>(ctx, 'POST', base(ctx.appId), {\n slug,\n source,\n ...(approve ? { approve: true } : {}),\n ...(budgetDollars !== undefined ? { budgetDollars } : {}),\n ...(concurrency !== undefined ? { concurrency } : {}),\n ...(priority ? { priority: true } : {}),\n ...(limit !== undefined ? { limit } : {}),\n });\n}\n\n// ─── manifests ───────────────────────────────────────────────────────────────\n\nexport interface UploadManifestParams {\n slug: string;\n /** JSONL: one `{ url, filename?, externalId?, metadata? }` per line. */\n content: Buffer;\n}\n\n/**\n * Upload a manifest for `start` with a `manifest` source. Returns the key to\n * pass as `source.key`.\n */\nexport async function uploadManifest(\n ctx: AdminContext,\n params: UploadManifestParams,\n): Promise<{ key: string }> {\n const token = await call<DataSourceJobManifestTokenResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/manifest-token`,\n { slug: params.slug },\n );\n await uploadDirect(token.upload, params.content, 'manifest.jsonl');\n return { key: token.key };\n}\n\n// ─── read ────────────────────────────────────────────────────────────────────\n\nexport interface ListParams {\n /** Only this source's jobs; omit for every job on the app. */\n slug?: string;\n}\n\nexport function list(ctx: AdminContext, params?: ListParams) {\n return call<DataSourceJobsListResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}${qs({ slug: params?.slug })}`,\n );\n}\n\nexport interface JobIdParams {\n id: string;\n}\n\n/** @throws AdminApiError `job_not_found` (404). */\nexport function get(ctx: AdminContext, params: JobIdParams) {\n return call<DataSourceJobGetResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}`,\n );\n}\n\n// ─── controls ────────────────────────────────────────────────────────────────\n\n/**\n * Approve a planned job: the yes to the plan's spend. Refused when the\n * projection does not fit the source's placement or the workspace cannot\n * cover it.\n *\n * @throws AdminApiError `job_not_found` (404), `invalid_transition` (422),\n * `plan_requires_dedicated` (422), `plan_exceeds_capacity` (422),\n * `insufficient_credits` (402).\n */\nexport function approve(\n ctx: AdminContext,\n params: JobIdParams & {\n /** Batches in flight from here on (max 128); the plan was made at the job's current value. */\n concurrency?: number;\n /** Embed at the provider's priority tier from here on (1.5x the embedding price). */\n priority?: boolean;\n },\n) {\n return call<DataSourceJobResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/approve`,\n controlBody(params),\n );\n}\n\n/** The optional knobs approve and resume share; undefined when none is set. */\nfunction controlBody(params: {\n concurrency?: number;\n priority?: boolean;\n}): Record<string, unknown> | undefined {\n const body = {\n ...(params.concurrency !== undefined\n ? { concurrency: params.concurrency }\n : {}),\n ...(params.priority !== undefined ? { priority: params.priority } : {}),\n };\n return Object.keys(body).length > 0 ? body : undefined;\n}\n\n/** Stop dispatching batches; the ones in flight finish. */\nexport function pause(ctx: AdminContext, params: JobIdParams) {\n return call<DataSourceJobResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/pause`,\n );\n}\n\n/** Continue from the checkpoint; failed batches with attempts left are retried. */\nexport function resume(\n ctx: AdminContext,\n params: JobIdParams & {\n /** Batches in flight from here on (max 128). */\n concurrency?: number;\n /** Embed at the provider's priority tier from here on (1.5x the embedding price). */\n priority?: boolean;\n },\n) {\n return call<DataSourceJobResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/resume`,\n controlBody(params),\n );\n}\n\n/**\n * Run a finished job's failed batches again, after fixing what failed them.\n * The job goes back to `running`; `nothing_to_retry` when none failed.\n */\nexport function retry(ctx: AdminContext, params: JobIdParams) {\n return call<DataSourceJobResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/retry`,\n );\n}\n\n/** End the job. Documents already indexed stay. */\nexport function cancel(ctx: AdminContext, params: JobIdParams) {\n return call<DataSourceJobResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/cancel`,\n );\n}\n\n// ─── waits ───────────────────────────────────────────────────────────────────\n\nexport interface WaitParams {\n id: string;\n /** How long without movement before giving up. Default one hour. */\n timeoutMs?: number;\n onProgress?: (message: string) => void;\n}\n\nexport type WaitResult =\n | { status: 'done'; job: DataSourceJob }\n /** The plan is ready but the job will not run on its own: a gate refused, or it waits for approval. */\n | { status: 'planned'; job: DataSourceJob; error: string }\n | { status: 'failed'; job: DataSourceJob; error: string }\n | { status: 'timeout'; job: DataSourceJob; error: string };\n\n/**\n * Poll until the job leaves `planning`: the plan is ready (`done`), or a gate\n * refused it (`planned` with the job's error), or it could not be planned.\n */\nexport function waitForPlan(ctx: AdminContext, params: WaitParams) {\n return settle(ctx, params, (job) => job.state !== 'planning');\n}\n\n/**\n * Poll until the job reaches a terminal state, pauses for the owner, or\n * settles in `planned` with nothing about to move it: a gate refused an\n * auto-approved plan, or the plan waits for an approval nobody asked this wait\n * to give. A pause for errors that will resume itself (`autoResumeAt` set) is\n * ridden through; a pause that waits for the owner is reported as `failed`\n * with the pause reason, since nothing more will happen without them.\n */\nexport function waitForJob(ctx: AdminContext, params: WaitParams) {\n return settle(\n ctx,\n params,\n (job) =>\n !['planning', 'planned', 'running', 'paused'].includes(job.state) ||\n (job.state === 'planned' && (job.error !== null || !job.autoApprove)) ||\n (job.state === 'paused' && !job.autoResumeAt),\n );\n}\n\nasync function settle(\n ctx: AdminContext,\n params: WaitParams,\n isSettled: (job: DataSourceJob) => boolean,\n): Promise<WaitResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const outcome = await pollUntil(\n async () => (await get(ctx, { id: params.id })).job,\n isSettled,\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: describeProgress,\n // A load of any length is waited out while it moves; the timeout bounds\n // silence. Planning moves by objects listed, a run by documents.\n progressKey: (job) => `${job.state}:${job.progress.done}`,\n onProgress: params.onProgress,\n },\n );\n const job = outcome.value;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n job,\n error: timedOut(timeoutMs, `; job is still ${job.state}`),\n };\n }\n if (job.state === 'failed' || job.state === 'cancelled') {\n return {\n status: 'failed',\n job,\n error: job.error ?? `The job was ${job.state}.`,\n };\n }\n if (job.state === 'paused') {\n return {\n status: 'failed',\n job,\n error:\n job.error ??\n `The job paused (${job.pauseReason ?? 'user'}). Resume it to continue.`,\n };\n }\n if (job.state === 'planned' && (job.error !== null || job.autoApprove)) {\n return {\n status: 'planned',\n job,\n error:\n job.error ??\n 'The plan is ready but the job did not start. Approve it once the cause is fixed.',\n };\n }\n return { status: 'done', job };\n}\n\n/**\n * One line of progress in the job's own terms: the platform's phase, count,\n * rate and ETA, with the spend so far beside them. A planning walk that has\n * finished listing says so, since its count has stopped moving on purpose.\n */\nexport function describeProgress(job: DataSourceJob, start: number): string {\n if (job.state === 'planning' && job.enumerationDone) {\n return renderProgress(\n { ...job.progress, phase: 'planning' },\n start,\n `reading a sample of ${job.counts.objectsSeen.toLocaleString()} objects`,\n );\n }\n const spend =\n job.state === 'planning'\n ? null\n : `$${job.estimatedDollars.toFixed(2)}${\n job.budgetDollars !== null\n ? ` of $${job.budgetDollars.toFixed(2)}`\n : ''\n }`;\n return renderProgress(job.progress, start, spend);\n}\n","/**\n * S3 connectors: make a bucket the customer owns the origin of a data source,\n * and keep the source in sync with it.\n *\n * Ops are pure (ctx, params) → typed result. The CLI skin in\n * commands/dataSourceConnectors.ts owns flags, progress and exit codes.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport type {\n DataSourceConnectorDeletions,\n DataSourceConnectorGetResult,\n DataSourceConnectorResult,\n DataSourceSyncResult,\n} from '../types/dataSourceConnectors.js';\n\nfunction base(appId: string): string {\n return `/_internal/v2/apps/${appId}/datasources`;\n}\n\n// ─── connect ─────────────────────────────────────────────────────────────────\n\nexport interface ConnectParams {\n /** Data source slug. Created on first use, like `add`. */\n slug: string;\n bucket: string;\n /** AWS region of the bucket, e.g. `us-east-1`. */\n region: string;\n /** Key prefix to follow; omit for the whole bucket. */\n prefix?: string;\n /** S3-compatible endpoint (https; http for localhost). Omit for AWS. */\n endpoint?: string;\n /** NAME of the app secret holding the access key id. */\n accessKeyIdSecret: string;\n /** NAME of the app secret holding the secret access key. */\n secretAccessKeySecret: string;\n /** Default `mirror`. */\n deletions?: DataSourceConnectorDeletions;\n /** Ceiling a sync auto-approves under. */\n budgetDollarsPerSync?: number;\n}\n\n/**\n * Connect a source to a bucket. The two secrets must already exist on the app\n * (`secrets set`), and the keys must be able to list the prefix — both are\n * checked before anything is recorded. Calling again with the same bucket,\n * region, prefix and endpoint updates credentials and policy in place; a\n * different origin is refused until the source is disconnected.\n *\n * @throws AdminApiError `invalid_connector` (400), `connector_secret_missing`\n * (422), `connector_probe_failed` (422), `connector_exists` (422).\n * @example\n * await admin.dataSourceConnectors.connect({\n * slug: 'archive', bucket: 'acme-docs', region: 'us-east-1', prefix: 'contracts/',\n * accessKeyIdSecret: 'ARCHIVE_S3_KEY', secretAccessKeySecret: 'ARCHIVE_S3_SECRET',\n * });\n */\nexport function connect(ctx: AdminContext, params: ConnectParams) {\n const {\n slug,\n bucket,\n region,\n prefix,\n endpoint,\n accessKeyIdSecret,\n secretAccessKeySecret,\n deletions,\n budgetDollarsPerSync,\n } = params;\n return call<DataSourceConnectorResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/connector`,\n {\n slug,\n bucket,\n region,\n ...(prefix !== undefined ? { prefix } : {}),\n ...(endpoint !== undefined ? { endpoint } : {}),\n accessKeyIdSecret,\n secretAccessKeySecret,\n ...(deletions !== undefined ? { deletions } : {}),\n ...(budgetDollarsPerSync !== undefined ? { budgetDollarsPerSync } : {}),\n },\n );\n}\n\n// ─── read ────────────────────────────────────────────────────────────────────\n\n/** The source's connector with its object counts, or `connector: null`. */\nexport function get(ctx: AdminContext, params: { slug: string }) {\n return call<DataSourceConnectorGetResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/connector${qs({ slug: params.slug })}`,\n );\n}\n\n// ─── disconnect ──────────────────────────────────────────────────────────────\n\n/**\n * Stop following the bucket. The documents stay; only the connector and its\n * object index go.\n *\n * @throws AdminApiError `connector_not_found` (422), `data_source_busy` (422)\n * while a job is in flight.\n */\nexport function disconnect(ctx: AdminContext, params: { slug: string }) {\n return call<DataSourceConnectorResult & { removed: true }>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/connector/remove`,\n { slug: params.slug },\n );\n}\n\n// ─── sync ────────────────────────────────────────────────────────────────────\n\nexport interface SyncParams {\n slug: string;\n /** Override the connector's per-sync budget for this run, in dollars. */\n budgetDollars?: number;\n /** Only the first N objects of the listing — a slice to measure or check. */\n limit?: number;\n /** Batches in flight (default 64, max 128). */\n concurrency?: number;\n /** Embed at the provider's priority tier (1.5x the embedding price). Off by default. */\n priority?: boolean;\n}\n\n/**\n * Start a sync: list the bucket, diff by ETag, run a job over what changed.\n * Auto-approved under the connector's per-sync budget; a plan over it (or over\n * the placement's capacity) waits in `planned` for `dataSourceJobs.approve`.\n * Block on the result with `dataSourceJobs.waitForJob`.\n *\n * @throws AdminApiError `connector_not_found` (422), `data_source_busy` (422).\n */\nexport function sync(ctx: AdminContext, params: SyncParams) {\n return call<DataSourceSyncResult>(ctx, 'POST', `${base(ctx.appId)}/sync`, {\n slug: params.slug,\n ...(params.budgetDollars !== undefined\n ? { budgetDollars: params.budgetDollars }\n : {}),\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n ...(params.concurrency !== undefined\n ? { concurrency: params.concurrency }\n : {}),\n ...(params.priority ? { priority: true } : {}),\n });\n}\n","/**\n * Warming an index, sampling a source, and retrieval evals: query sets, runs,\n * comparisons. Ops are pure (ctx, params) → typed result; the CLI skin in\n * commands/dataSourceEvals.ts owns flags, progress printing and exit codes.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport { renderProgress } from '../output.js';\nimport { elapsedSeconds, pollUntil, timedOut } from '../poll.js';\nimport { list as listSources } from './dataSources.js';\nimport type { DataSourcesListEntry } from '../types/dataSources.js';\nimport type {\n DataSourcesHydrateResult,\n DataSourcesSampleResult,\n EvalCompareResult,\n EvalQueriesAddResult,\n EvalQueriesListResult,\n EvalQueryStyle,\n EvalRetrieval,\n EvalRun,\n EvalRunResult,\n EvalRunsListResult,\n EvalSet,\n EvalSetGetResult,\n EvalSetResult,\n EvalSetsListResult,\n} from '../types/dataSourceEvals.js';\n\n/** @internal Consumed by the CLI skin. */\nexport const DEFAULT_WAIT_TIMEOUT_MS = 30 * 60 * 1000;\nconst POLL_MS = 4000;\n\nfunction base(appId: string): string {\n return `/_internal/v2/apps/${appId}/datasources`;\n}\n\n// ─── hydrate ─────────────────────────────────────────────────────────────────\n\n/**\n * Warm a source's index if it is cold. A search on a large cold index answers\n * `index_warming` until the reload lands; call this before a demo, or after an\n * eviction you know about. Answers `resident: true` when nothing was needed.\n */\nexport function hydrate(ctx: AdminContext, params: { slug: string }) {\n return call<DataSourcesHydrateResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/hydrate`,\n { slug: params.slug },\n );\n}\n\n/**\n * Recreate a dedicated source's collection with the platform's current shape\n * and refill it from the stored vectors. Nothing is re-embedded. Dedicated\n * capacity only; refused while a job, move, hydration or candidate version is\n * in flight, and with `collection_shared` when another source shares the\n * collection on that capacity. Same response as `hydrate`: follow it with\n * `waitForHydration`.\n *\n * @throws AdminApiError `reindex_requires_dedicated` (422), `data_source_busy`\n * (422), `collection_shared` (422).\n */\nexport function reindex(ctx: AdminContext, params: { slug: string }) {\n return call<DataSourcesHydrateResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/reindex`,\n { slug: params.slug },\n );\n}\n\nexport interface WaitForHydrationParams {\n slug: string;\n /** How long without movement before giving up. Defaults to DEFAULT_WAIT_TIMEOUT_MS (30 min). */\n timeoutMs?: number;\n /** Receives `copying… X/Y documents · N/min · about M min left (Ns)`. */\n onProgress?: (message: string) => void;\n}\n\nexport type WaitForHydrationResult =\n | { status: 'done'; source: DataSourcesListEntry }\n | { status: 'failed'; source: DataSourcesListEntry; error: string }\n | { status: 'timeout'; source: DataSourcesListEntry; error: string };\n\n/** Poll the source list until its `hydration` clears, fails, or the timeout elapses. */\nexport async function waitForHydration(\n ctx: AdminContext,\n params: WaitForHydrationParams,\n): Promise<WaitForHydrationResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const outcome = await pollUntil(\n async () => {\n const { dataSources } = await listSources(ctx);\n const source = dataSources.find((s) => s.slug === params.slug);\n if (!source) {\n throw new Error(`Data source \"${params.slug}\" not found.`);\n }\n return source;\n },\n (source) => !source.hydration || source.hydration.error !== null,\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (source, start) =>\n renderProgress(source.hydration!.progress, start),\n // A reload of any size is waited out while it moves; the timeout\n // bounds silence.\n progressKey: (source) => source.hydration?.copied ?? null,\n onProgress: params.onProgress,\n },\n );\n const source = outcome.value;\n const hydration = source.hydration;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n source,\n error: timedOut(\n timeoutMs,\n `with ${hydration!.copied}/${hydration!.total} documents loaded`,\n ),\n };\n }\n if (hydration?.error) {\n return { status: 'failed', source, error: hydration.error };\n }\n return { status: 'done', source };\n}\n\n// ─── sample ──────────────────────────────────────────────────────────────────\n\nexport interface SampleParams {\n /** The source to draw from. */\n slug: string;\n /** Documents to draw (at most 2,000). */\n size: number;\n /** Slug for the sample; default `<slug>-sample`. */\n as?: string;\n /** Scope the draw: metadata equality, or the full document selector. */\n filter?: Record<string, unknown>;\n /** Metadata key to stratify on, proportional per value. */\n stratify?: string;\n placement?: { resourceId: string } | 'shared';\n}\n\n/**\n * Draw a sample of a source into a new source with the same pinned config.\n * The copy is a job (auto-approved; extraction is reused by content hash, so\n * the plan is chunk + embed only). Documents keep their content hashes, which\n * is what lets an eval set built on the sample score the parent too.\n *\n * @throws AdminApiError `invalid_size` (400), `slug_in_use` (422),\n * `data_source_limit` (422), `data_source_busy` (422).\n */\nexport function sample(ctx: AdminContext, params: SampleParams) {\n const { slug, size, as, filter, stratify, placement } = params;\n return call<DataSourcesSampleResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/sample`,\n {\n slug,\n size,\n ...(as ? { as } : {}),\n ...(filter ? { filter } : {}),\n ...(stratify ? { stratify } : {}),\n ...(placement !== undefined ? { placement } : {}),\n },\n );\n}\n\n// ─── query sets ──────────────────────────────────────────────────────────────\n\nexport interface CreateSetParams {\n slug: string;\n /** Lowercase [a-z0-9_-], unique per source. */\n name: string;\n description?: string;\n /** Queries to generate from the corpus; 0 (default) makes an empty set to add to. */\n size?: number;\n /** `cloze` (default, free) or `question` (a chat model writes them). */\n style?: EvalQueryStyle;\n /** Chat model for `question`; default the source's contextual model or the platform's. */\n modelId?: string;\n tags?: string[];\n /** Makes generation reproducible; default the current time. */\n seed?: number;\n}\n\n/**\n * Create a query set, generating queries from the corpus when `size` is set.\n * Generation runs in the background; the set is `generating` until it is\n * `ready` (see `waitForSet`).\n *\n * @throws AdminApiError `eval_set_exists` (422), `invalid_name` (400).\n */\nexport function createSet(ctx: AdminContext, params: CreateSetParams) {\n const { slug, name, description, size, style, modelId, tags, seed } = params;\n return call<EvalSetResult>(ctx, 'POST', `${base(ctx.appId)}/eval/sets`, {\n slug,\n name,\n ...(description ? { description } : {}),\n ...(size !== undefined ? { size } : {}),\n ...(style ? { style } : {}),\n ...(modelId ? { modelId } : {}),\n ...(tags?.length ? { tags } : {}),\n ...(seed !== undefined ? { seed } : {}),\n });\n}\n\nexport function listSets(ctx: AdminContext, params?: { slug?: string }) {\n return call<EvalSetsListResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/eval/sets${qs({ slug: params?.slug })}`,\n );\n}\n\nexport function getSet(\n ctx: AdminContext,\n params: { id: string; queries?: boolean },\n) {\n return call<EvalSetGetResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/eval/sets/${encodeURIComponent(params.id)}${qs({\n queries: params.queries ? 'true' : undefined,\n })}`,\n );\n}\n\nexport function deleteSet(ctx: AdminContext, params: { id: string }) {\n return call<{ deleted: true; set: EvalSet }>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/eval/sets/${encodeURIComponent(params.id)}/delete`,\n );\n}\n\nexport interface QueryInput {\n query: string;\n /** Which documents should come back; each reference must exist on the set's source. */\n expect: {\n documentIds?: string[];\n filenames?: string[];\n externalIds?: string[];\n contentHashes?: string[];\n };\n passage?: string;\n tags?: string[];\n}\n\n/**\n * Add hand-written queries (≤ 500 per call). Every reference is resolved\n * before anything is written; an unknown filename refuses the whole call by\n * name (`expected_document_not_found`).\n */\nexport function addQueries(\n ctx: AdminContext,\n params: { id: string; queries: QueryInput[] },\n) {\n return call<EvalQueriesAddResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/eval/sets/${encodeURIComponent(params.id)}/queries`,\n { queries: params.queries },\n );\n}\n\nexport function listQueries(ctx: AdminContext, params: { id: string }) {\n return call<EvalQueriesListResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/eval/sets/${encodeURIComponent(params.id)}/queries`,\n );\n}\n\nexport function deleteQuery(\n ctx: AdminContext,\n params: { id: string; queryId: string },\n) {\n return call<{ deleted: string; queryCount: number }>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/eval/sets/${encodeURIComponent(params.id)}/queries/delete`,\n { queryId: params.queryId },\n );\n}\n\n// ─── runs ────────────────────────────────────────────────────────────────────\n\nexport interface RunParams {\n setId: string;\n /** Target source; default the set's own. Expectations resolve by content hash. */\n slug?: string;\n /** Evaluate the target's candidate version instead of the active one. */\n candidate?: boolean;\n label?: string;\n retrieval?: EvalRetrieval;\n}\n\n/**\n * Score a set against a target. Runs in the background; block with\n * `waitForRun`. Each query is a real search (embedding + rerank spend).\n *\n * @throws AdminApiError `eval_set_not_ready` (422), `eval_set_empty` (422),\n * `no_candidate_pipeline` (404), `invalid_retrieval` (400).\n */\nexport function run(ctx: AdminContext, params: RunParams) {\n const { setId, slug, candidate, label, retrieval } = params;\n return call<EvalRunResult>(ctx, 'POST', `${base(ctx.appId)}/eval/runs`, {\n setId,\n ...(slug ? { slug } : {}),\n ...(candidate ? { candidate: true } : {}),\n ...(label ? { label } : {}),\n ...(retrieval && Object.keys(retrieval).length ? { retrieval } : {}),\n });\n}\n\nexport function listRuns(\n ctx: AdminContext,\n params?: { setId?: string; slug?: string },\n) {\n return call<EvalRunsListResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/eval/runs${qs({ setId: params?.setId, slug: params?.slug })}`,\n );\n}\n\nexport function getRun(\n ctx: AdminContext,\n params: { id: string; queries?: boolean; worst?: number },\n) {\n return call<EvalRunResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/eval/runs/${encodeURIComponent(params.id)}${qs({\n queries: params.queries ? 'true' : undefined,\n worst: params.worst,\n })}`,\n );\n}\n\n/** Two runs side by side: aggregate deltas, and per-query wins/losses when they share a set. */\nexport function compare(ctx: AdminContext, params: { a: string; b: string }) {\n return call<EvalCompareResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/eval/runs/compare${qs({ a: params.a, b: params.b })}`,\n );\n}\n\n// ─── waits ───────────────────────────────────────────────────────────────────\n\nexport interface WaitParams {\n id: string;\n timeoutMs?: number;\n onProgress?: (message: string) => void;\n}\n\nexport type WaitForRunResult =\n | { status: 'done'; run: EvalRun }\n | { status: 'failed'; run: EvalRun; error: string }\n | { status: 'timeout'; run: EvalRun; error: string };\n\nexport async function waitForRun(\n ctx: AdminContext,\n params: WaitParams,\n): Promise<WaitForRunResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const outcome = await pollUntil(\n async () => (await getRun(ctx, { id: params.id })).run,\n (run) => run.state === 'done' || run.state === 'failed',\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (run, start) =>\n `${run.state}… ${run.completed}/${run.total} queries (${elapsedSeconds(start)}s)`,\n onProgress: params.onProgress,\n },\n );\n const run = outcome.value;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n run,\n error: timedOut(\n timeoutMs,\n `; run is ${run.state} (${run.completed}/${run.total})`,\n ),\n };\n }\n if (run.state === 'failed') {\n return { status: 'failed', run, error: run.error ?? 'The run failed.' };\n }\n return { status: 'done', run };\n}\n\nexport type WaitForSetResult =\n | { status: 'done'; set: EvalSet }\n | { status: 'failed'; set: EvalSet; error: string }\n | { status: 'timeout'; set: EvalSet; error: string };\n\n/** Poll until generation lands (`ready`) or fails; a set waits `queued` for a worker first. */\nexport async function waitForSet(\n ctx: AdminContext,\n params: WaitParams,\n): Promise<WaitForSetResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const outcome = await pollUntil(\n async () => (await getSet(ctx, { id: params.id })).set,\n (set) => set.state === 'ready' || set.state === 'failed',\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (set, start) => `${set.state}… (${elapsedSeconds(start)}s)`,\n onProgress: params.onProgress,\n },\n );\n const set = outcome.value;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n set,\n error: timedOut(timeoutMs, `; set is still ${set.state}`),\n };\n }\n if (set.state === 'failed') {\n return { status: 'failed', set, error: set.error ?? 'Generation failed.' };\n }\n return { status: 'done', set };\n}\n","/**\n * Data-source mappers: the loop around customer code that turns raw objects\n * into documents — inspect the objects, test the mapper, make a build's mapper\n * the source's active one, remap after a fix, read and replay what a job\n * quarantined.\n *\n * Ops are pure (ctx, params) → typed result. The CLI skin in\n * commands/dataSourceMappers.ts owns flags, progress and exit codes.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport type {\n DataSourceInspectResult,\n DataSourceMapDeployResult,\n DataSourceMapTestResult,\n DataSourceQuarantineResult,\n DataSourceRemapResult,\n} from '../types/dataSourceMappers.js';\n\nfunction base(appId: string): string {\n return `/_internal/v2/apps/${appId}/datasources`;\n}\n\n/** Which objects to look at: a prefix of an app file store, or the connected bucket. */\nexport type ObjectSelection =\n | { store: string; access?: 'private' | 'public'; prefix?: string }\n | { connector: true };\n\nfunction selectionBody(selection: ObjectSelection): Record<string, unknown> {\n if ('connector' in selection) {\n return { connector: true };\n }\n return {\n store: selection.store,\n ...(selection.access ? { access: selection.access } : {}),\n ...(selection.prefix !== undefined ? { prefix: selection.prefix } : {}),\n };\n}\n\n// ─── inspect ─────────────────────────────────────────────────────────────────\n\nexport interface InspectParams {\n /** Required for a connector selection; optional for a store. */\n slug?: string;\n selection: ObjectSelection;\n /** Only these keys. */\n keys?: string[];\n /** Objects to list (default 5,000, max 50,000). */\n limit?: number;\n}\n\n/**\n * Profile raw objects before writing a mapper: counts and bytes by extension\n * and by key shape, size buckets, and ten sampled heads with their JSON key\n * signatures. Read-only.\n *\n * @throws AdminApiError `invalid_source` (400), `connector_not_found` (422).\n */\nexport function inspect(ctx: AdminContext, params: InspectParams) {\n return call<DataSourceInspectResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/inspect`,\n {\n ...(params.slug ? { slug: params.slug } : {}),\n ...selectionBody(params.selection),\n ...(params.keys ? { keys: params.keys } : {}),\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n },\n );\n}\n\n// ─── map test ────────────────────────────────────────────────────────────────\n\nexport interface MapTestParams {\n slug: string;\n selection: ObjectSelection;\n keys?: string[];\n /** Objects to map (default 20, max 200). */\n limit?: number;\n /** Run the LOCAL mapper through the app's dev session instead of the live bundle. */\n dev?: boolean;\n /**\n * With `dev`, which of your dev sessions: its dev release id. Default your\n * newest. Only ever your own.\n */\n releaseId?: string;\n}\n\n/**\n * Run the source's mapper over real objects and return the outcomes — nothing\n * is ingested. With `dev` the mapper runs from local source through the\n * running dev session, which is how a mapper is checked before a deploy.\n *\n * @throws AdminApiError `no_mapper` (422), `no_dev_session` (422),\n * `invalid_source` (400).\n */\nexport function mapTest(ctx: AdminContext, params: MapTestParams) {\n return call<DataSourceMapTestResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/map-test`,\n {\n slug: params.slug,\n ...selectionBody(params.selection),\n ...(params.keys ? { keys: params.keys } : {}),\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n ...(params.dev ? { dev: true } : {}),\n ...(params.releaseId ? { releaseId: params.releaseId } : {}),\n },\n );\n}\n\n// ─── remap ───────────────────────────────────────────────────────────────────\n\nexport interface RemapParams {\n slug: string;\n /** Pause when estimated spend reaches this; default the plan's headroom. */\n budgetDollars?: number;\n /** Only the first N raw objects. */\n limit?: number;\n}\n\n// ─── deploy ──────────────────────────────────────────────────────────────────\n\nexport interface MapDeployParams {\n slug: string;\n /**\n * The release to take the mapper from. Default: the newest built release —\n * live or the head of any branch — that carries a compiled mapper for the\n * slug.\n */\n releaseId?: string;\n}\n\n/**\n * Make a built release's compiled mapper the source's active mapper — what\n * jobs, syncs and `add()` run from now on. A branch build is enough: the app\n * need never have been published. Publishing to main also activates the\n * mapper main declares. Idempotent (`changed: false` when already active).\n *\n * @throws AdminApiError `no_built_mapper` (422) when no build carries a\n * compiled mapper for the slug, `release_not_found` (404).\n */\nexport function mapDeploy(ctx: AdminContext, params: MapDeployParams) {\n return call<DataSourceMapDeployResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/mapper/deploy`,\n {\n slug: params.slug,\n ...(params.releaseId ? { releaseId: params.releaseId } : {}),\n },\n );\n}\n\n/**\n * Run the active mapper over every raw object the source holds a copy of.\n * Auto-approved: unchanged markdown is skipped by hash, so a remap after a\n * metadata tweak costs frames and little else. Block on the job with\n * `dataSourceJobs.waitForJob`.\n *\n * @throws AdminApiError `no_mapper` (422), `nothing_to_remap` (422),\n * `data_source_busy` (422).\n */\nexport function remap(ctx: AdminContext, params: RemapParams) {\n return call<DataSourceRemapResult>(ctx, 'POST', `${base(ctx.appId)}/remap`, {\n slug: params.slug,\n ...(params.budgetDollars !== undefined\n ? { budgetDollars: params.budgetDollars }\n : {}),\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n });\n}\n\n// ─── quarantine + replay ─────────────────────────────────────────────────────\n\nexport interface QuarantineParams {\n id: string;\n kind?: 'skip' | 'error';\n /** Only the mapper's (`map`) or only the reader's (`read`). */\n stage?: 'map' | 'read';\n /** Only objects quarantined with exactly this reason. */\n reason?: string;\n cursor?: string;\n /** Page size (default 100, max 1,000). */\n limit?: number;\n}\n\n/**\n * What a job's mapper skipped or failed on, and what its reader failed on:\n * counts, reasons by frequency, and a page of objects.\n *\n * @throws AdminApiError `job_not_found` (404).\n */\nexport function quarantine(ctx: AdminContext, params: QuarantineParams) {\n return call<DataSourceQuarantineResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/jobs/${params.id}/quarantine${qs({\n ...(params.kind ? { kind: params.kind } : {}),\n ...(params.stage ? { stage: params.stage } : {}),\n ...(params.reason ? { reason: params.reason } : {}),\n ...(params.cursor ? { cursor: params.cursor } : {}),\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n })}`,\n );\n}\n\nexport interface ReplayParams {\n id: string;\n kind?: 'skip' | 'error';\n}\n\n/**\n * Run a job's quarantined objects through the current mapper, from their raw\n * copies. Starts a job; block on it with `dataSourceJobs.waitForJob`.\n *\n * @throws AdminApiError `nothing_to_replay` (422), `no_mapper` (422),\n * `data_source_busy` (422).\n */\nexport function replay(ctx: AdminContext, params: ReplayParams) {\n return call<DataSourceRemapResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/jobs/${params.id}/replay`,\n params.kind ? { kind: params.kind } : {},\n );\n}\n","/**\n * Database query operations.\n *\n * Ops are pure (ctx, sql) → typed result; the CLI skin in commands/db.ts\n * owns SQL assembly (the raw-spec mode, the tables introspection query) and\n * all output.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call } from '../http.js';\nimport type { DbQueryResult } from '../types/db.js';\n\n/**\n * Execute one SQL statement against the app's live-release database.\n *\n * The statement is passed verbatim — no parsing or rewriting. Both read\n * (`SELECT`) and write (`INSERT`, `UPDATE`, `DELETE`) statements are\n * accepted. The `results` array always has exactly one element for a single\n * statement; `changes` is 0 for SELECT.\n *\n * A statement the database refuses (a syntax error, a constraint, a result\n * too large) throws with `errorString: 'sql_error'`, and the body's\n * `errorMessage` is the database's own message.\n *\n * @param sql The SQL statement to execute.\n * @throws AdminApiError `no_live_release` (404) — the app has not been\n * deployed; `no_database` (404) — the live release has no database;\n * `invalid_request` (400) — `queries[]` missing or malformed;\n * `sql_error` (400) — the database refused the statement.\n * @example\n * const { results } = await admin.db.query('SELECT * FROM users LIMIT 10');\n */\nexport function query(ctx: AdminContext, sql: string) {\n return call<DbQueryResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/db/query`,\n { queries: [{ sql }] },\n );\n}\n","/**\n * Diagnostics operations: live-release id resolution (delegates to\n * ops/releases.ts to avoid duplicating the dashboard call), release diagnostics\n * fetch, and raw Lighthouse report download.\n *\n * Ops are pure: (ctx, params) → typed result. No printing, no process coupling.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, fetchWithTimeout, REPORT_TIMEOUT_MS, seg } from '../http.js';\nimport { dashboardLive } from './releases.js';\nimport type { DiagnosticsReleaseResult } from '../types/diagnostics.js';\n\n/**\n * Resolve the id of the currently-live release, or null if the app has not\n * been published. Delegates to the releases dashboardLive op to avoid\n * duplicating the dashboard endpoint call.\n *\n * @example\n * const releaseId = await admin.diagnostics.getLiveReleaseId();\n */\nexport async function getLiveReleaseId(\n ctx: AdminContext,\n): Promise<string | null> {\n const live = await dashboardLive(ctx);\n return live?.id ?? null;\n}\n\n/**\n * Fetch a release by id, including its Lighthouse diagnostics payload.\n *\n * `diagnostics` is null when the audit has not yet landed (~30–60s after\n * go-live). The `lighthouseJsonUrl` inside `diagnostics` is a short-lived\n * signed GET URL re-minted on each call — do not cache the URL.\n *\n * @param releaseId The release id to fetch (e.g. from `getLiveReleaseId`).\n * @throws AdminApiError `release_not_found` (404) — the release id does not\n * exist or belongs to a different app.\n * @example\n * const { diagnostics } = await admin.diagnostics.getRelease('rel_abc123');\n */\nexport function getRelease(ctx: AdminContext, releaseId: string) {\n return call<DiagnosticsReleaseResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/releases/${seg(releaseId)}`,\n );\n}\n\n/**\n * Fetch the raw Lighthouse JSON report from its signed URL. Uses\n * REPORT_TIMEOUT_MS since the report is a large artifact pulled from object\n * storage.\n *\n * @param url The short-lived signed URL from `diagnostics.lighthouseJsonUrl`.\n * @example\n * const report = await admin.diagnostics.fetchReport(url);\n */\nexport async function fetchReport(url: string): Promise<unknown> {\n const res = await fetchWithTimeout(\n url,\n {},\n REPORT_TIMEOUT_MS,\n 'Lighthouse report fetch',\n );\n if (!res.ok) {\n throw new Error(`Failed to fetch Lighthouse report: HTTP ${res.status}`);\n }\n return res.json();\n}\n","/**\n * Release operations: list, get, by-commit, dashboard live-release, and the\n * composite waitForCommit op that owns the two poll loops.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError (or a plain Error for application-level failures such as\n * an unexpected non-404 during commit resolve). No printing, no process\n * coupling — the CLI skin in commands/releases.ts and the importable client\n * both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, tryCall, qs, seg } from '../http.js';\nimport { sleep } from '../sleep.js';\nimport type {\n ReleasesListResult,\n ReleasesGetResult,\n ReleasesByCommitResult,\n DashboardResult,\n DashboardLiveRelease,\n V2ReleaseStatus,\n} from '../types/releases.js';\n\nexport interface ReleasesListParams {\n /** Max releases to return per page (default 20, clamped 1–100). */\n limit?: number;\n}\n\n/**\n * Paginated list of releases, newest first (non-dev only).\n *\n * Returns up to `limit` releases. `nextCursor` in the response is non-null\n * when further pages exist; pass it as a raw query parameter to walk all pages.\n *\n * @example\n * const { releases } = await admin.releases.list({ limit: 50 });\n */\nexport function list(ctx: AdminContext, params: ReleasesListParams = {}) {\n return call<ReleasesListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/releases${qs({ limit: params.limit })}`,\n );\n}\n\n/**\n * Full detail for a single release by id.\n *\n * Includes build log, methods, interfaces, databases, a short-lived signed\n * commit-diff URL, a signed Lighthouse diagnostics URL, and the async\n * post-deploy progress state.\n *\n * @throws AdminApiError `release_not_found` (404) — no release with that id exists on this app.\n * @example\n * const release = await admin.releases.get('rel_abc123');\n * console.log(release.status, release.buildDurationMs);\n */\nexport function get(ctx: AdminContext, releaseId: string) {\n return call<ReleasesGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/releases/${seg(releaseId)}`,\n );\n}\n\n/**\n * By-commit lookup. Returns the raw tryCall result so callers can tolerate\n * 404s during the resolve-grace window (used internally by waitForCommit and\n * exposed for programmatic callers that want a one-shot lookup).\n *\n * HTTP errors arrive as `{ ok: false, status, body }` rather than thrown —\n * the API returns `invalid_commit_sha` (400) for non-hex input and\n * `release_not_found` (404) when the commit has no release yet.\n *\n * @example\n * const r = await admin.releases.byCommit('91ca67a');\n * if (r.ok) console.log(r.body.status);\n */\nexport function byCommit(\n ctx: AdminContext,\n commitSha: string,\n): Promise<{ ok: boolean; status: number; body: ReleasesByCommitResult }> {\n return tryCall<ReleasesByCommitResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/releases/by-commit/${seg(commitSha)}`,\n );\n}\n\n/**\n * The currently-live release, or null when the app has never been published.\n * Fetched from the dashboard endpoint — same source as `releases current`.\n *\n * @example\n * const live = await admin.releases.dashboardLive();\n * if (live) console.log(live.commitSha, live.publishedAt);\n */\nexport async function dashboardLive(\n ctx: AdminContext,\n): Promise<DashboardLiveRelease | null> {\n const dashboard = await call<DashboardResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/dashboard`,\n );\n return dashboard.liveRelease;\n}\n\n// ---- waitForCommit internals ----\n\n/**\n * Compact, stable projection of a release for the wait result.\n *\n * `previewUrl` is present for a feature-branch build (status 'preview') and is\n * where that build is actually reachable — gated to anyone who can open the app\n * in Remy. Reported as data rather than taught as a URL shape, so the caller\n * never has to construct one.\n */\nexport interface ReleaseSummary {\n releaseId: string;\n commitSha: string;\n branch: string | null;\n status: V2ReleaseStatus;\n buildDurationMs: number | null;\n publishedAt: string | null;\n previewUrl?: string;\n /** Why it failed; only present when status is `failed`. */\n error?: string;\n /**\n * Only present when status is `failed`. 'interrupted' means a platform\n * restart killed the build and a retry is already running — not a code\n * problem. See ReleaseFailureFields.\n */\n failureKind?: 'build' | 'interrupted' | 'unbuildable';\n /** Build stage that was running when it failed; only when `failed`. */\n failurePhase?: string;\n /**\n * Each data source whose reader this live release brought live, with the\n * documents it hasn't read: what `datasources reread --unread` reads, priced\n * first. Absent when the release declares no reader.\n */\n readers?: { slug: string; unread: number }[];\n}\n\nfunction summarizeRelease(release: ReleasesByCommitResult): ReleaseSummary {\n const summary: ReleaseSummary = {\n releaseId: release.id,\n commitSha: release.commitSha,\n branch: release.branch ?? null,\n status: release.status,\n buildDurationMs: release.buildDurationMs ?? null,\n publishedAt: release.publishedAt ?? null,\n ...(release.previewUrl ? { previewUrl: release.previewUrl } : {}),\n };\n const readers = (release.dataSources ?? []).filter((d) => d.reader);\n if (readers.length > 0 && release.status === 'live') {\n summary.readers = readers.map((d) => ({\n slug: d.slug,\n unread: d.readerUnread ?? 0,\n }));\n }\n if (release.status !== 'failed') {\n return summary;\n }\n return {\n ...summary,\n error:\n release.failureReason ?? 'Build failed (no error entry in the build log)',\n ...(release.failureKind ? { failureKind: release.failureKind } : {}),\n ...(release.failurePhase ? { failurePhase: release.failurePhase } : {}),\n };\n}\n\n/**\n * Terminal outcome of a `waitForCommit` call.\n *\n * `live` — deployed to the default branch; the app is live.\n * `preview` — feature-branch build finished; `summary.previewUrl` is set.\n * `failed` — build error; `summary.error` carries the reason.\n * `superseded` — a newer commit for this app finished first.\n * `timeout` — timed out before a terminal status; `summary` has the last-known state.\n * `not_found` — no release registered within the 30s resolve grace.\n */\nexport type WaitOutcome =\n 'live' | 'preview' | 'failed' | 'superseded' | 'timeout' | 'not_found';\n\nexport interface WaitForCommitResult {\n /** Terminal outcome; determines which other fields are populated. */\n outcome: WaitOutcome;\n /** Raw release row at the time of resolution; absent for `not_found`. */\n release?: ReleasesByCommitResult;\n /** The summarizeRelease projection; absent for `not_found`. */\n summary?: ReleaseSummary;\n /**\n * Error message string for `not_found` and `timeout` outcomes. The CLI skin\n * incorporates this into the printable output object. For `failed`, the error\n * is already baked into `summary.error` by summarizeRelease.\n */\n error?: string;\n}\n\nexport interface WaitForCommitParams {\n /** Full or abbreviated (7–40 hex char) git commit SHA; the API matches by prefix. */\n commitSha: string;\n /** Defaults to 300 000 ms (5 min), matching the CLI's --timeout 300 default. */\n timeoutMs?: number;\n /**\n * Called with the exact progress strings the CLI prints via progress():\n * `waiting for release to be created for ${shortSha}…`\n * `${status}… (Ns)`\n */\n onProgress?: (message: string) => void;\n}\n\nconst POLL_MS = 3_000;\nconst RESOLVE_GRACE_MS = 30_000;\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\n/**\n * Wait for the release built from a git commit to reach a terminal state.\n *\n * The \"publish and wait until live\" primitive. Phase 1 resolves the release\n * row by commit SHA, tolerating 404s for up to 30s — a SHA polled immediately\n * after `git push` will briefly 404 while the receive-pack hook registers it,\n * and that is expected. Phase 2 polls every 3s until the release reaches a\n * terminal status or the timeout expires.\n *\n * Possible outcomes:\n * `live` — default-branch deploy succeeded; the app is live.\n * `preview` — feature-branch build finished; `summary.previewUrl` is the gated URL.\n * `failed` — build failed; `summary.error` carries the last build-log error entry.\n * `superseded` — a newer commit finished first and this build was skipped.\n * `timeout` — `timeoutMs` elapsed before a terminal status; `summary` has the last-known state.\n * `not_found` — no release created within the 30s resolve grace; the push may not have\n * registered yet, or this SHA never produced a build.\n *\n * `onProgress` is called with a human-readable string on each poll cycle —\n * the exact strings the CLI skin passes to `progress()`, so callers can echo\n * them without reformatting.\n *\n * Throws a plain `Error` (not AdminApiError) only when Phase 1 encounters an\n * unexpected non-404 HTTP error (e.g. a 500 from the API).\n *\n * @example\n * const result = await admin.releases.waitForCommit({\n * commitSha: '91ca67a',\n * timeoutMs: 600_000,\n * onProgress: (msg) => console.error(msg),\n * });\n * if (result.outcome !== 'live' && result.outcome !== 'preview') {\n * throw new Error(result.error ?? result.outcome);\n * }\n */\nexport async function waitForCommit(\n ctx: AdminContext,\n params: WaitForCommitParams,\n): Promise<WaitForCommitResult> {\n const { commitSha, onProgress } = params;\n const timeoutMs = params.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const shortSha = commitSha.slice(0, 8);\n const start = Date.now();\n\n // Phase 1 — resolve the release for this commit.\n let release: ReleasesByCommitResult;\n while (true) {\n const r = await byCommit(ctx, commitSha);\n if (r.ok) {\n release = r.body;\n break;\n }\n if (r.status !== 404) {\n throw new Error(\n `Failed to resolve release for ${shortSha}: HTTP ${r.status} ${JSON.stringify(r.body)}`,\n );\n }\n if (Date.now() - start > RESOLVE_GRACE_MS) {\n return {\n outcome: 'not_found',\n error: `No release created for commit ${commitSha} within ${RESOLVE_GRACE_MS / 1000}s — either the push hasn't registered yet or this SHA never produced a build`,\n };\n }\n onProgress?.(`waiting for release to be created for ${shortSha}…`);\n await sleep(POLL_MS);\n }\n\n // Phase 2 — poll status until terminal.\n const SUCCESS = new Set<string>(['live', 'preview']);\n while (true) {\n if (SUCCESS.has(release.status)) {\n return {\n outcome: release.status as 'live' | 'preview',\n release,\n summary: summarizeRelease(release),\n };\n }\n if (release.status === 'failed') {\n return { outcome: 'failed', release, summary: summarizeRelease(release) };\n }\n if (release.status === 'superseded') {\n return {\n outcome: 'superseded',\n release,\n summary: summarizeRelease(release),\n };\n }\n if (Date.now() - start > timeoutMs) {\n return {\n outcome: 'timeout',\n release,\n summary: summarizeRelease(release),\n error: `Timed out after ${timeoutMs / 1000}s (last status: ${release.status})`,\n };\n }\n onProgress?.(\n `${release.status}… (${Math.round((Date.now() - start) / 1000)}s)`,\n );\n await sleep(POLL_MS);\n const r = await byCommit(ctx, commitSha);\n if (r.ok) {\n release = r.body;\n }\n // A transient non-ok keeps the last known release; the timeout guard above\n // still applies, so we don't loop forever on a persistent error.\n }\n}\n","/**\n * App domain operations: platform subdomain + custom hostnames.\n *\n * `findHostname` resolves a user-supplied hostname to its row id and full\n * entry (list → match → id). It throws a plain Error with the exact\n * \"not found\" message the CLI historically surfaced — the entry-point catch\n * prints `.message` identically whether it came from `fatal()` or here.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, seg } from '../http.js';\nimport type {\n DomainsCustomHostnameView,\n DomainsCustomListResult,\n DomainsCustomAddResult,\n DomainsCustomCheckResult,\n DomainsCustomRemoveResult,\n DomainsCustomRetryResult,\n DomainsGetResult,\n DomainsSetResult,\n DomainsCheckResult,\n} from '../types/domains.js';\n\n/**\n * Get the app's current platform subdomain (e.g. `my-app.madewithremy.com`).\n *\n * Returns `{ subdomain: null }` when none is set.\n *\n * @example\n * const { subdomain } = await admin.domains.get();\n */\nexport function get(ctx: AdminContext) {\n return call<DomainsGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-subdomain`,\n );\n}\n\n/**\n * Set the app's platform subdomain.\n *\n * @param subdomain The desired subdomain (hyphenated, no suffix).\n * @example\n * await admin.domains.set('my-app');\n */\nexport function set(ctx: AdminContext, subdomain: string) {\n return call<DomainsSetResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-subdomain`,\n { subdomain },\n );\n}\n\n/**\n * Check whether a platform subdomain is available before calling `set`.\n *\n * @example\n * const { isAvailable } = await admin.domains.check('my-app');\n */\nexport function check(ctx: AdminContext, subdomain: string) {\n return call<DomainsCheckResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-subdomain/check-availability`,\n { subdomain },\n );\n}\n\n/**\n * List all custom hostnames registered on the app.\n *\n * Results come from a Cloudflare-synced cache that can be up to ~5 minutes\n * stale. Use `customRetry` to force a synchronous re-check after the customer\n * adds DNS records. `uiStatus` values: `waiting_for_dns | issuing_ssl | live |\n * action_needed | reconnecting`.\n *\n * @example\n * const { hostnames } = await admin.domains.customList();\n * const live = hostnames.filter((h) => h.uiStatus === 'live');\n */\nexport function customList(ctx: AdminContext) {\n return call<DomainsCustomListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-domains`,\n );\n}\n\n/**\n * Register a custom hostname on the app.\n *\n * Apex input (e.g. `acme.com`) auto-creates the `www.acme.com` pair and\n * returns both entries. `dnsInstructions` on each returned entry contains\n * the DNS records the customer must add to their provider.\n *\n * @throws AdminApiError `invalid_hostname` (400) — the hostname failed format\n * validation; `hostname_in_use` (400) — the hostname (or its auto-paired\n * www) is already registered on any app.\n * @example\n * const { hostnames } = await admin.domains.customAdd('acme.com');\n * // hostnames[0] = apex row, hostnames[1] = www pair\n */\nexport function customAdd(ctx: AdminContext, hostname: string) {\n return call<DomainsCustomAddResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-domains`,\n { hostname },\n );\n}\n\n/**\n * Preflight a hostname before registering: validates format, checks\n * availability, and signals whether an apex would auto-pair www.\n *\n * Never throws — invalid input returns `{ valid: false, errorMessage }`.\n *\n * @example\n * const { valid, willAutoPairWww } = await admin.domains.customCheck('acme.com');\n */\nexport function customCheck(ctx: AdminContext, hostname: string) {\n return call<DomainsCustomCheckResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-domains/check-domain`,\n { hostname },\n );\n}\n\n/**\n * Resolve a hostname entry by name: lists all hostnames and matches on the\n * canonical lowercase hostname, returning the row id and full entry.\n *\n * @throws Error `No custom domain \"${hostname}\" found on this app` when the\n * hostname is not registered.\n * @example\n * const { id, entry } = await admin.domains.findHostname('app.acme.com');\n */\nexport async function findHostname(\n ctx: AdminContext,\n hostname: string,\n): Promise<{ id: string; entry: DomainsCustomHostnameView }> {\n const wanted = hostname.toLowerCase();\n const res = await customList(ctx);\n const entry = (res.hostnames ?? []).find(\n (h) => typeof h.hostname === 'string' && h.hostname === wanted,\n );\n if (!entry) {\n throw new Error(`No custom domain \"${hostname}\" found on this app`);\n }\n return { id: entry.id, entry };\n}\n\n/**\n * Remove a custom hostname from the app.\n *\n * Apex hostnames also remove their paired `www.` entry. The hostname is\n * resolved internally via `findHostname` before the delete call.\n *\n * @throws Error `No custom domain \"${hostname}\" found on this app` when not\n * registered; AdminApiError `not_found` (404) if the resolved id has gone\n * stale.\n * @example\n * await admin.domains.customRemove('acme.com');\n */\nexport async function customRemove(ctx: AdminContext, hostname: string) {\n const { id } = await findHostname(ctx, hostname);\n return call<DomainsCustomRemoveResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-domains/${seg(id)}/delete`,\n );\n}\n\n/**\n * Re-trigger Cloudflare validation for a hostname, typically after the\n * customer has updated their DNS records.\n *\n * @throws Error `No custom domain \"${hostname}\" found on this app` when not\n * registered; AdminApiError `not_found` (404) if the resolved id has gone\n * stale; `no_cf_id` (400) — the hostname was never registered with\n * Cloudflare and cannot be retried.\n * @example\n * const { hostname: updated } = await admin.domains.customRetry('app.acme.com');\n */\nexport async function customRetry(ctx: AdminContext, hostname: string) {\n const { id } = await findHostname(ctx, hostname);\n return call<DomainsCustomRetryResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-domains/${seg(id)}/retry`,\n );\n}\n","/**\n * Email operations: outbound delivery log, blast stats, suppression list,\n * inbound inbox, and custom domain management (both directions).\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/email.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n EmailBatchResult,\n EmailBatchesResult,\n EmailDomainBase,\n EmailInboxResult,\n EmailListResult,\n EmailMessageResult,\n EmailSendingStatusResult,\n EmailStatsResult,\n EmailSuppressResult,\n EmailSuppressionsResult,\n EmailUnsuppressResult,\n InboundEmailDomainAddResult,\n InboundEmailDomainCheckResult,\n InboundEmailDomainDeleteResult,\n InboundEmailDomainVerifyResult,\n InboundEmailDomainsListResult,\n OutboundEmailDomainAddResult,\n OutboundEmailDomainCheckResult,\n OutboundEmailDomainDeleteResult,\n OutboundEmailDomainVerifyResult,\n OutboundEmailDomainsListResult,\n} from '../types/email.js';\n\n// ---------------------------------------------------------------------------\n// Param interfaces\n// ---------------------------------------------------------------------------\n\nexport interface EmailListParams {\n /**\n * Comma-separated statuses to include. Values: `suppressed`, `failed`,\n * `sent`, `delivered`, `blocked`, `bounced`, `complained`, `delayed`,\n * `rejected`. Default: all statuses. `blocked` means an SES suppression list\n * dropped the message before delivery — usually this app's OWN tenant list\n * (a prior hard bounce or spam report from that address), occasionally the\n * shared account-wide list. `unsuppress` reports which.\n */\n status?: string;\n /** Origin to filter by: `method` (app-sent) or `auth` (sign-in codes). Default: all. */\n kind?: string;\n /**\n * Exact-match recipient address (index-backed, fast). Use `search` for\n * partial or substring matches instead.\n */\n recipient?: string;\n /** Show only messages belonging to this blast / campaign batch id. */\n batchId?: string;\n /**\n * Substring search across subject and recipient address. Bounded; results\n * are not cursor-paginated.\n */\n search?: string;\n /** ISO date range start (inclusive). */\n start?: string;\n /** ISO date range end (inclusive). */\n end?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface EmailWindowParams {\n /** ISO date range start (inclusive). */\n start?: string;\n /** ISO date range end (inclusive). */\n end?: string;\n}\n\nexport interface EmailBatchesParams {\n /** ISO date range start (inclusive). */\n start?: string;\n /** ISO date range end (inclusive). */\n end?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface EmailSuppressionsParams {\n limit?: number;\n offset?: number;\n}\n\nexport interface EmailInboxParams {\n /** Filter by processing status: `success` or `error`. Default: all. */\n status?: string;\n /** Substring search across sender address and subject. */\n search?: string;\n /** ISO date range start (inclusive). */\n start?: string;\n /** ISO date range end (inclusive). */\n end?: string;\n /** Cursor from a previous response for pagination. */\n cursor?: string;\n limit?: number;\n}\n\n/** Direction of mail flow: `sending` = outbound (a domain at the email provider); `inbound` = receiving (MX). */\nexport type DomainDirection = 'sending' | 'inbound';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst DOMAIN_BASES: Record<DomainDirection, string> = {\n sending: 'outbound-email-domains',\n inbound: 'email-domains',\n};\n\nfunction domainsPath(ctx: AdminContext, direction: DomainDirection): string {\n return `/_internal/v2/apps/${ctx.appId}/settings/${DOMAIN_BASES[direction]}`;\n}\n\nasync function resolveDomainId(\n ctx: AdminContext,\n direction: DomainDirection,\n domain: string,\n): Promise<string> {\n const { domains } = await call<{ domains: EmailDomainBase[] }>(\n ctx,\n 'GET',\n domainsPath(ctx, direction),\n );\n const wanted = domain.trim().toLowerCase();\n const match = (domains ?? []).find(\n (d: { domain: string }) => d.domain.toLowerCase() === wanted,\n );\n if (!match) {\n const known = (domains ?? []).map((d: { domain: string }) => d.domain);\n throw new Error(\n `No ${direction} domain \"${domain}\" on this app.` +\n (known.length ? ` Registered: ${known.join(', ')}` : ''),\n );\n }\n return match.id;\n}\n\n// ---------------------------------------------------------------------------\n// Outbound message ops\n// ---------------------------------------------------------------------------\n\n/**\n * Sent messages for this app, including messages that never reached SES.\n *\n * The log covers every send attempt — suppressed, over-cap,\n * sender-not-allowed — because most real failures never touch the provider.\n * Status values: `suppressed` (app-level unsubscribe), `failed`, `sent`,\n * `delivered`, `blocked` (dropped by an SES suppression list — usually this\n * app's own tenant list after an earlier bounce or spam report from that\n * address), `bounced`, `complained`, `delayed`, `rejected`. Paginated via\n * cursor in the result or by offset.\n *\n * @example\n * const { messages } = await admin.email.list({ status: 'bounced,blocked', limit: 50 });\n */\nexport function list(ctx: AdminContext, params: EmailListParams = {}) {\n return call<EmailListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/messages${qs(params)}`,\n );\n}\n\n/**\n * Full detail for one outbound message, including bounce diagnostics.\n *\n * @throws AdminApiError `not_found` (404) — no message with that id on this app.\n * @example\n * const msg = await admin.email.get('msg_abc123');\n * console.log(msg.status, msg.diagnostic);\n */\nexport function get(ctx: AdminContext, messageId: string) {\n return call<EmailMessageResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/messages/${seg(messageId)}`,\n );\n}\n\n/**\n * Aggregate counts and delivery rates over a time window.\n *\n * `accepted` is the denominator for all rates (messages SES received);\n * `counts` includes pre-SES failures. `series` is a per-bucket time-series\n * for charting.\n *\n * @example\n * const { counts, rates } = await admin.email.stats({ start: '2026-01-01T00:00:00Z' });\n */\nexport function stats(ctx: AdminContext, params: EmailWindowParams = {}) {\n return call<EmailStatsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/summary${qs(params)}`,\n );\n}\n\n/**\n * Whether this app can send email right now, and up to what — the first thing\n * to check when \"it's not sending emails\".\n *\n * Reports four independent things: `sending` (the gate the send path itself\n * uses, so this and a `409 sending_paused` can never disagree), `enforcement`\n * (the platform's own throttle/pause and WHO applied it), `ses` (Amazon's view\n * of the app's tenant), and `quota` (the daily recipient limit, usage, and\n * where the limit came from).\n *\n * How to read a pause: `sending.source === 'ses'` means Amazon paused the\n * tenant on its own findings — nothing the app owner does lifts it directly;\n * it clears when the finding clears. `source === 'platform'` with\n * `enforcement.origin === 'platform'` is the automatic bounce/complaint sweep\n * and steps down on its own as rates recover; `origin === 'operator'` is a\n * human hold and will not. A throttle shows up as `enforcement.level:\n * 'throttled'` with the reduced `quota.limit` and its `expiresAt`.\n *\n * @example\n * const s = await admin.email.status();\n * if (!s.sending.allowed) console.log(s.sending.source, s.sending.reason);\n * console.log(`${s.quota.used}/${s.quota.limit ?? '∞'} recipients today`);\n */\nexport function status(ctx: AdminContext) {\n return call<EmailSendingStatusResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/status`,\n );\n}\n\n/**\n * One row per blast/campaign with per-status counts and, for queued sends,\n * the in-flight lifecycle.\n *\n * A marketing send delivers one message per recipient; many rows share a\n * `batchId` (set by the caller via `sendEmail`). `recipients` is the total\n * fan-out count including pre-SES failures; `accepted` is the SES-received\n * denominator used for rate calculations.\n *\n * Large or marketing sends are accepted immediately and delivered in chunks —\n * `status` (`accepted`/`sending`/`completed`/`partial`/`failed`), `chunksDone`/\n * `chunksTotal` and `pending` report the progress. `status: null` is a normal,\n * finished send delivered inline (or predating the queue), not an error.\n *\n * @example\n * const { batches } = await admin.email.batches({ limit: 20 });\n * const inFlight = batches.filter((b) => b.status === 'sending');\n */\nexport function batches(ctx: AdminContext, params: EmailBatchesParams = {}) {\n return call<EmailBatchesResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/batches${qs(params)}`,\n );\n}\n\n/**\n * Stats for a single blast identified by its batch id, including the queued\n * lifecycle (`status`, chunk progress, `pending`) when the send was queued.\n * A reused batch id reports its NEWEST run's lifecycle.\n *\n * @throws AdminApiError `not_found` (404) — no batch with that id on this app.\n * @example\n * const blast = await admin.email.batch('batch_xyz');\n * console.log(blast.status, blast.pending, blast.counts);\n */\nexport function batch(ctx: AdminContext, batchId: string) {\n return call<EmailBatchResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/batches/${seg(batchId)}`,\n );\n}\n\n/**\n * App-level suppression list (addresses that have opted out of this app's mail).\n *\n * @example\n * const { suppressions } = await admin.email.suppressions({ limit: 100 });\n */\nexport function suppressions(\n ctx: AdminContext,\n params: EmailSuppressionsParams = {},\n) {\n return call<EmailSuppressionsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/suppressions${qs(params)}`,\n );\n}\n\n/**\n * Add an address to this app's suppression list.\n *\n * @throws AdminApiError `invalid_email` (400) — the address is not a valid email.\n * @example\n * await admin.email.suppress('user@example.com');\n */\nexport function suppress(ctx: AdminContext, email: string) {\n return call<EmailSuppressResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/suppressions/add`,\n { email },\n );\n}\n\n/**\n * Remove an address from this app's suppression lists — the app-level\n * unsubscribe row AND the app's SES tenant suppression entry (a prior hard\n * bounce or spam report against this app), which is the one that actually\n * unblocks delivery.\n *\n * No `confirm` parameter here — the op is the deliberate act. The CLI skin\n * keeps the `--confirm` gate before calling this.\n *\n * Read the result, not just `ok`: `tenantEntryRemoved` true means a\n * provider-side bounce record was cleared and mail will be attempted again\n * (another bounce re-suppresses automatically); `platformSuppression` non-null\n * means the address is on SES's ACCOUNT-wide list — never cleared, shared by\n * every app — and this removal changed nothing about deliverability. The CLI\n * skin surfaces both advisories on stderr.\n *\n * @throws AdminApiError `invalid_email` (400) — the address is not a valid email.\n * @example\n * const result = await admin.email.unsuppress('user@example.com');\n * if (result.platformSuppression) console.warn('Still blocked account-wide.');\n */\nexport function unsuppress(ctx: AdminContext, email: string) {\n return call<EmailUnsuppressResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/suppressions/remove`,\n { email },\n );\n}\n\n/**\n * Inbound messages received by this app (sender/subject previews).\n *\n * An inbox row's `id` is its request-log id — open the full detail (parsed\n * message, method run, errors) with `requests.get(id)`. Cursor-paginated;\n * the next page token is in `EmailInboxResult.nextCursor`.\n *\n * @example\n * const { emails } = await admin.email.inbox({ status: 'error', limit: 20 });\n */\nexport function inbox(ctx: AdminContext, params: EmailInboxParams = {}) {\n return call<EmailInboxResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/inbox${qs(params)}`,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Domain ops (both directions via DomainDirection)\n//\n// Generic over the direction so a literal 'sending' / 'inbound' argument gets\n// the direction's concrete result type (the sending list carries\n// effectiveSender; the inbound one doesn't), while a runtime variable — the\n// CLI's spec-key factory passes one — still resolves to the union. The\n// implementation casts once: `call` can't know the conditional, but the path\n// selection and the conditional select on the same DomainDirection value.\n// ---------------------------------------------------------------------------\n\n/**\n * Direction-conditional result selector: maps a literal `DomainDirection` to\n * its concrete result type, or the union when the direction is a runtime variable.\n */\nexport type ForDirection<D extends DomainDirection, Sending, Inbound> = [\n D,\n] extends ['sending']\n ? Sending\n : [D] extends ['inbound']\n ? Inbound\n : Sending | Inbound;\n\n/**\n * All registered custom domains for a direction.\n *\n * Sending domains (`'sending'`) include `effectiveSender` — the address the\n * app currently sends from and its fallback tier (`app_domain` > `org_domain`\n * > `subdomain` > `default`). Inbound domains (`'inbound'`) list custom\n * receiving domains; apps already receive at `*@<slug>.madewithremy.com` with\n * no setup.\n *\n * @example\n * const { domains, effectiveSender } = await admin.email.listDomains('sending');\n */\nexport function listDomains<D extends DomainDirection>(\n ctx: AdminContext,\n direction: D,\n): Promise<\n ForDirection<D, OutboundEmailDomainsListResult, InboundEmailDomainsListResult>\n> {\n return call(ctx, 'GET', domainsPath(ctx, direction)) as Promise<\n ForDirection<\n D,\n OutboundEmailDomainsListResult,\n InboundEmailDomainsListResult\n >\n >;\n}\n\n/**\n * Pre-flight check: validate a domain name and confirm it is not already registered.\n *\n * For inbound domains, also returns `dnsInstructions` (the MX record) when\n * `valid` is true — the record is known before registration and can be given\n * to the user up front. Sending domain DKIM CNAMEs are only available after\n * `addDomain`. Returns `{ valid: false, errorMessage }` inline rather than\n * throwing for validation failures.\n *\n * @example\n * const { valid, dnsInstructions } = await admin.email.checkDomain('inbound', 'acme.com');\n */\nexport function checkDomain<D extends DomainDirection>(\n ctx: AdminContext,\n direction: D,\n domain: string,\n): Promise<\n ForDirection<D, OutboundEmailDomainCheckResult, InboundEmailDomainCheckResult>\n> {\n return call(ctx, 'POST', `${domainsPath(ctx, direction)}/check-domain`, {\n domain,\n }) as Promise<\n ForDirection<\n D,\n OutboundEmailDomainCheckResult,\n InboundEmailDomainCheckResult\n >\n >;\n}\n\n/**\n * Register a new custom domain in the given direction.\n *\n * **Sending (`'sending'`):** creates the domain at the email provider and\n * returns `dnsInstructions.records`, the DNS records to publish, each marked\n * required or not (on the cloud, three DKIM CNAMEs and a recommended SPF TXT).\n * Hand these to the user to create at their DNS host, then call `verifyDomain`\n * to re-check. Verification can take minutes after the records resolve;\n * `uiStatus` will be `pending` until then.\n *\n * **Inbound (`'inbound'`):** creates the domain row and returns\n * `dnsInstructions` with the MX record to add, plus an `ownershipTxt` record\n * when the domain was already aimed at the platform or held by another app\n * (it verifies only once both are published). Apps already receive at\n * `*@<slug>.madewithremy.com`; a custom inbound domain is optional.\n *\n * @throws AdminApiError `invalid_domain` (400) — not a valid registrable domain\n * name; `domain_in_use` (400) — already registered on any app;\n * `sending_domain_create_failed` (502, sending only) — the provider\n * couldn't create the domain; `sending_domains_unavailable` (400, sending\n * only) — the deployment sends from one address and takes no domains.\n * @example\n * const { domain } = await admin.email.addDomain('sending', 'mail.acme.com');\n * console.log(domain.dnsInstructions.records);\n */\nexport function addDomain<D extends DomainDirection>(\n ctx: AdminContext,\n direction: D,\n domain: string,\n): Promise<\n ForDirection<D, OutboundEmailDomainAddResult, InboundEmailDomainAddResult>\n> {\n return call(ctx, 'POST', domainsPath(ctx, direction), {\n domain,\n }) as Promise<\n ForDirection<D, OutboundEmailDomainAddResult, InboundEmailDomainAddResult>\n >;\n}\n\n/**\n * Force an immediate DNS check on a registered domain.\n *\n * Resolves the domain name to its row id via an extra GET, then calls the\n * `retry` endpoint. Use after adding DNS records to check earlier than the\n * background poller. `uiStatus` transitions from `pending` → `verified`, or\n * stays `action_needed` (check `verificationErrors`). Sending verification\n * that was never started expires after ~72h; fix the records and call\n * `verifyDomain` again.\n *\n * @throws Error if no domain matching `domain` is registered on this app\n * (thrown before the API call, not an AdminApiError).\n * @throws AdminApiError `not_found` (404) — the row was deleted between list and verify.\n * @example\n * const { domain } = await admin.email.verifyDomain('sending', 'mail.acme.com');\n * console.log(domain.uiStatus, domain.verificationErrors);\n */\nexport async function verifyDomain<D extends DomainDirection>(\n ctx: AdminContext,\n direction: D,\n domain: string,\n): Promise<\n ForDirection<\n D,\n OutboundEmailDomainVerifyResult,\n InboundEmailDomainVerifyResult\n >\n> {\n const id = await resolveDomainId(ctx, direction, domain);\n return call(\n ctx,\n 'POST',\n `${domainsPath(ctx, direction)}/${seg(id)}/retry`,\n ) as Promise<\n ForDirection<\n D,\n OutboundEmailDomainVerifyResult,\n InboundEmailDomainVerifyResult\n >\n >;\n}\n\n/**\n * Remove a registered domain.\n *\n * For sending domains, also removes the domain at the email provider\n * (best-effort; a failure there still removes the row). Resolves the domain name to its row\n * id via an extra GET before deletion.\n *\n * @throws Error if no domain matching `domain` is registered on this app\n * (thrown before the API call, not an AdminApiError).\n * @throws AdminApiError `not_found` (404) — the row was deleted between list and delete.\n * @example\n * await admin.email.removeDomain('sending', 'mail.acme.com');\n */\nexport async function removeDomain<D extends DomainDirection>(\n ctx: AdminContext,\n direction: D,\n domain: string,\n): Promise<\n ForDirection<\n D,\n OutboundEmailDomainDeleteResult,\n InboundEmailDomainDeleteResult\n >\n> {\n const id = await resolveDomainId(ctx, direction, domain);\n return call(\n ctx,\n 'POST',\n `${domainsPath(ctx, direction)}/${seg(id)}/delete`,\n ) as Promise<\n ForDirection<\n D,\n OutboundEmailDomainDeleteResult,\n InboundEmailDomainDeleteResult\n >\n >;\n}\n","/**\n * File-store operations: presigned uploads, read links, metadata, listing,\n * deletion. Pure (ctx, params) → typed result; the CLI skin owns everything\n * filesystem-shaped (path resolution, reading/writing disk).\n */\n\nimport path from 'node:path';\nimport { createHash } from 'node:crypto';\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport { uploadDirect } from '../upload.js';\nimport type {\n FilesDeleteResult,\n FilesListResult,\n FilesLsResult,\n FilesStatResult,\n FilesUploadUrlResult,\n FilesUrlResult,\n} from '../types/files.js';\n\nexport type FileAccess = 'public' | 'private';\n\nexport interface FileRef {\n /** Store name (e.g. 'assets'). */\n store: string;\n /** 'public' or 'private'. */\n access: FileAccess;\n /** Store-relative object key. */\n key: string;\n}\n\nexport interface FilesPutParams {\n content: Buffer;\n store: string;\n access: FileAccess;\n /**\n * Omitted → content-addressed: `<sha256(content)><ext-of-filename>`.\n * Idempotent and immutable, so the returned URL is safe to bake into source.\n */\n key?: string;\n /** Used for the upload form part name and the default key's extension. */\n filename?: string;\n contentType?: string;\n /**\n * Omitted → content-addressed public objects default to\n * `public, max-age=31536000, immutable` (their keys are never reused);\n * everything else falls through to the server default.\n */\n cacheControl?: string;\n /** Called just before the byte upload starts. */\n onProgress?: (message: string) => void;\n}\n\n/**\n * Upload a file via presigned POST (up to 5 GiB).\n *\n * The API mints a presigned S3 POST; bytes go straight to storage, bypassing\n * the API's JSON body limit. The key defaults to sha256(content) plus the\n * filename extension (see `FilesPutParams.key`), making re-uploads of the same\n * bytes idempotent and their URL safe to bake into source. Pass `key` for a\n * stable, overwritable name (e.g. a config JSON the frontend fetches).\n *\n * @throws AdminApiError `invalid_store` (400); `invalid_access` (400);\n * `invalid_key` (400).\n * @example\n * const { key, url } = await admin.files.put({\n * content: imageBuffer,\n * store: 'assets',\n * access: 'public',\n * filename: 'hero.jpg',\n * });\n */\nexport async function put(\n ctx: AdminContext,\n params: FilesPutParams,\n): Promise<{ key: string; url: string }> {\n const { content, store, access, filename } = params;\n const key =\n params.key ||\n `${createHash('sha256').update(content).digest('hex')}${\n filename ? path.extname(filename) : ''\n }`;\n const cacheControl =\n params.cacheControl ||\n (!params.key && access === 'public'\n ? 'public, max-age=31536000, immutable'\n : undefined);\n\n const presign = await call<FilesUploadUrlResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/file-storage/upload-url`,\n {\n store,\n access,\n key,\n maxSize: content.length,\n ...(params.contentType ? { contentType: params.contentType } : {}),\n ...(cacheControl ? { cacheControl } : {}),\n },\n );\n\n params.onProgress?.(\n `uploading ${(content.length / 1024 / 1024).toFixed(1)}MB…`,\n );\n await uploadDirect(\n { uploadUrl: presign.uploadUrl, uploadFields: presign.uploadFields },\n content,\n filename ?? key,\n );\n\n return { key: presign.key, url: presign.url };\n}\n\n/**\n * Mint a read link for one object.\n *\n * Private objects return a signed, expiring URL with `expiresAt` (ttl clamped\n * server-side to [60s, 7d], default 300s). Public objects return a permanent\n * on-domain URL with no expiry. Use a private store plus `sign` as the\n * sensitive-file handoff channel — links are unguessable and the object stays\n * deletable.\n *\n * @param ttlSeconds Requested TTL in seconds (clamped to [60, 604800]; default\n * 300). Ignored for public objects.\n * @throws AdminApiError `invalid_store` (400); `invalid_access` (400);\n * `invalid_key` (400); `file_flagged` (403) — the object was flagged by AV\n * scanning and cannot be linked.\n * @example\n * const { url, expiresAt } = await admin.files.sign(\n * { store: 'handoff', access: 'private', key },\n * 86400,\n * );\n */\nexport function sign(ctx: AdminContext, ref: FileRef, ttlSeconds?: number) {\n return call<FilesUrlResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/file-storage/url${qs({ ...ref, ttl: ttlSeconds })}`,\n );\n}\n\n/**\n * Download an object's bytes in-process.\n *\n * Mints a 60s presigned link via `sign`, then plain-fetches it — the link is\n * self-authorizing, so no auth headers are needed for the byte transfer. No\n * timeout on the byte stream; large objects are the whole point.\n *\n * @throws AdminApiError `file_flagged` (403) — the object was flagged by AV\n * scanning; also propagates `sign` errors.\n * @example\n * const { bytes, contentType } = await admin.files.fetchBytes({\n * store: 'handoff',\n * access: 'private',\n * key,\n * });\n */\nexport async function fetchBytes(\n ctx: AdminContext,\n ref: FileRef,\n): Promise<{ bytes: Buffer; contentType: string | null }> {\n const { url } = await sign(\n ctx,\n ref,\n ref.access === 'private' ? 60 : undefined,\n );\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Download failed: ${res.status} ${res.statusText}`);\n }\n return {\n bytes: Buffer.from(await res.arrayBuffer()),\n contentType: res.headers.get('content-type'),\n };\n}\n\n/**\n * Object metadata (size, contentType, updatedAt, scan status) — no download.\n *\n * A missing key throws AdminApiError 404, so this doubles as an existence\n * check without transferring any bytes.\n *\n * @throws AdminApiError `invalid_store` (400); `invalid_access` (400);\n * `invalid_key` (400); 404 if the key does not exist.\n * @example\n * const meta = await admin.files.stat({\n * store: 'assets',\n * access: 'public',\n * key: 'hero.jpg',\n * });\n */\nexport function stat(ctx: AdminContext, ref: FileRef) {\n return call<FilesStatResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/file-storage/metadata${qs(ref)}`,\n );\n}\n\nexport interface FilesLsParams {\n /** Store name (e.g. 'assets'). */\n store: string;\n /** 'public' or 'private'. */\n access: FileAccess;\n /** Return only keys that start with this string. */\n prefix?: string;\n /** Server-side substring search (switches the listing mode). */\n q?: string;\n /** Pagination cursor from the previous page's `cursor` field. */\n cursor?: string;\n /** Maximum objects to return per page. */\n limit?: number;\n}\n\n/**\n * List objects in one store with optional prefix filtering or substring search.\n *\n * Flat list by default. Pass `q` for substring search across the whole store\n * (overrides `prefix`, delimiter ignored). Results are paginated — follow the\n * returned `cursor` to fetch the next page.\n *\n * @throws AdminApiError `invalid_store` (400); `invalid_access` (400).\n * @example\n * const { files, cursor } = await admin.files.ls({\n * store: 'assets',\n * access: 'public',\n * prefix: 'images/',\n * });\n */\nexport function ls(ctx: AdminContext, params: FilesLsParams) {\n return call<FilesLsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/file-storage${qs(params)}`,\n );\n}\n\n/**\n * Store-level summary: every store with object counts, total bytes, and\n * AV/PII scan status histograms.\n *\n * @example\n * const { stores, totalObjects } = await admin.files.summary();\n */\nexport function summary(ctx: AdminContext) {\n return call<FilesListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/file-storage/summary`,\n );\n}\n\n/**\n * Delete one object from a store.\n *\n * @throws AdminApiError `invalid_store` (400); `invalid_access` (400);\n * `invalid_key` (400).\n * @example\n * await admin.files.remove({ store: 'handoff', access: 'private', key });\n */\nexport function remove(ctx: AdminContext, ref: FileRef) {\n return call<FilesDeleteResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/file-storage/delete`,\n { store: ref.store, access: ref.access, keys: [ref.key] },\n );\n}\n","/**\n * Provisioned-infrastructure operations: lease, park, resume and delete\n * dedicated resources (first kind: retrieval capacity for data sources).\n *\n * Ops are pure (ctx, params) → typed result. The CLI skin in\n * commands/infra.ts owns flag parsing, progress printing and exit codes.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call } from '../http.js';\nimport { renderProgress } from '../output.js';\nimport { elapsedSeconds, pollUntil, timedOut } from '../poll.js';\nimport type {\n InfraGetResult,\n InfraListResult,\n InfraLogsResult,\n InfraPhase,\n InfraResource,\n InfraResourceResult,\n} from '../types/infra.js';\n\n/** @internal Consumed by the CLI skin; waitForPhase documents the default. */\nexport const DEFAULT_WAIT_TIMEOUT_MS = 10 * 60 * 1000;\nconst POLL_MS = 3000;\n\nfunction base(appId: string): string {\n return `/_internal/v2/apps/${appId}/infra`;\n}\n\n// ─── list ────────────────────────────────────────────────────────────────────\n\nexport interface ListParams {\n /** Include resources that have been deleted; off by default. */\n includeDestroyed?: boolean;\n}\n\n/**\n * The app's dedicated resources plus the offerings it can provision, with\n * their hourly and monthly prices.\n *\n * @example\n * const { resources, offerings } = await admin.infra.list();\n */\nexport function list(ctx: AdminContext, params?: ListParams) {\n return call<InfraListResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}${params?.includeDestroyed ? '?includeDestroyed=true' : ''}`,\n );\n}\n\n// ─── get ─────────────────────────────────────────────────────────────────────\n\nexport interface GetParams {\n /** Resource id. */\n id: string;\n}\n\n/**\n * One resource with its state timeline and the data sources placed on it.\n *\n * @throws AdminApiError `resource_not_found` (404).\n */\nexport function get(ctx: AdminContext, params: GetParams) {\n return call<InfraGetResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}`,\n );\n}\n\n// ─── logs ────────────────────────────────────────────────────────────────────\n\nexport interface LogsParams {\n /** Resource id. */\n id: string;\n /** Continue after this line id (the last line of a previous page). */\n after?: string;\n /** Lines per page; without `after`, the newest this many. Max 500. */\n limit?: number;\n}\n\n/**\n * The platform's narration of a resource, oldest first: the steps a\n * transition went through, failed attempts, and failures with the pod's\n * events and a warnings-and-errors tail of the instance log. Not the\n * instance's own stdout.\n *\n * @throws AdminApiError `resource_not_found` (404).\n */\nexport function logs(ctx: AdminContext, params: LogsParams) {\n const query = new URLSearchParams();\n if (params.after) {\n query.set('after', params.after);\n }\n if (params.limit) {\n query.set('limit', String(params.limit));\n }\n const search = query.toString();\n return call<InfraLogsResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/logs${search ? `?${search}` : ''}`,\n );\n}\n\n// ─── provision ───────────────────────────────────────────────────────────────\n\nexport interface ProvisionParams {\n /** Offering id from `list().offerings`, e.g. `retrieval.small`. */\n offeringId: string;\n /** Display name; defaults to the offering label. */\n name?: string;\n}\n\n/**\n * Lease a new resource. Spends credits: the workspace must have a month's\n * worth available before the request is accepted; nothing is charged until\n * activation, and from then the resource bills by the hour.\n *\n * The response is the row in `requested`; the platform brings it to `active`\n * within a minute or so. Use `waitForPhase` to block on that.\n *\n * @throws AdminApiError `offering_not_found` (400), `offering_retired` (422),\n * `provisioning_unavailable` (422), `insufficient_credits` (402).\n * @example\n * const { resource } = await admin.infra.provision({ offeringId: 'retrieval.small' });\n */\nexport function provision(ctx: AdminContext, params: ProvisionParams) {\n return call<InfraResourceResult>(ctx, 'POST', base(ctx.appId), {\n offeringId: params.offeringId,\n ...(params.name ? { name: params.name } : {}),\n });\n}\n\n// ─── hibernate / resume / destroy / rename ───────────────────────────────────\n\nexport interface ResourceIdParams {\n /** Resource id. */\n id: string;\n}\n\n/**\n * Park an active resource. Data is kept; searches on its data sources return\n * `capacity_hibernating` while it parks and `capacity_hibernated` once parked,\n * until it resumes; billing drops to the retained-storage rate.\n *\n * @throws AdminApiError `resource_not_found` (404), `invalid_transition` (422).\n */\nexport function hibernate(ctx: AdminContext, params: ResourceIdParams) {\n return call<InfraResourceResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/hibernate`,\n );\n}\n\n/**\n * Bring a hibernated (or failed) resource back to active.\n *\n * @throws AdminApiError `resource_not_found` (404), `invalid_transition` (422).\n */\nexport function resume(ctx: AdminContext, params: ResourceIdParams) {\n return call<InfraResourceResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/resume`,\n );\n}\n\n/**\n * Delete a resource. Refused while any data source is placed on it — move\n * those to shared capacity (`admin.dataSources.move({ placement: 'shared' })`,\n * data intact) or delete them first. Billing stops when the phase reaches\n * `destroyed`.\n *\n * @throws AdminApiError `resource_not_found` (404),\n * `resource_has_attachments` (422), `invalid_transition` (422).\n */\nexport function destroy(ctx: AdminContext, params: ResourceIdParams) {\n return call<InfraResourceResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/destroy`,\n );\n}\n\nexport interface ResizeParams {\n id: string;\n /** Offering id from `list().offerings`, e.g. `retrieval.medium`. */\n offeringId: string;\n}\n\n/**\n * Change a resource's size, keeping its documents.\n *\n * The platform parks the resource, swaps its spec, and brings it back up with\n * its sources' indexes rebuilt from durable storage in the background, so a\n * resize passes through `hibernated` and searches on those sources answer\n * `index_warming` with the rebuild's progress until it lands. A resource that\n * is already hibernated swaps in place and stays parked. Growing is gated on a\n * month of credits at the new rate like a provision; shrinking is refused\n * below what the resource holds. The response carries `resizingTo` until the\n * swap has happened; `waitForPhase` with `until: (r) => r.resizingTo === null`\n * blocks on the whole thing.\n *\n * @throws AdminApiError `resource_not_found` (404), `offering_not_found`\n * (400), `offering_retired` (422), `same_offering` (400),\n * `offering_kind_mismatch` (400), `resize_pending` (422), `resize_too_small`\n * (422), `insufficient_credits` (402), `invalid_transition` (422).\n * @example\n * await admin.infra.resize({ id, offeringId: 'retrieval.medium' });\n */\nexport function resize(ctx: AdminContext, params: ResizeParams) {\n return call<InfraResourceResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/resize`,\n { offeringId: params.offeringId },\n );\n}\n\nexport interface RenameParams {\n id: string;\n name: string;\n}\n\n/** @throws AdminApiError `resource_not_found` (404), `invalid_name` (400). */\nexport function rename(ctx: AdminContext, params: RenameParams) {\n return call<InfraResourceResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/rename`,\n { name: params.name },\n );\n}\n\n// ─── waitForPhase ────────────────────────────────────────────────────────────\n\nexport interface WaitForPhaseParams {\n id: string;\n /** The phase(s) that count as done. */\n phases: InfraPhase[];\n /**\n * An extra condition on top of the phase — a resize, for one, ends in the\n * phase it started from and is done only once `resizingTo` has cleared.\n */\n until?: (resource: InfraResource) => boolean;\n /** How long without movement before giving up. Default 10 minutes. */\n timeoutMs?: number;\n onProgress?: (message: string) => void;\n}\n\nexport type WaitForPhaseResult =\n | { status: 'done'; resource: InfraResource }\n | { status: 'failed'; resource: InfraResource; error: string }\n | { status: 'timeout'; resource: InfraResource; error: string };\n\n/**\n * Poll a resource until it reaches one of `phases`, fails, or the timeout\n * elapses. A `failed` phase returns immediately with the platform's error.\n *\n * @example\n * const result = await admin.infra.waitForPhase({ id, phases: ['active'] });\n */\nexport async function waitForPhase(\n ctx: AdminContext,\n params: WaitForPhaseParams,\n): Promise<WaitForPhaseResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const wanted = new Set<InfraPhase>(params.phases);\n const arrived = (resource: InfraResource) =>\n wanted.has(resource.phase) && (params.until?.(resource) ?? true);\n\n const outcome = await pollUntil(\n async () => (await get(ctx, { id: params.id })).resource,\n (resource) => arrived(resource) || resource.phase === 'failed',\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (resource, start) =>\n resource.progress\n ? renderProgress(\n resource.progress,\n start,\n resource.resizingTo\n ? `resizing to ${resource.resizingTo.label}`\n : null,\n )\n : `${resource.phase}${resource.detail ? ` · ${resource.detail}` : ''}${\n resource.resizingTo\n ? ` · resizing to ${resource.resizingTo.label}`\n : ''\n }… (${elapsedSeconds(start)}s)`,\n // A rebuild after a resume runs as long as it must; the timeout bounds\n // silence, and a phase or step change counts as movement.\n progressKey: (resource) =>\n `${resource.phase}:${resource.progress?.done ?? ''}:${resource.detail ?? ''}`,\n onProgress: params.onProgress,\n },\n );\n const resource = outcome.value;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n resource,\n error: timedOut(timeoutMs, `; resource is still ${resource.phase}`),\n };\n }\n if (arrived(resource)) {\n return { status: 'done', resource };\n }\n return {\n status: 'failed',\n resource,\n error: resource.lastError ?? 'The platform could not complete the change.',\n };\n}\n","/**\n * App issues operations: CRUD for bugs, ideas, and tasks.\n *\n * Ops take resolved strings for body content — the stdin read\n * (`fs.readFileSync(0, ...)`) stays in the CLI skin (commands/issues.ts).\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n IssuesListResult,\n IssuesGetResult,\n IssuesCreateResult,\n IssuesCommentResult,\n IssuesUpdateResult,\n IssuesDeleteResult,\n} from '../types/issues.js';\n\n// The origin the API should credit for an entry this client writes, as a\n// spreadable fragment. Empty when the client is acting as the app it is pointed\n// at, which is the ordinary case and the one the API reads as \"my own agent\".\nfunction authorship(ctx: AdminContext): { originAppId?: string } {\n return ctx.originAppId ? { originAppId: ctx.originAppId } : {};\n}\n\nexport interface IssuesListParams {\n /** Filter by status: `open` or `closed`. Omit for any state. */\n status?: string;\n /** Match issues carrying ANY of these labels. */\n labels?: string[];\n /** Only issues another app filed here, by that app's id. */\n originAppId?: string;\n /** Max issues to return (default 50). */\n limit?: number;\n /** Keyset cursor from a previous response's `nextCursor`. */\n cursor?: string;\n}\n\n// The wire names the list routes read. `labels` is sent as a repeated `label`\n// param, so the mapping is explicit rather than a field rename away from\n// silently dropping the filter.\nfunction listQuery(params: IssuesListParams): string {\n return qs({\n status: params.status,\n label: params.labels,\n originAppId: params.originAppId,\n limit: params.limit,\n cursor: params.cursor,\n });\n}\n\n/**\n * List the issues filed IN an app, newest-first.\n *\n * @throws AdminApiError `invalid_status` (400) — status is not `open` or\n * `closed`.\n * @example\n * const { issues } = await admin.issues.list({ status: 'open', labels: ['bug'] });\n */\nexport function list(ctx: AdminContext, params: IssuesListParams = {}) {\n return call<IssuesListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/issues${listQuery(params)}`,\n );\n}\n\n/**\n * List the issues this app filed INTO other apps, newest-first.\n *\n * The sender's half of a cross-app thread: one call returns every issue the\n * app sent out, so a fan-out across forty apps is read once rather than forty\n * times. Scoped to apps in the same workspace.\n *\n * @throws AdminApiError `invalid_status` (400) — status is not `open` or\n * `closed`.\n * @example\n * const { issues } = await admin.issues.filed({ status: 'open' });\n */\nexport function filed(\n ctx: AdminContext,\n params: Omit<IssuesListParams, 'originAppId'> = {},\n) {\n return call<IssuesListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/issues/filed${listQuery(params)}`,\n );\n}\n\n/**\n * Get one issue with its full comment thread.\n *\n * @param number The friendly per-app issue number (e.g. `\"42\"`), as shown\n * in `list` results under `issue.number`.\n * @throws AdminApiError `issue_not_found` (404) — no issue with this number\n * in this app.\n * @example\n * const { issue, comments } = await admin.issues.get('42');\n */\nexport function get(ctx: AdminContext, number: string) {\n return call<IssuesGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}`,\n );\n}\n\nexport interface IssuesCreateParams {\n /** Issue title (required, non-empty). */\n title: string;\n /** Issue body in markdown. */\n body?: string;\n /** Labels to file it under. Open set, at most 20, 64 chars each. */\n labels?: string[];\n /**\n * The app filing this, when it isn't the app the issue lands in. Defaults to\n * `ctx.originAppId` — set whenever the caller retargeted at another app — so\n * cross-app authorship is recorded without anyone opting in. Pass it\n * explicitly only to override that.\n */\n originAppId?: string;\n}\n\n/**\n * File a new issue authored as the agent (`authorKind: \"agent\"`).\n *\n * Returns the created issue row. When the server is supplied a `source`\n * blob and an open issue for the same source already existed, it returns\n * that issue with `deduped: true` (no new row created); the ops layer does\n * not accept `source`, so `deduped` is always absent from op-layer responses.\n *\n * @throws AdminApiError `missing_title` (400) — title is required or empty;\n * `invalid_labels` (400) — labels are not strings, or exceed the count /\n * length caps; `invalid_origin_app_id` (400) — originAppId is not an app id.\n * @example\n * const { issue } = await admin.issues.create({ title: 'Checkout 500s on empty cart', labels: ['bug'] });\n */\nexport function create(ctx: AdminContext, params: IssuesCreateParams) {\n const requestBody: Record<string, unknown> = {\n title: params.title,\n authorKind: 'agent',\n };\n if (params.body !== undefined) {\n requestBody.body = params.body;\n }\n if (params.labels !== undefined) {\n requestBody.labels = params.labels;\n }\n const originAppId = params.originAppId ?? ctx.originAppId;\n if (originAppId !== undefined) {\n requestBody.originAppId = originAppId;\n }\n return call<IssuesCreateResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/issues`,\n requestBody,\n );\n}\n\n/**\n * Post a comment on an issue's thread authored as the agent.\n *\n * @param number The issue number.\n * @param body The comment body (non-empty).\n * @throws AdminApiError `missing_body` (400) — body is empty;\n * `issue_not_found` (404) — no issue with this number in this app.\n * @example\n * await admin.issues.comment('42', 'Fixed in the latest release.');\n */\nexport function comment(ctx: AdminContext, number: string, body: string) {\n return call<IssuesCommentResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}/comments`,\n { body, authorKind: 'agent', ...authorship(ctx) },\n );\n}\n\n/**\n * Close an issue, optionally with a closing comment.\n *\n * Records a `closed` timeline event on the thread, preceded by the comment\n * when one is given — so answering and resolving is one call, which is what\n * replying to an issue another app filed usually amounts to.\n *\n * @param number The issue number.\n * @param comment Optional prose posted before the close event.\n * @throws AdminApiError `issue_not_found` (404) — no issue with this number\n * in this app.\n * @example\n * await admin.issues.close('42', 'Already fixed in v3 — no change needed.');\n */\nexport function close(ctx: AdminContext, number: string, comment?: string) {\n const requestBody: Record<string, unknown> = {\n status: 'closed',\n authorKind: 'agent',\n ...authorship(ctx),\n };\n if (comment !== undefined) {\n requestBody.comment = comment;\n }\n return call<IssuesUpdateResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}/update`,\n requestBody,\n );\n}\n\n/**\n * Reopen a closed issue.\n *\n * Records a `reopened` timeline event on the thread.\n *\n * @param number The issue number.\n * @throws AdminApiError `issue_not_found` (404) — no issue with this number\n * in this app.\n * @example\n * await admin.issues.reopen('42');\n */\nexport function reopen(ctx: AdminContext, number: string) {\n return call<IssuesUpdateResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}/update`,\n { status: 'open', authorKind: 'agent', ...authorship(ctx) },\n );\n}\n\nexport interface IssuesEditParams {\n /** Replace the issue's title (non-empty). */\n title?: string;\n /** Replace the issue's body. */\n body?: string;\n /** Replace the issue's labels wholesale (not a merge). */\n labels?: string[];\n /** Change the status to `open` or `closed`. */\n status?: string;\n}\n\n/**\n * Edit an issue's title, body, labels, or status.\n *\n * Status transitions record a `closed` or `reopened` timeline event\n * automatically. At least one field must be provided.\n *\n * @param number The issue number.\n * @throws AdminApiError `missing_title` (400) — title was supplied but empty;\n * `invalid_labels` (400) — labels are not strings, or exceed the count /\n * length caps; `invalid_status` (400) — status is not `open` or `closed`;\n * `no_fields` (400) — no editable field was provided; `issue_not_found`\n * (404) — no issue with this number in this app.\n * @example\n * await admin.issues.edit('42', { status: 'closed' });\n */\nexport function edit(\n ctx: AdminContext,\n number: string,\n params: IssuesEditParams,\n) {\n const requestBody: Record<string, unknown> = {\n authorKind: 'agent',\n ...authorship(ctx),\n };\n if (params.title !== undefined) {\n requestBody.title = params.title;\n }\n if (params.body !== undefined) {\n requestBody.body = params.body;\n }\n if (params.labels !== undefined) {\n requestBody.labels = params.labels;\n }\n if (params.status !== undefined) {\n requestBody.status = params.status;\n }\n return call<IssuesUpdateResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}/update`,\n requestBody,\n );\n}\n\n/**\n * Delete an issue. The number is permanently retired (never reissued).\n *\n * @param number The issue number.\n * @throws AdminApiError `issue_not_found` (404) — no issue with this number\n * in this app.\n * @example\n * await admin.issues.del('42');\n */\nexport function del(ctx: AdminContext, number: string) {\n return call<IssuesDeleteResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}/delete`,\n );\n}\n","/**\n * Jewels operations: shadowing overview, pair ledger, approval queue, training.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/jewels.ts and the importable client both call these.\n *\n * Long-running ops (resolve --approve, dryrun, train, grade) hold the request\n * for a full agent/model run; they pass their own timeout bound to `call`.\n * The constant is exported so the CLI skin can pass the same value to\n * cliStream.rawToStdout for the `jewels export --file` passthrough.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\n\nimport type {\n JewelsDryrunResult,\n JewelsExportResult,\n JewelsGradeResult,\n JewelsOverviewResult,\n JewelsPairResult,\n JewelsPairsResult,\n JewelsQueueResult,\n JewelsResolveResult,\n JewelsRunResult,\n JewelsRunsResult,\n JewelsTimeseriesResult,\n JewelsTrainResult,\n} from '../types/jewels.js';\n\n/**\n * Jewel runs are full agent loops: resolve --approve applies the method as\n * the reviewer, and dryrun executes the live jewel end to end — both can\n * legitimately take minutes, so they get their own request bound.\n * @internal Consumed by the CLI skin; not part of the documented surface.\n */\nexport const JEWEL_RUN_TIMEOUT_MS = 600_000;\n\nexport interface WindowParams {\n /** ISO date string for the start of the query window (default: 30 days before `end`). */\n start?: string;\n /** ISO date string for the end of the query window (default: now). */\n end?: string;\n}\n\nexport interface JewelsPairsParams extends WindowParams {\n /** Filter to a specific method id. */\n methodId?: string;\n /** Filter by verdict: `agree`, `disagree`, `skip`, or `expired`. */\n verdict?: string;\n /** Filter by shadow mode: `shadow`, `arrival`, `auto`, or `approve`. */\n mode?: string;\n /** Page size (default 50). */\n limit?: number;\n /** Keyset cursor from a previous response's `nextCursor`. */\n cursor?: string;\n}\n\nexport interface JewelsQueueParams {\n /** Filter to a specific method id. */\n methodId?: string;\n /** Max items to return (default 50). */\n limit?: number;\n}\n\nexport interface JewelsTimeseriesParams extends WindowParams {\n /** Filter to a specific method id. */\n methodId?: string;\n /** Number of time buckets (default 24). */\n buckets?: number;\n}\n\nexport interface JewelsResolveParams {\n /** The queue item's id (from `queue` results). */\n itemId: string;\n /**\n * `approve` runs the method for real as the calling user (the reviewer),\n * grades the proposed-vs-final pair, and closes the item. `dismiss` closes\n * the item without acting — no method run, no pair recorded.\n */\n action: 'approve' | 'dismiss';\n /**\n * Override the proposed input before applying (approve only). When set the\n * resolution is recorded as `edited`; omit to apply the proposal as-is.\n */\n input?: Record<string, unknown>;\n}\n\nexport interface JewelsDryrunParams {\n /** The method id whose jewel should run against `subject`. */\n methodId: string;\n /** The triggering subject object to pass to the jewel. */\n subject: Record<string, unknown>;\n}\n\nexport interface JewelsExportParams extends WindowParams {\n /** The method id to export pairs for. */\n methodId: string;\n}\n\nexport interface JewelsTrainParams {\n /** The method id to train a fine-tuning run for. */\n methodId: string;\n}\n\nexport interface JewelsRunsParams {\n /** Filter to a specific method id. */\n methodId?: string;\n /** Max runs to return (default 20). */\n limit?: number;\n}\n\n/**\n * Per-method shadowing overview: autonomy, sample rate, pair counts by verdict,\n * agreement rate, human-invocation coverage, and queue depth.\n *\n * Time window defaults to the last 30 days when `start`/`end` are omitted.\n * Training summary (active run, last run, latest model) is always all-time\n * regardless of the window — it reflects current model state, not the pair\n * stats window.\n *\n * @example\n * const { methods, totals } = await admin.jewels.overview();\n * const shadowed = methods.filter((m) => m.hasJewel);\n */\nexport function overview(ctx: AdminContext, params: WindowParams = {}) {\n return call<JewelsOverviewResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/overview${qs(params)}`,\n );\n}\n\n/**\n * Verdict counts (agree / disagree / skip / expired) over time, bucketed.\n *\n * One bucket array per method; use `methodId` to narrow to a single series.\n * Time window defaults to the last 30 days.\n *\n * @example\n * const { methods } = await admin.jewels.timeseries({ methodId: 'triage-issue', buckets: 48 });\n */\nexport function timeseries(\n ctx: AdminContext,\n params: JewelsTimeseriesParams = {},\n) {\n return call<JewelsTimeseriesResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/timeseries${qs(params)}`,\n );\n}\n\n/**\n * Paginated list of slim pair rows (excludes the full JSONB pair payload).\n *\n * Use `pair(pairId)` to fetch the full record with hydrated traces.\n * Time window defaults to the last 30 days.\n *\n * @example\n * const { pairs, nextCursor } = await admin.jewels.pairs({ verdict: 'disagree' });\n */\nexport function pairs(ctx: AdminContext, params: JewelsPairsParams = {}) {\n return call<JewelsPairsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/pairs${qs(params)}`,\n );\n}\n\n/**\n * Full pair record: proposed vs actual output, reasoning, grade notes, and\n * hydrated model transcripts (propose + grade phases) when the jewel attached\n * traces. Objects that could not be fetched degrade to `{ id, phase, missing: true }`\n * rather than a 500.\n *\n * @param pairId The pair id (from `pairs` results or the overview).\n * @throws AdminApiError `pair_not_found` (404) — no pair with this id in this app.\n * @example\n * const { pair, traces } = await admin.jewels.pair('6f1e...');\n */\nexport function pair(ctx: AdminContext, pairId: string) {\n return call<JewelsPairResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/pairs/${seg(pairId)}`,\n );\n}\n\n/**\n * Pending approve-mode proposals awaiting review.\n *\n * Only items for methods with `autonomy: 'approve'` appear here. Use\n * `resolve` to approve or dismiss an item.\n *\n * @example\n * const { items } = await admin.jewels.queue({ methodId: 'triage-issue' });\n */\nexport function queue(ctx: AdminContext, params: JewelsQueueParams = {}) {\n return call<JewelsQueueResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/queue${qs(params)}`,\n );\n}\n\n/**\n * Approve or dismiss one approval-queue item.\n *\n * **Approve** applies the method as the calling user (the reviewer): the\n * proposal's input runs for real, the platform grades proposed-vs-final, and\n * the item closes. Pass `input` to apply an edited version (resolution\n * recorded as `edited`). **Dismiss** closes the item without acting — no\n * method run, no pair recorded.\n *\n * The request holds for a full jewel/method run — allow minutes (up to\n * `JEWEL_RUN_TIMEOUT_MS`).\n *\n * @example\n * const { resolution, output } = await admin.jewels.resolve({ itemId: '6f1e...', action: 'approve' });\n */\nexport function resolve(ctx: AdminContext, params: JewelsResolveParams) {\n const body: Record<string, unknown> = {\n itemId: params.itemId,\n action: params.action,\n };\n if (params.input !== undefined) {\n body.input = params.input;\n }\n return call<JewelsResolveResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/jewels/queue/resolve`,\n body,\n JEWEL_RUN_TIMEOUT_MS,\n );\n}\n\n/**\n * Run the live jewel against a subject without recording or committing\n * anything.\n *\n * Executes inside a disposable database mirror — guaranteed side-effect-free\n * on the app database. The prod twin of the dev `testJewel` tool (which runs\n * draft code against the dev DB); this one answers for the deployed release\n * against the real world. Allow minutes for the full jewel run.\n *\n * @throws AdminApiError `invalid_subject` (400) — `subject` is not an object;\n * `invalid_app_method` (400) — unknown method id; `no_jewel` (400) — the\n * method has no compiled jewel in the live release.\n * @example\n * const { record } = await admin.jewels.dryrun({ methodId: 'triage-issue', subject: { issueId: 'abc' } });\n */\nexport function dryrun(ctx: AdminContext, params: JewelsDryrunParams) {\n return call<JewelsDryrunResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/jewels/${seg(params.methodId)}/dryrun`,\n { subject: params.subject },\n JEWEL_RUN_TIMEOUT_MS,\n );\n}\n\n/**\n * Dataset report (no `--file`): per-file row counts, every exclusion bucket\n * named (skip, expired, ungraded, auto, traceless, traceMissing,\n * preferenceUnrenderable), and trace coverage.\n *\n * The streaming JSONL variant (`--file`) is handled entirely by the CLI skin\n * via `cliStream.rawToStdout` — it is not an op.\n *\n * @throws AdminApiError `missing_method_id` (400) — `methodId` is required;\n * `invalid_file` (400) — `file` is not one of the allowed dataset file types.\n * @example\n * const { summary } = await admin.jewels.exportSummary({ methodId: 'triage-issue' });\n */\nexport function exportSummary(ctx: AdminContext, params: JewelsExportParams) {\n return call<JewelsExportResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/export${qs(params)}`,\n undefined,\n JEWEL_RUN_TIMEOUT_MS,\n );\n}\n\n/**\n * Kick off a LoRA fine-tuning run on the method's graded pairs.\n *\n * Returns **immediately** with a run id and dataset report (per-file row\n * counts, exclusion buckets); the GPU trainer runs asynchronously. Poll\n * with `getRun(run.id)` for live progress — the run's `log` carries a\n * narrated status timeline and loss-curve points. One run per method at\n * a time.\n *\n * The tuning dial comes from the method's manifest in the live release.\n * The report's agreement is scored against the held-out ledger split —\n * real decisions the model never saw.\n *\n * @throws AdminApiError `missing_method_id` (400) — `methodId` is required;\n * `invalid_app_method` (400) — unknown method id; `no_jewel` (400) — the\n * method has no compiled jewel in the live release.\n * @example\n * const { run, summary } = await admin.jewels.train({ methodId: 'triage-issue' });\n * // poll for completion:\n * const { run: status } = await admin.jewels.getRun(run.id);\n */\nexport function train(ctx: AdminContext, params: JewelsTrainParams) {\n return call<JewelsTrainResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/jewels/train`,\n { methodId: params.methodId },\n JEWEL_RUN_TIMEOUT_MS,\n );\n}\n\n/**\n * List training runs newest-first.\n *\n * The `log` field is serialized as `[]` in list responses; fetch a single\n * run with `getRun` to read the full event log.\n *\n * @example\n * const { runs } = await admin.jewels.runs({ methodId: 'triage-issue' });\n */\nexport function runs(ctx: AdminContext, params: JewelsRunsParams = {}) {\n return call<JewelsRunsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/training-runs${qs(params)}`,\n );\n}\n\n/**\n * Get one training run with its full event log and report.\n *\n * The run's `log` is an append-only array of `status` (narration) and `loss`\n * (training curve) entries — the primary polling target for `train --wait`.\n * Status `complete` or `failed` is the terminal signal.\n *\n * @param runId The run id returned by `train` or `runs`.\n * @throws AdminApiError `run_not_found` (404) — no run with this id in this app.\n * @example\n * const { run } = await admin.jewels.getRun(runId);\n * if (run.status === 'complete') console.log(run.report?.grading);\n */\nexport function getRun(ctx: AdminContext, runId: string) {\n return call<JewelsRunResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/training-runs/${seg(runId)}`,\n );\n}\n\n/**\n * Re-grade a completed run's held-out predictions with the jewel's own grade\n * function (the same grader as the pairs dashboard).\n *\n * Writes `report.grading`. Runs automatically on completion — use this as\n * the manual retry or backfill for runs that predate the grading feature or\n * whose fire-and-forget trigger was lost. Idempotent.\n *\n * @param runId The run id to grade.\n * @throws AdminApiError `run_not_found` (404) — no run with this id in this app.\n * @example\n * const { grading } = await admin.jewels.grade(runId);\n * console.log(`agreement: ${grading.agreement}`);\n */\nexport function grade(ctx: AdminContext, runId: string) {\n return call<JewelsGradeResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/jewels/training-runs/${seg(runId)}/grade`,\n undefined,\n JEWEL_RUN_TIMEOUT_MS,\n );\n}\n","/**\n * Methods operations: list (via dashboard) and invoke.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/methods.ts owns streaming (--stream → cliStream.streamToStdout)\n * and user-facing error messages.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, seg } from '../http.js';\nimport type {\n DashboardResult,\n DashboardReleaseMethod,\n} from '../types/releases.js';\nimport type { MethodsInvokeResult } from '../types/methods.js';\n\n/**\n * How long an invoke waits for the method's answer: as long as the API's load\n * balancer holds an idle connection (600 s), since a method can run for many\n * minutes and a request can't outwait that. A method still running past it\n * carries on; `requests list --method <id>` shows how it ended.\n * @internal Consumed by the CLI skin; not part of the documented surface.\n */\nexport const METHOD_RUN_TIMEOUT_MS = 600_000;\n\nexport interface MethodsInvokeParams {\n /** The method's compiled id (e.g. `mth_abc123`), as shown by `methods.list`. */\n methodId: string;\n /** Input payload forwarded to the method as its first argument. */\n input: Record<string, unknown>;\n /** Present when --roles or --user-id is set; routes through /invoke-as. */\n impersonate?: { roles?: string[]; userId?: string };\n}\n\n/**\n * List methods available on the live release.\n *\n * Fetches the dashboard endpoint and unwraps `liveRelease.methods`. Throws a\n * plain `Error` (not AdminApiError) when the app has no live release —\n * message: `\"No live release — publish first.\"`.\n *\n * @example\n * const methods = await admin.methods.list();\n * const target = methods.find((m) => m.id === 'mth_abc123');\n */\nexport async function list(\n ctx: AdminContext,\n): Promise<DashboardReleaseMethod[]> {\n const dashboard = await call<DashboardResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/dashboard`,\n );\n const release = dashboard.liveRelease;\n if (!release) {\n throw new Error('No live release — publish first.');\n }\n return release.methods ?? [];\n}\n\n/**\n * Invoke a method and return its output (non-streaming).\n *\n * Routes to `/invoke-as` when `impersonate` is set (either `roles` or\n * `userId` provided), allowing role-gated methods to be tested without\n * spec edits. The streaming path in the CLI skin calls\n * `cliStream.streamToStdout` with the same path/body construction.\n *\n * @throws AdminApiError `missing_impersonation` (400) — `impersonate` object\n * is malformed; `invalid_impersonation` (400) — `impersonate.userId` or\n * `impersonate.roles` has a bad type, or neither field is populated.\n * @example\n * const { output } = await admin.methods.invoke({\n * methodId: 'mth_abc123',\n * input: { query: 'hello' },\n * });\n */\nexport function invoke(ctx: AdminContext, params: MethodsInvokeParams) {\n const { methodId, input, impersonate } = params;\n const useImpersonate =\n impersonate !== undefined &&\n (impersonate.roles !== undefined || impersonate.userId !== undefined);\n const apiPath = useImpersonate\n ? `/_internal/v2/apps/${ctx.appId}/methods/${seg(methodId)}/invoke-as`\n : `/_internal/v2/apps/${ctx.appId}/methods/${seg(methodId)}/invoke`;\n const body: Record<string, unknown> = useImpersonate\n ? { input, impersonate }\n : { input };\n return call<MethodsInvokeResult>(\n ctx,\n 'POST',\n apiPath,\n body,\n METHOD_RUN_TIMEOUT_MS,\n );\n}\n","/**\n * Prerender operations: snapshot listing, stored-HTML view, cache invalidation.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/prerender.ts owns the `prerender get` crawler fetch (a public-URL\n * bot-UA fetch that is NOT an authed API call).\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\n\nimport type {\n PrerenderInvalidateResult,\n PrerenderPagesResult,\n PrerenderViewResult,\n} from '../types/prerender.js';\n\nexport interface PrerenderPagesParams {\n /** Opaque cursor from a previous `pages` response; omit to start from the first page. */\n cursor?: string;\n}\n\nexport interface PrerenderViewParams {\n /** App path to look up (e.g. `/u/abc123`). Must be non-empty. */\n path: string;\n}\n\nexport interface PrerenderInvalidateParams {\n /**\n * Paths to purge. Omit (or pass undefined) to purge every snapshot\n * (the `--all` flag). An explicit empty array is the same as --all.\n */\n paths?: string[];\n}\n\n/**\n * List stored prerendered snapshots for the live release.\n *\n * Paginated — pass `nextCursor` from the previous response as `cursor` on\n * the next call. Returns `{ releaseId: null, pages: [] }` (not an error)\n * when the app has no live release.\n *\n * @example\n * const { pages } = await admin.prerender.pages();\n * console.log(`${pages.length} snapshots cached`);\n */\nexport function pages(ctx: AdminContext, params: PrerenderPagesParams = {}) {\n return call<PrerenderPagesResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/prerender/pages${qs(params)}`,\n );\n}\n\n/**\n * Retrieve the stored snapshot HTML for a single path.\n *\n * Returns JSON (not text/html) so the snapshot cannot execute in the API\n * origin; render the `html` field in a sandboxed iframe if displaying it.\n *\n * @throws AdminApiError `snapshot_not_found` (404) — no snapshot exists for\n * that path (the path is cold; trigger a render via `prerender get`);\n * `missing_path` (400) — `path` is empty.\n * @example\n * const { html } = await admin.prerender.view({ path: '/u/abc123' });\n */\nexport function view(ctx: AdminContext, params: PrerenderViewParams) {\n return call<PrerenderViewResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/prerender/pages/view${qs({ path: params.path })}`,\n );\n}\n\n/**\n * Purge one or more prerendered snapshots for the live release.\n *\n * Omit `paths` (or pass `undefined`) to purge every snapshot for the app.\n * An empty array behaves the same as omitting. The next crawler visit to any\n * invalidated path will trigger a fresh render.\n *\n * @example\n * // Purge a specific path:\n * await admin.prerender.invalidate({ paths: ['/u/abc123'] });\n * // Purge all snapshots:\n * await admin.prerender.invalidate();\n */\nexport function invalidate(\n ctx: AdminContext,\n params: PrerenderInvalidateParams = {},\n) {\n const body: Record<string, unknown> = {};\n if (params.paths !== undefined && params.paths.length > 0) {\n body.paths = params.paths;\n }\n return call<PrerenderInvalidateResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/prerender/invalidate`,\n body,\n );\n}\n","/**\n * Browser-QA replay recordings: list what the QA agent recorded, and render a\n * replay to an mp4.\n *\n * `ls` is a grouped view over `files.ls` — a replay chunk is an ordinary\n * private file in the app's `qa-recordings` store and needs no endpoint of its\n * own.\n *\n * `export` is the one operation in this SDK that does NOT go through the\n * management API. Rendering a replay means playing it in a real browser and\n * encoding the frames, and the only machine set up to do that is the dev box\n * the recording was made on: it already has the headless Chrome, the rrweb\n * replayer and ffmpeg. So this talks to the sandbox's local sidecar, and says\n * so plainly when there isn't one. (CLI-only paths are established here —\n * `methods invoke --stream`, `jewels export --file` — but this is the first\n * that needs local compute rather than local disk.)\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { SIDECAR_URL } from '../config.js';\nimport * as files from './files.js';\nimport type {\n QaRecordingRun,\n QaRecordingSession,\n QaRecordingsExportResult,\n QaRecordingsLsResult,\n} from '../types/qaRecordings.js';\n\n/** The app store QA replay chunks are written to (private). */\nexport const RECORDING_STORE = 'qa-recordings';\n\nexport interface QaRecordingsLsParams {\n /** Only this session. Omitted → every session in the store. */\n sessionId?: string;\n cursor?: string;\n /** Chunk objects to scan, not sessions returned. */\n limit?: number;\n}\n\n/**\n * Recording sessions in this app, grouped from the chunk keys.\n *\n * @example\n * const { sessions } = await admin.qaRecordings.ls({});\n * // → [{ sessionId, chunks, bytes, runs: [{ runId, keys }] }]\n */\nexport async function ls(\n ctx: AdminContext,\n params: QaRecordingsLsParams = {},\n): Promise<QaRecordingsLsResult> {\n const page = await files.ls(ctx, {\n store: RECORDING_STORE,\n access: 'private',\n ...(params.sessionId ? { prefix: `${params.sessionId}/` } : {}),\n ...(params.cursor ? { cursor: params.cursor } : {}),\n ...(params.limit ? { limit: params.limit } : {}),\n });\n\n const sessions = new Map<string, QaRecordingSession>();\n for (const entry of page.files) {\n // `{sessionId}/{runId}/{seq}.json`. Anything else is not a chunk — skip it\n // rather than inventing a session for it.\n const parts = entry.key.split('/');\n if (parts.length !== 3) {\n continue;\n }\n const [sessionId, runId] = parts;\n let session = sessions.get(sessionId);\n if (!session) {\n session = { sessionId, chunks: 0, bytes: 0, runs: [] };\n sessions.set(sessionId, session);\n }\n let run = session.runs.find((r: QaRecordingRun) => r.runId === runId);\n if (!run) {\n run = { runId, chunks: 0, bytes: 0, keys: [] };\n session.runs.push(run);\n }\n const size = entry.size ?? 0;\n session.chunks += 1;\n session.bytes += size;\n run.chunks += 1;\n run.bytes += size;\n run.keys.push(entry.key);\n if (entry.updatedAt) {\n if (!session.startedAt || entry.updatedAt < session.startedAt) {\n session.startedAt = entry.updatedAt;\n }\n if (!session.endedAt || entry.updatedAt > session.endedAt) {\n session.endedAt = entry.updatedAt;\n }\n }\n }\n\n // Keys within a run sort by seq, and sessions by recency — the run somebody\n // just did is the one they are almost always asking about.\n for (const session of sessions.values()) {\n for (const run of session.runs) {\n run.keys.sort((a, b) => seqOf(a) - seqOf(b));\n }\n }\n return {\n store: RECORDING_STORE,\n sessions: [...sessions.values()].sort((a, b) =>\n (b.endedAt ?? '').localeCompare(a.endedAt ?? ''),\n ),\n ...(page.cursor ? { cursor: page.cursor } : {}),\n };\n}\n\nfunction seqOf(key: string): number {\n const n = Number(\n key\n .split('/')\n .pop()\n ?.replace(/\\.json$/, ''),\n );\n return Number.isFinite(n) ? n : 0;\n}\n\nexport interface QaRecordingsExportParams {\n /** The recording session to render (32 hex characters). */\n sessionId: string;\n /** Window of the session, as epoch milliseconds. Both required: a replay is\n * a slice of a continuous recording, not a file. */\n from: number;\n to: number;\n /** Where the mp4 is written. Defaults to `assets`, public. */\n store?: string;\n access?: 'public' | 'private';\n /** Milliseconds to wait for the render. */\n timeoutMs?: number;\n}\n\n// Above the sidecar's own 600s rung so the box's error surfaces rather than a\n// severed request (see the ladder in mindstudio-sandbox/src/lsp/sidecar.ts).\nconst DEFAULT_EXPORT_TIMEOUT_MS = 660_000;\n\n/**\n * Render a window of a recording session to an mp4 on the dev box.\n *\n * Blocks for the whole render — the clip plays in real time, then encodes and\n * uploads — and answers with where the video landed. Runs only on a Remy dev\n * box, since that is where the browser and ffmpeg are.\n *\n * @example\n * const { url } = await admin.qaRecordings.exportVideo({\n * sessionId, from: 1758000000000, to: 1758000042000,\n * });\n */\nexport async function exportVideo(\n _ctx: AdminContext,\n params: QaRecordingsExportParams,\n): Promise<QaRecordingsExportResult> {\n const body = {\n recordingSessionId: params.sessionId,\n startTs: params.from,\n endTs: params.to,\n ...(params.store ? { store: params.store } : {}),\n ...(params.access ? { access: params.access } : {}),\n };\n\n let res: Response;\n try {\n res = await fetch(`${SIDECAR_URL}/export-recording`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(\n params.timeoutMs ?? DEFAULT_EXPORT_TIMEOUT_MS,\n ),\n });\n } catch (err) {\n // Nothing listening is the common case and has a specific cause worth\n // naming, rather than surfacing ECONNREFUSED at the user. Not an\n // AdminApiError: this never reached an API.\n throw new Error(\n `Could not reach the sandbox at ${SIDECAR_URL} ` +\n `(${err instanceof Error ? err.message : String(err)}). ` +\n 'Rendering a replay needs the dev box that recorded it — this ' +\n 'command only works inside a Remy sandbox.',\n );\n }\n\n const payload = (await res.json().catch(() => ({}))) as Record<\n string,\n unknown\n >;\n if (!res.ok) {\n throw new Error(\n typeof payload.error === 'string'\n ? payload.error\n : `The sandbox refused the export (HTTP ${res.status}).`,\n );\n }\n const status = payload.export as QaRecordingsExportResult | undefined;\n if (!status) {\n throw new Error(\n 'The sandbox accepted the export but reported no result. Check the ' +\n \"box's tunnel logs.\",\n );\n }\n // A render that ran and failed is a RESULT, not an exception — it carries a\n // reason and an error code the caller may want to branch on (FFMPEG_\n // UNAVAILABLE, CANCELLED). The CLI skin turns a non-completed status into a\n // non-zero exit; an importing caller inspects `status`.\n return status;\n}\n","/**\n * Request log + method metrics operations.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/requests.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n RequestsListResult,\n RequestsGetResult,\n RequestsStatsSummaryResult,\n RequestsStatsMethodResult,\n} from '../types/requests.js';\n\nexport interface RequestsListParams {\n /** Filter to a single method id (e.g. `mth_abc123`). */\n methodId?: string;\n /** `'success'` or `'error'` — omit to return all statuses. */\n status?: string;\n /** Maximum rows to return (default 50). */\n limit?: number;\n /** Row offset for pagination (default 0). */\n offset?: number;\n /** Keyset cursor from a previous page's `nextCursor`. */\n cursor?: string;\n}\n\nexport interface MetricsWindowParams {\n /** Window start as an ISO 8601 date string (inclusive). */\n start?: string;\n /** Window end as an ISO 8601 date string (inclusive). */\n end?: string;\n}\n\n/**\n * Recent request log entries, optionally filtered by method or status.\n *\n * Results are cursor-paginated — check `nextCursor` to page forward. Default\n * `limit` is 50 and `offset` is 0. A run's `id` is also its request-log id,\n * so `requests.get(id)` drills into the full payload for any interface\n * (cron, api, agent, …).\n *\n * @example\n * const { requests } = await admin.requests.list({ status: 'error', limit: 10 });\n */\nexport function list(ctx: AdminContext, params: RequestsListParams = {}) {\n return call<RequestsListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/requests${qs(params)}`,\n );\n}\n\n/**\n * Full request log entry — input, output, stdout, error, and interface context.\n *\n * @param requestId The request id (e.g. from `list`, or the `requestId`\n * returned by `cron.run`).\n * @throws AdminApiError `not_found` (404) — the request id does not exist or\n * belongs to a different app.\n * @example\n * const entry = await admin.requests.get('req_abc123');\n */\nexport function get(ctx: AdminContext, requestId: string) {\n return call<RequestsGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/requests/${seg(requestId)}`,\n );\n}\n\n/**\n * Aggregated metrics for the whole app over a time window.\n *\n * Returns per-bucket totals, per-method breakdowns with sparklines,\n * per-error-type counts, and interface distribution. When `start`/`end` are\n * omitted the server applies its own default window.\n *\n * @example\n * const { totals, byMethod } = await admin.requests.statsSummary();\n */\nexport function statsSummary(\n ctx: AdminContext,\n params: MetricsWindowParams = {},\n) {\n return call<RequestsStatsSummaryResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/metrics/summary${qs(params)}`,\n );\n}\n\n/**\n * Per-method time-series metrics over a time window.\n *\n * Returns per-bucket counts (including `successCount`, which is absent from\n * the app-summary buckets), overall totals, and an error-type breakdown.\n * When `start`/`end` are omitted the server applies its own default window.\n *\n * @param methodId The method id to scope the query (e.g. `mth_abc123`).\n * @example\n * const { buckets, totals } = await admin.requests.statsForMethod('mth_abc123');\n */\nexport function statsForMethod(\n ctx: AdminContext,\n methodId: string,\n params: MetricsWindowParams = {},\n) {\n return call<RequestsStatsMethodResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/metrics/methods/${seg(methodId)}${qs(params)}`,\n );\n}\n","/**\n * App secrets operations: list, read, write, and delete encrypted key/value pairs.\n *\n * `SecretsSetParams` allows `null` values to explicitly clear an environment's\n * stored value (mapped from the CLI's `--dev-clear` / `--prod-clear` flags).\n * The key presence check (at least one of devValue/prodValue) stays in the skin.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, seg } from '../http.js';\nimport type {\n SecretsListResult,\n SecretsGetResult,\n SecretsSetResult,\n SecretsDeleteResult,\n} from '../types/secrets.js';\n\n/**\n * List all secret keys for the app (values are not returned — use `get` to\n * retrieve decrypted values for a specific key).\n *\n * @example\n * const { secrets } = await admin.secrets.list();\n * const withProd = secrets.filter((s) => s.hasProdValue);\n */\nexport function list(ctx: AdminContext) {\n return call<SecretsListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/secrets`,\n );\n}\n\n/**\n * Get the decrypted dev and prod values for a secret key.\n *\n * This call is audited as a `secret.reveal` event on the workspace.\n *\n * @throws AdminApiError `secret_not_found` (404).\n * @example\n * const { devValue, prodValue } = await admin.secrets.get('STRIPE_SECRET_KEY');\n */\nexport function get(ctx: AdminContext, key: string) {\n return call<SecretsGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/secrets/${seg(key)}`,\n );\n}\n\nexport interface SecretsSetParams {\n /**\n * Value for the dev environment; `null` clears the stored dev value;\n * omitting the field leaves the dev value unchanged.\n */\n devValue?: string | null;\n /**\n * Value for the prod environment; `null` clears the stored prod value;\n * omitting the field leaves the prod value unchanged.\n */\n prodValue?: string | null;\n}\n\n/**\n * Create or update a secret's value for dev and/or prod (merge semantics —\n * environments you omit are not changed).\n *\n * Active sandboxes are invalidated so they reprovision with the updated values.\n * Key must match `[A-Z][A-Z0-9_]{0,99}` (validated server-side).\n *\n * @throws AdminApiError `invalid_key` (400) — the key does not match\n * `[A-Z][A-Z0-9_]{0,99}`; `missing_value` (400) — neither devValue nor\n * prodValue was provided.\n * @example\n * await admin.secrets.set('STRIPE_SECRET_KEY', { devValue: 'sk_test_…', prodValue: 'sk_live_…' });\n * // Clear just the dev value:\n * await admin.secrets.set('STRIPE_SECRET_KEY', { devValue: null });\n */\nexport function set(ctx: AdminContext, key: string, params: SecretsSetParams) {\n const body: Record<string, unknown> = {};\n if ('devValue' in params) {\n body.devValue = params.devValue;\n }\n if ('prodValue' in params) {\n body.prodValue = params.prodValue;\n }\n return call<SecretsSetResult>(\n ctx,\n 'PUT',\n `/_internal/v2/apps/${ctx.appId}/secrets/${seg(key)}`,\n body,\n );\n}\n\n/**\n * Delete a secret entirely (removes both dev and prod values).\n *\n * Active sandboxes are invalidated. Silently succeeds if the key does not\n * exist.\n *\n * @example\n * await admin.secrets.del('OLD_KEY');\n */\nexport function del(ctx: AdminContext, key: string) {\n return call<SecretsDeleteResult>(\n ctx,\n 'DELETE',\n `/_internal/v2/apps/${ctx.appId}/secrets/${seg(key)}`,\n );\n}\n","/**\n * App settings operations: get and update the app's v2_settings jsonb.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/settings.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call } from '../http.js';\nimport type { SettingsResult, V2AppSettings } from '../types/settings.js';\n\n/**\n * Get all V2AppSettings for this app.\n *\n * Returns the current state of every dashboard-controlled toggle: signup\n * allowlist, test accounts, frame-ancestors, disposable-email blocking,\n * telemetry capture, and more. See `V2AppSettings` in `types/settings.ts`\n * for the full field set and per-field semantics.\n *\n * @example\n * const settings = await admin.settings.getSettings();\n * console.log(settings.blockDisposableEmails);\n */\nexport function getSettings(ctx: AdminContext): Promise<V2AppSettings> {\n return call<SettingsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/settings/v2`,\n ).then((res) => res.settings ?? {});\n}\n\n// `partial` stays loose on purpose: `settings set` forwards an arbitrary\n// user-supplied key for the route to validate, so a V2AppSettings-typed body\n// would reject exactly the escape hatch the command exists to provide.\n/**\n * Apply a partial update to the app's V2AppSettings.\n *\n * The server validates and normalizes security-shaped values before writing:\n * signup-allowlist entries must be `*@domain.com` or `user@domain.com`; test\n * accounts require a valid email or E.164 identifier and a 6-digit code (max\n * 5 entries); frame-ancestor entries must be exact `https://` origins (max\n * 25). Unknown keys in `partial` are silently dropped. Returns the full\n * settings after the update.\n *\n * `partial` is deliberately untyped: the CLI escape-hatch `settings set`\n * forwards arbitrary keys for the route to validate; a strict `V2AppSettings`\n * body would reject that use.\n *\n * @throws AdminApiError `invalid_signup_allowlist` (400) — malformed entry or\n * non-array value; `invalid_test_accounts` (400) — invalid identifier/code,\n * duplicate identifier, or over the 5-entry cap;\n * `invalid_frame_ancestors` (400) — not a valid https origin or over the\n * 25-entry cap.\n * @example\n * const updated = await admin.settings.updateSettings({ blockDisposableEmails: false });\n */\nexport function updateSettings(\n ctx: AdminContext,\n partial: Record<string, unknown>,\n): Promise<V2AppSettings> {\n return call<SettingsResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/v2`,\n partial,\n ).then((res) => res.settings ?? {});\n}\n","/**\n * App users operations: list, role management, API key lifecycle.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/users.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n UsersListResult,\n UsersSetRoleResult,\n UsersCreateApiKeyResult,\n UsersRevokeApiKeyResult,\n} from '../types/users.js';\n\nexport interface UsersListParams {\n /** Max users to return per page (server default 50, clamped to 200). */\n limit?: number;\n /** Zero-based page offset. */\n offset?: number;\n}\n\n/**\n * All app-managed users with their roles and masked API-key status.\n *\n * @example\n * const { users } = await admin.users.list({ limit: 20 });\n * const admins = users.filter((u) => u.roles.includes('admin'));\n */\nexport function list(ctx: AdminContext, params: UsersListParams = {}) {\n return call<UsersListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/users${qs(params)}`,\n );\n}\n\n/**\n * Replace a user's role set with a single role.\n *\n * Sends `roles: [role]` — the array replaces the user's entire prior role\n * list. The updated user record is returned.\n *\n * @throws AdminApiError `user_not_found` (404) — the user does not belong to\n * this app; `invalid_roles` (400) — the roles field was malformed.\n * @example\n * const { user } = await admin.users.setRole('usr_abc123', 'admin');\n */\nexport function setRole(ctx: AdminContext, userId: string, role: string) {\n return call<UsersSetRoleResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/users/${seg(userId)}/roles`,\n { roles: [role] },\n );\n}\n\n/**\n * Generate an API key for a user; the full plaintext `key` is returned exactly\n * once — only the masked form is stored after this call.\n *\n * Requires the app's live release to have the `api-key` auth method enabled.\n *\n * @throws AdminApiError `user_not_found` (404) — the user does not belong to\n * this app; `auth_method_not_enabled` (400) — the `api-key` auth method is\n * not enabled on the app's live release.\n * @example\n * const { key } = await admin.users.createApiKey('usr_abc123');\n * // Store `key` immediately — it cannot be retrieved again.\n */\nexport function createApiKey(ctx: AdminContext, userId: string) {\n return call<UsersCreateApiKeyResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/users/${seg(userId)}/api-key`,\n );\n}\n\n/**\n * Revoke a user's API key; takes effect immediately — in-flight requests using\n * the key will fail.\n *\n * @throws AdminApiError `user_not_found` (404) — the user does not belong to\n * this app.\n * @example\n * await admin.users.revokeApiKey('usr_abc123');\n */\nexport function revokeApiKey(ctx: AdminContext, userId: string) {\n return call<UsersRevokeApiKeyResult>(\n ctx,\n 'DELETE',\n `/_internal/v2/apps/${ctx.appId}/users/${seg(userId)}/api-key`,\n );\n}\n","/**\n * Voice operations: phone numbers, sessions, and policy settings.\n *\n * `findNumberId` resolves a user-supplied E.164 string to a row id (list →\n * normalize → match). It throws a plain Error with the exact historical\n * message if not found — entry-point catch prints it identically to `fatal()`.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n VoiceNumbersListResult,\n VoiceNumbersSearchResult,\n VoiceNumbersBuyResult,\n VoiceNumbersReleaseResult,\n VoiceNumbersSetNameResult,\n VoiceSessionsListResult,\n VoiceSessionGetResult,\n VoiceSettingsGetResult,\n VoiceSettingsSetResult,\n} from '../types/voice.js';\n\n// ---------------------------------------------------------------------------\n// Phone numbers\n// ---------------------------------------------------------------------------\n\n/**\n * Canonicalize a user-typed phone number to E.164 before matching: strip\n * formatting, accept bare 10/11-digit US numbers.\n */\nfunction normalizeE164(input: string): string {\n const stripped = input.replace(/[\\s().-]/g, '');\n if (/^\\d{10}$/.test(stripped)) {\n return `+1${stripped}`;\n }\n if (/^1\\d{10}$/.test(stripped)) {\n return `+${stripped}`;\n }\n return stripped;\n}\n\n/**\n * All dedicated phone numbers attached to the app.\n *\n * Lazily reconciles any pending orders so callers can poll this until a\n * `pending` number converges to `active` or `failed`.\n *\n * @example\n * const { numbers } = await admin.voice.numbersList();\n * const active = numbers.filter((n) => n.status === 'active');\n */\nexport function numbersList(ctx: AdminContext) {\n return call<VoiceNumbersListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/settings/voice-phone-numbers`,\n );\n}\n\nexport interface NumbersSearchParams {\n /** US 3-digit area code to filter by. */\n areaCode?: string;\n /** City name to filter by. */\n locality?: string;\n /** State or region code (e.g. `CA`). */\n administrativeArea?: string;\n /** Max results to return (server clamps to 50). */\n limit?: number;\n}\n\n/**\n * Search available US numbers by area code or locality.\n *\n * Results are Telnyx availability snapshots — they are not reservations and\n * may be gone by the time `numbersBuy` is called.\n *\n * @throws AdminApiError `missing_search_filter` (400) — neither areaCode nor\n * locality provided; `invalid_area_code` (400) — area code is not 3 digits;\n * `telnyx_not_configured` (422) — phone numbers are not available on this\n * platform host.\n * @example\n * const { results } = await admin.voice.numbersSearch({ areaCode: '310', limit: 5 });\n */\nexport function numbersSearch(ctx: AdminContext, params: NumbersSearchParams) {\n return call<VoiceNumbersSearchResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/voice-phone-numbers/search`,\n {\n areaCode: params.areaCode,\n locality: params.locality,\n administrativeArea: params.administrativeArea,\n limit: params.limit,\n },\n );\n}\n\nexport interface NumbersBuyParams {\n /** E.164 US number to purchase, from a prior `numbersSearch` result. */\n phoneNumber: string;\n /** City name label — display metadata only, echoed from the search result. */\n locality?: string;\n /** State/region label — display metadata only, echoed from the search result. */\n administrativeArea?: string;\n /** Carrier monthly cost string (e.g. `\"1.00000\"`) — display metadata only. */\n monthlyCost?: string;\n}\n\n/**\n * Buy and attach a dedicated phone number to the app ($1/month billed to the\n * workspace starting immediately — always confirm with the user before calling).\n *\n * The number is both the outbound caller-ID for `voice.call()` and the app's\n * inbound line. A `pending` status usually activates within seconds; poll\n * `numbersList` to confirm. One number per app in v1 — release before switching.\n *\n * @throws AdminApiError `invalid_phone_number` (400) — not a valid +1 E.164\n * US number; `number_already_assigned` (422) — this app already has a live\n * number; `number_unavailable` (422) — the number is no longer available;\n * `insufficient_credits` (402) — the workspace balance is too low;\n * `telnyx_not_configured` (422) — phone numbers unavailable on this host.\n * @example\n * const { number } = await admin.voice.numbersBuy({\n * phoneNumber: '+13105551234',\n * locality: 'Los Angeles',\n * administrativeArea: 'CA',\n * monthlyCost: '1.00000',\n * });\n */\nexport function numbersBuy(ctx: AdminContext, params: NumbersBuyParams) {\n return call<VoiceNumbersBuyResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/voice-phone-numbers`,\n {\n phoneNumber: params.phoneNumber,\n locality: params.locality,\n administrativeArea: params.administrativeArea,\n monthlyCost: params.monthlyCost,\n },\n );\n}\n\n/**\n * Resolve a phone-number row id from its E.164 value by listing and matching.\n * Throws with the exact historical message if not found.\n */\nasync function findNumberId(ctx: AdminContext, e164: string): Promise<string> {\n const normalized = normalizeE164(e164);\n const res = await numbersList(ctx);\n const entry = (res.numbers ?? []).find((n) => n.e164 === normalized);\n if (!entry) {\n throw new Error(`No phone number \"${e164}\" on this app`);\n }\n return entry.id;\n}\n\n/**\n * Release a dedicated phone number from the app (permanent).\n *\n * The monthly rental stops immediately (no refund for the current month),\n * the carrier quarantines the number for ~15 days, and both inbound calls\n * and outbound `voice.call()` stop working until a new number is attached.\n *\n * @param e164 The phone number in E.164 or bare 10-digit US format.\n * @throws Error `No phone number \"${e164}\" on this app` when not found;\n * AdminApiError `number_not_found` (404) if the resolved id has gone stale;\n * `order_in_progress` (422) — the purchase is still settling, try again in\n * a minute.\n * @example\n * await admin.voice.numbersRelease('+13105551234');\n */\nexport async function numbersRelease(ctx: AdminContext, e164: string) {\n const id = await findNumberId(ctx, e164);\n return call<VoiceNumbersReleaseResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/voice-phone-numbers/${seg(id)}/release`,\n );\n}\n\n/**\n * Set or clear the outbound caller-ID display name (CNAM) for a phone number.\n *\n * CNAM must be 1–15 letters, numbers, or spaces; carrier propagation takes\n * 12–72 hours and display is ultimately the receiving carrier's call. Pass an\n * empty string to remove the listing.\n *\n * @param e164 The phone number in E.164 or bare 10-digit US format.\n * @param displayName 1–15 character CNAM string, or `\"\"` to remove the listing.\n * @throws Error `No phone number \"${e164}\" on this app` when not found;\n * AdminApiError `number_not_found` (404) if the resolved id has gone stale;\n * `number_not_active` (422) — the number must be active before setting a\n * display name; `invalid_display_name` (400) — value is not 1–15 letters,\n * numbers, or spaces.\n * @example\n * await admin.voice.numbersSetName('+13105551234', 'Acme Corp');\n * // Clear the listing:\n * await admin.voice.numbersSetName('+13105551234', '');\n */\nexport async function numbersSetName(\n ctx: AdminContext,\n e164: string,\n displayName: string,\n) {\n const id = await findNumberId(ctx, e164);\n return call<VoiceNumbersSetNameResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/voice-phone-numbers/${seg(id)}/display-name`,\n { displayName },\n );\n}\n\n// ---------------------------------------------------------------------------\n// Sessions\n// ---------------------------------------------------------------------------\n\nexport interface SessionsListParams {\n /** Max sessions per page (default 20, server clamps to 100). */\n limit?: number;\n /** Pagination cursor from a prior page's `nextCursor`. */\n cursor?: string;\n}\n\n/**\n * Call log for the app (web, phone-out, phone-in sessions), newest first.\n *\n * Returns cursored pages; pass `nextCursor` from one page as `cursor` for the\n * next. Transcripts are not included — fetch a session with `sessionsGet` for\n * the full transcript.\n *\n * @example\n * const { sessions, nextCursor } = await admin.voice.sessionsList({ limit: 20 });\n */\nexport function sessionsList(\n ctx: AdminContext,\n params: SessionsListParams = {},\n) {\n return call<VoiceSessionsListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/voice-sessions${qs(params)}`,\n );\n}\n\n/**\n * One voice session with full transcript and cost breakdown.\n *\n * `transcript` is the primary tool for debugging and iterating on a voice\n * persona. `cost` is `null` while the session is still active.\n *\n * @throws AdminApiError `session_not_found` (404).\n * @example\n * const session = await admin.voice.sessionsGet('4f6c…');\n * console.log(session.transcript);\n */\nexport function sessionsGet(ctx: AdminContext, sessionId: string) {\n return call<VoiceSessionGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/voice-sessions/${seg(sessionId)}`,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Settings\n// ---------------------------------------------------------------------------\n\n/**\n * Voice policy for the app: owner-set overrides, the effective (default-filled\n * and ceiling-clamped) values that apply at session mint, and the platform\n * ceilings.\n *\n * @example\n * const { settings, effective, ceilings } = await admin.voice.settingsGet();\n */\nexport function settingsGet(ctx: AdminContext) {\n return call<VoiceSettingsGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/voice-settings`,\n );\n}\n\nexport interface VoiceSettingsSetParams {\n /** Cap on simultaneous sessions across all visitors (platform ceiling applies). */\n maxConcurrentSessions?: number;\n /** Cap on simultaneous sessions per visitor. */\n maxConcurrentSessionsPerVisitor?: number;\n /** Max session duration in seconds before the session is terminated. */\n maxSessionDurationSecs?: number;\n}\n\n/**\n * Override one or more voice-policy settings for the app (merge semantics —\n * fields you omit keep their current values).\n *\n * @throws AdminApiError `invalid_voice_settings` (400) — a field value is not\n * a positive number.\n * @example\n * await admin.voice.settingsSet({ maxConcurrentSessions: 5, maxSessionDurationSecs: 600 });\n */\nexport function settingsSet(ctx: AdminContext, params: VoiceSettingsSetParams) {\n return call<VoiceSettingsSetResult>(\n ctx,\n 'PUT',\n `/_internal/v2/apps/${ctx.appId}/voice-settings`,\n {\n maxConcurrentSessions: params.maxConcurrentSessions,\n maxConcurrentSessionsPerVisitor: params.maxConcurrentSessionsPerVisitor,\n maxSessionDurationSecs: params.maxSessionDurationSecs,\n },\n );\n}\n","/**\n * The importable admin client: every CLI command as a typed method, bound to\n * one app. Namespaces mirror the CLI groups 1:1 — `remy-admin requests list`\n * is `admin.requests.list(...)` — so there is exactly one mental model.\n *\n * The client is a thin binding layer: each namespace is its ops module with\n * the AdminContext pre-applied. Ops throw AdminApiError / AdminTimeoutError;\n * nothing here prints, exits, or streams (the CLI-only streaming passthroughs\n * live in cliStream.ts and are deliberately not exposed).\n */\n\nimport {\n DEFAULT_BASE_URL,\n loadWorkspaceAppId,\n type AdminContext,\n} from './ctx.js';\n\nimport * as agent from './ops/agent.js';\nimport * as tasks from './ops/tasks.js';\nimport * as analytics from './ops/analytics.js';\nimport * as appEvents from './ops/events.js';\nimport * as crashes from './ops/crashes.js';\nimport * as cron from './ops/cron.js';\nimport * as data from './ops/data.js';\nimport * as dataSources from './ops/dataSources.js';\nimport * as dataSourceJobs from './ops/dataSourceJobs.js';\nimport * as dataSourceConnectors from './ops/dataSourceConnectors.js';\nimport * as dataSourceEvals from './ops/dataSourceEvals.js';\nimport * as dataSourceMappers from './ops/dataSourceMappers.js';\nimport * as db from './ops/db.js';\nimport * as diagnostics from './ops/diagnostics.js';\nimport * as domains from './ops/domains.js';\nimport * as email from './ops/email.js';\nimport * as files from './ops/files.js';\nimport * as infra from './ops/infra.js';\nimport * as issues from './ops/issues.js';\nimport * as jewels from './ops/jewels.js';\nimport * as methods from './ops/methods.js';\nimport * as prerender from './ops/prerender.js';\nimport * as qaRecordings from './ops/qaRecordings.js';\nimport * as releases from './ops/releases.js';\nimport * as requests from './ops/requests.js';\nimport * as secrets from './ops/secrets.js';\nimport * as settings from './ops/settings.js';\nimport * as users from './ops/users.js';\nimport * as voice from './ops/voice.js';\n\nexport interface AdminClientOptions {\n /** Org-scoped `sk_` API key. Falls back to MINDSTUDIO_API_KEY. */\n apiKey?: string;\n /**\n * The app to manage. Falls back to the workspace's mindstudio.json —\n * pass explicitly anywhere that file doesn't exist.\n */\n appId?: string;\n /** API origin. Falls back to MINDSTUDIO_BASE_URL, then the production default. */\n baseUrl?: string;\n}\n\n/** An ops module with the AdminContext pre-applied to every function. */\ntype BoundOps<T> = {\n [\n K in keyof T as T[K] extends (\n ctx: AdminContext,\n ...args: never[]\n ) => unknown\n ? K\n : never\n ]: T[K] extends (ctx: AdminContext, ...args: infer A) => infer R\n ? (...args: A) => R\n : never;\n};\n\nfunction bindOps<T extends object>(ops: T, ctx: AdminContext): BoundOps<T> {\n const bound: Record<string, unknown> = {};\n for (const [name, value] of Object.entries(ops)) {\n if (typeof value === 'function') {\n bound[name] = (...args: unknown[]) => value(ctx, ...args);\n }\n }\n return bound as BoundOps<T>;\n}\n\nfunction resolveOptions(options: AdminClientOptions): AdminContext {\n const apiKey = options.apiKey ?? process.env['MINDSTUDIO_API_KEY'] ?? '';\n if (!apiKey) {\n throw new Error(\n 'No API key: pass { apiKey } to createAdminClient or set MINDSTUDIO_API_KEY',\n );\n }\n return {\n apiKey,\n // loadWorkspaceAppId throws its own precise message if there's no\n // mindstudio.json to fall back to.\n appId: options.appId ?? loadWorkspaceAppId(),\n baseUrl:\n options.baseUrl ?? process.env['MINDSTUDIO_BASE_URL'] ?? DEFAULT_BASE_URL,\n };\n}\n\nfunction buildClient(ctx: AdminContext) {\n return {\n /** The resolved context this client is bound to. */\n context: ctx as Readonly<AdminContext>,\n /**\n * A sibling client for another app, sharing credentials.\n *\n * The app we came from becomes the origin, so a write through the returned\n * client records which app acted — the same rule the CLI's `--app` follows.\n * Chaining `forApp` twice keeps the FIRST app as the origin, since that is\n * the one whose workspace this code is running in.\n */\n forApp(appId: string) {\n return buildClient({\n ...ctx,\n appId,\n originAppId:\n appId === ctx.appId\n ? ctx.originAppId\n : (ctx.originAppId ?? ctx.appId),\n });\n },\n\n agent: bindOps(agent, ctx),\n tasks: bindOps(tasks, ctx),\n analytics: bindOps(analytics, ctx),\n events: bindOps(appEvents, ctx),\n crashes: bindOps(crashes, ctx),\n cron: bindOps(cron, ctx),\n data: bindOps(data, ctx),\n dataSources: bindOps(dataSources, ctx),\n dataSourceJobs: bindOps(dataSourceJobs, ctx),\n dataSourceConnectors: bindOps(dataSourceConnectors, ctx),\n dataSourceEvals: bindOps(dataSourceEvals, ctx),\n dataSourceMappers: bindOps(dataSourceMappers, ctx),\n db: bindOps(db, ctx),\n diagnostics: bindOps(diagnostics, ctx),\n domains: bindOps(domains, ctx),\n email: {\n ...bindOps(email, ctx),\n // Hand-bound: these are generic over the direction ('sending' |\n // 'inbound') and bindOps' mapped type would erase the generic,\n // collapsing every result to the cross-direction union.\n listDomains: <D extends email.DomainDirection>(direction: D) =>\n email.listDomains(ctx, direction),\n checkDomain: <D extends email.DomainDirection>(\n direction: D,\n domain: string,\n ) => email.checkDomain(ctx, direction, domain),\n addDomain: <D extends email.DomainDirection>(\n direction: D,\n domain: string,\n ) => email.addDomain(ctx, direction, domain),\n verifyDomain: <D extends email.DomainDirection>(\n direction: D,\n domain: string,\n ) => email.verifyDomain(ctx, direction, domain),\n removeDomain: <D extends email.DomainDirection>(\n direction: D,\n domain: string,\n ) => email.removeDomain(ctx, direction, domain),\n },\n files: bindOps(files, ctx),\n infra: bindOps(infra, ctx),\n issues: bindOps(issues, ctx),\n jewels: bindOps(jewels, ctx),\n methods: bindOps(methods, ctx),\n prerender: bindOps(prerender, ctx),\n qaRecordings: bindOps(qaRecordings, ctx),\n releases: bindOps(releases, ctx),\n requests: bindOps(requests, ctx),\n secrets: bindOps(secrets, ctx),\n settings: bindOps(settings, ctx),\n users: bindOps(users, ctx),\n voice: bindOps(voice, ctx),\n };\n}\n\nexport type AdminClient = ReturnType<typeof buildClient>;\n\n/**\n * Create a client bound to one app.\n *\n * ```ts\n * import { createAdminClient } from '@madewithremy/admin';\n * const admin = createAdminClient({ apiKey: 'sk_…', appId: 'app_…' });\n * const { releases } = await admin.releases.list({ limit: 5 });\n * ```\n */\nexport function createAdminClient(\n options: AdminClientOptions = {},\n): AdminClient {\n return buildClient(resolveOptions(options));\n}\n","/**\n * @madewithremy/admin — manage production Remy apps from code.\n *\n * Two ways in:\n * import admin from '@madewithremy/admin'; // lazy, env-configured\n * import { createAdminClient } from '@madewithremy/admin'; // explicit\n *\n * Every CLI command (`remy-admin <group> <sub>`) is a client method\n * (`admin.<group>.<sub>()`). Ops throw AdminApiError / AdminTimeoutError.\n */\n\nexport {\n createAdminClient,\n type AdminClient,\n type AdminClientOptions,\n} from './client.js';\nexport type { AdminContext } from './ctx.js';\nexport { AdminApiError, AdminTimeoutError } from './errors.js';\nexport * from './types/index.js';\n\nimport { createAdminClient, type AdminClient } from './client.js';\n\n// ---------------------------------------------------------------------------\n// Lazy default singleton\n// ---------------------------------------------------------------------------\n\n/**\n * Lazy default client — created on first property access from the environment\n * (MINDSTUDIO_API_KEY, MINDSTUDIO_BASE_URL, the workspace's mindstudio.json), so the\n * import itself is safe anywhere; resolution errors surface at first use.\n *\n * ```ts\n * import admin from '@madewithremy/admin';\n * const { jobs } = await admin.cron.list({});\n * ```\n */\nlet _default: AdminClient;\nexport const admin: AdminClient = new Proxy({} as AdminClient, {\n get(_, prop) {\n _default ??= createAdminClient();\n const value = Reflect.get(_default, prop, _default);\n return typeof value === 'function' ? value.bind(_default) : value;\n },\n});\n\nexport default admin;\n"],"mappings":";;;;;;;AASA,OAAO,QAAQ;AACf,OAAO,UAAU;;;ACAV,IAAM,gBACX,QAAQ,IAAI,eAAe,KAAK;AAO3B,IAAM,cACX,QAAQ,IAAI,kBAAkB,KAAK;;;ACFrC,OAAO,WAAW;AAUX,SAAS,IAAI,KAAsB;AACxC,SAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AACxD;AAMO,SAAS,gBAAmB,KAA6B;AAC9D,MAAI;AACJ,MAAI;AACF,WAAO,EAAE,IAAI,MAAM,OAAO,KAAK,MAAM,GAAG,GAAQ,UAAU,MAAM;AAAA,EAClE,SAAS,KAAK;AACZ,kBAAc,IAAI,GAAG;AAAA,EACvB;AAEA,MAAI;AACF,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO,MAAM,MAAM,GAAG;AAAA,MACtB,UAAU;AAAA,MACV,OAAO;AAAA,IACT;AAAA,EACF,SAAS,KAAK;AAKZ,WAAO,EAAE,IAAI,OAAO,OAAO,IAAI,GAAG,GAAG,UAAU,MAAM;AAAA,EACvD;AACF;;;AFtBO,IAAM,mBAAmB;AAQzB,SAAS,mBAAmB,eAAe,eAAuB;AACvE,QAAM,eAAe,KAAK,KAAK,cAAc,iBAAiB;AAC9D,MAAI;AACJ,MAAI;AACF,UAAM,GAAG,aAAa,cAAc,OAAO;AAAA,EAC7C,SAAS,KAAU;AACjB,QAAI,IAAI,SAAS,UAAU;AACzB,YAAM,IAAI,MAAM,gCAAgC,YAAY,EAAE;AAAA,IAChE;AACA,UAAM,IAAI,MAAM,mCAAmC,IAAI,OAAO,EAAE;AAAA,EAClE;AAGA,QAAM,SAAS,gBAAoC,GAAG;AACtD,MAAI,CAAC,OAAO,IAAI;AACd,UAAM,IAAI,MAAM,oCAAoC,OAAO,KAAK,EAAE;AAAA,EACpE;AACA,MAAI,CAAC,OAAO,MAAM,OAAO;AACvB,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC3D;AACA,SAAO,OAAO,MAAM;AACtB;;;AGhEA;AAAA;AAAA;AAAA;AAAA;;;ACwEO,IAAM,gBAAN,cAA4B,MAAM;AAAA,EACvC,YACW,QACAA,OACAC,SACA,MACT;AACA,UAAM,OAAO,MAAM,IAAID,KAAI,aAAaC,OAAM,KAAK,KAAK,UAAU,IAAI,CAAC,EAAE;AALhE;AACA,gBAAAD;AACA,kBAAAC;AACA;AAGT,SAAK,OAAO;AAAA,EACd;AAAA,EAPW;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAKb;AAGO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAC3C,YAAY,OAAe,WAAmB;AAC5C,UAAM,GAAG,KAAK,oBAAoB,YAAY,GAAI,GAAG;AACrD,SAAK,OAAO;AAAA,EACd;AACF;;;AC3EO,IAAM,qBAAqB;AAM3B,IAAM,qBAAqB,IAAI;AAO/B,SAAS,iBAAiB,KAAuB;AACtD,MAAI,eAAe,eAAe;AAChC,WAAO,IAAI,UAAU;AAAA,EACvB;AACA,MAAI,eAAe,mBAAmB;AACpC,WAAO;AAAA,EACT;AAEA,SAAO,eAAe;AACxB;AAEO,IAAM,oBAAoB;AAG1B,SAAS,IAAI,OAAgC;AAClD,SAAO,mBAAmB,OAAO,KAAK,CAAC;AACzC;AAUO,SAAS,GAAG,QAAwB;AACzC,QAAMC,UAAS,IAAI,gBAAgB;AACnC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,QAAI,UAAU,UAAa,UAAU,MAAM;AACzC;AAAA,IACF;AAGA,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,iBAAW,SAAS,OAAO;AACzB,QAAAA,QAAO,OAAO,KAAK,OAAO,KAAK,CAAC;AAAA,MAClC;AACA;AAAA,IACF;AACA,IAAAA,QAAO,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,EAC/B;AACA,QAAM,OAAOA,QAAO,SAAS;AAC7B,SAAO,OAAO,IAAI,IAAI,KAAK;AAC7B;AAEA,SAAS,YAAY,KAA2C;AAC9D,SAAO;AAAA,IACL,eAAe,UAAU,IAAI,MAAM;AAAA,IACnC,gBAAgB;AAAA,EAClB;AACF;AASA,eAAsB,SAAS,KAA6B;AAC1D,MAAI,IAAI,WAAW,KAAK;AACtB,WAAO,EAAE,IAAI,MAAM,QAAQ,IAAI;AAAA,EACjC;AACA,QAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,MAAI,CAAC,KAAK,KAAK,GAAG;AAChB,WAAO,EAAE,IAAI,MAAM,QAAQ,IAAI,OAAO;AAAA,EACxC;AACA,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO,EAAE,KAAK,KAAK;AAAA,EACrB;AACF;AAEA,eAAsB,iBACpB,KACA,MACA,WACA,OACmB;AACnB,MAAI;AACF,WAAO,MAAM,MAAM,KAAK;AAAA,MACtB,GAAG;AAAA,MACH,QAAQ,YAAY,QAAQ,SAAS;AAAA,IACvC,CAAC;AAAA,EACH,SAAS,KAAU;AACjB,QAAI,KAAK,SAAS,gBAAgB;AAChC,YAAM,IAAI,kBAAkB,OAAO,SAAS;AAAA,IAC9C;AACA,UAAM;AAAA,EACR;AACF;AASA,eAAsB,KACpB,KACA,QACA,SACA,MAGA,YAAoB,oBACR;AACZ,QAAM,MAAM,MAAM;AAAA,IAChB,GAAG,IAAI,OAAO,GAAG,OAAO;AAAA,IACxB;AAAA,MACE;AAAA,MACA,SAAS,YAAY,GAAG;AAAA,MACxB,GAAI,OAAO,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,CAAC;AAAA,IAC/C;AAAA,IACA;AAAA,IACA,OAAO,MAAM,IAAI,OAAO;AAAA,EAC1B;AAEA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,cAAc,QAAQ,SAAS,IAAI,QAAQ,MAAM,SAAS,GAAG,CAAC;AAAA,EAC1E;AAEA,SAAO,SAAS,GAAG;AACrB;AAOA,eAAsB,QACpB,KACA,QACA,SACmD;AACnD,QAAM,MAAM,MAAM;AAAA,IAChB,GAAG,IAAI,OAAO,GAAG,OAAO;AAAA,IACxB,EAAE,QAAQ,SAAS,YAAY,GAAG,EAAE;AAAA,IACpC;AAAA,IACA,OAAO,MAAM,IAAI,OAAO;AAAA,EAC1B;AACA,SAAO,EAAE,IAAI,IAAI,IAAI,QAAQ,IAAI,QAAQ,MAAM,MAAM,SAAS,GAAG,EAAE;AACrE;;;AF1IO,SAAS,YAAY,KAAmB,SAA4B,CAAC,GAAG;AAC7E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,iBAAiB,GAAG,MAAM,CAAC;AAAA,EAC5D;AACF;AAgBO,SAAS,WAAW,KAAmB,UAAkB;AAC9D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,kBAAkB,IAAI,QAAQ,CAAC;AAAA,EAChE;AACF;;;AG/DA;AAAA;AAAA;AAAA;AAAA;AAiCO,SAAS,KAAK,KAAmB,SAA0B,CAAC,GAAG;AACpE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,eAAe,GAAG,MAAM,CAAC;AAAA,EAC1D;AACF;AAkBO,SAAS,IAAI,KAAmB,SAAiB;AACtD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,gBAAgB,IAAI,OAAO,CAAC;AAAA,EAC7D;AACF;;;AC/DA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiKO,SAAS,MAAM,KAAmB,MAA+B;AACtE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B;AAAA,EACF;AACF;AAeO,SAAS,MAAM,KAAmB,SAAgC;AACvE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B,EAAE,QAAQ;AAAA,EACZ;AACF;AAaO,SAAS,QAAQ,KAAmB,SAAwB,CAAC,GAAG;AACrE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,oBAAoB,GAAG,MAAM,CAAC;AAAA,EAC/D;AACF;AAWO,SAAS,IAAI,KAAmB,SAAoB,CAAC,GAAG;AAC7D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,gBAAgB,GAAG,MAAM,CAAC;AAAA,EAC3D;AACF;AAWO,SAAS,KAAK,KAAmB;AACtC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,EACjC;AACF;AAaO,SAAS,UAAU,KAAmB,SAA0B,CAAC,GAAG;AACzE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,uBAAuB,GAAG,MAAM,CAAC;AAAA,EAClE;AACF;AAgBO,SAAS,SAAS,KAAmB,QAAwB;AAClE,QAAM,EAAE,MAAM,GAAG,KAAK,IAAI;AAC1B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,sBAAsB,IAAI,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;AAAA,EAC3E;AACF;;;AC7RA;AAAA;AAAA;AAAA;AAAA;AA4CO,SAAS,aACd,KACA,SAA4B,CAAC,GAC7B;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,mBAAmB,GAAG,MAAM,CAAC;AAAA,EAC9D;AACF;AAoBO,SAAS,QAAQ,KAAmB,QAA6B;AACtE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B,EAAE,UAAU,OAAO,UAAU,MAAM,OAAO,MAAM,OAAO,OAAO,MAAM;AAAA,EACtE;AACF;;;AChFA;AAAA;AAAA,aAAAC;AAAA,EAAA,YAAAC;AAAA,EAAA;AAAA;AAAA;AAiEO,SAASC,MAAK,KAAmB,SAA4B,CAAC,GAAG;AACtE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,mBAAmB,GAAG,MAAM,CAAC;AAAA,EAC9D;AACF;AAWO,SAAS,YACd,KACA,aACA,SAAmC,CAAC,GACpC;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,oBAAoB,IAAI,WAAW,CAAC,UAAU,GAAG,MAAM,CAAC;AAAA,EACzF;AACF;AAYO,SAASC,KAAI,KAAmB,SAAiB;AACtD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,2BAA2B,IAAI,OAAO,CAAC;AAAA,EACxE;AACF;AAWO,SAAS,MAAM,KAAmB,SAA6B,CAAC,GAAG;AACxE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,mCAAmC,GAAG,MAAM,CAAC;AAAA,EAC9E;AACF;;;AC/HA;AAAA;AAAA,cAAAC;AAAA,EAAA;AAAA;AA4BO,SAASC,MAAK,KAAmB,SAAyB,CAAC,GAAG;AACnE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,iBAAiB,GAAG,MAAM,CAAC;AAAA,EAC5D;AACF;AAgBO,SAAS,IAAI,KAAmB,OAAe;AACpD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC;AAAA,EACpD;AACF;;;ACxDA;AAAA;AAAA;AAAA;AAAA;AA0CO,SAAS,YAAY,KAAmB,SAA4B,CAAC,GAAG;AAC7E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B;AAAA,MACE,SAAS;AAAA,MACT,GAAI,OAAO,YAAY,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;AAAA,IAC5D;AAAA,EACF;AACF;AAkCO,SAAS,aACd,KACA,SAA6B,CAAC,GAC9B;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B;AAAA,MACE,SAAS;AAAA,MACT,GAAI,OAAO,WAAW,EAAE,MAAM,WAAW,IAAI,CAAC;AAAA,MAC9C,GAAI,OAAO,YAAY,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;AAAA,IAC5D;AAAA,EACF;AACF;;;ACpGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA,SAAS,kBAAkB;;;ACCpB,SAAS,MAAM,IAA2B;AAC/C,SAAO,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAC7C;;;ACsBA,eAAsB,UACpB,MACA,WACA,SACyB;AACzB,QAAMC,SAAQ,KAAK,IAAI;AACvB,MAAI,UAAUA;AACd,MAAI;AACJ,MAAI,iBAAgC;AAEpC,SAAO,MAAM;AACX,QAAI;AACJ,QAAI;AACF,cAAQ,MAAM,KAAK;AACnB,uBAAiB;AAAA,IACnB,SAAS,KAAK;AACZ,UAAI,CAAC,iBAAiB,GAAG,GAAG;AAC1B,cAAM;AAAA,MACR;AACA,yBAAmB,KAAK,IAAI;AAC5B,UAAI,KAAK,IAAI,IAAI,iBAAiB,oBAAoB;AACpD,cAAM;AAAA,MACR;AACA,cAAQ;AAAA,QACN,yCAAoC,eAAeA,MAAK,CAAC;AAAA,MAC3D;AACA,YAAM,MAAM,QAAQ,MAAM;AAC1B;AAAA,IACF;AAEA,QAAI,UAAU,KAAK,GAAG;AACpB,aAAO,EAAE,SAAS,MAAM,MAAM;AAAA,IAChC;AACA,QAAI,QAAQ,aAAa;AACvB,YAAM,MAAM,QAAQ,YAAY,KAAK;AACrC,UAAI,QAAQ,SAAS;AACnB,kBAAU;AACV,kBAAU,KAAK,IAAI;AAAA,MACrB;AAAA,IACF;AACA,QAAI,KAAK,IAAI,IAAI,UAAU,QAAQ,WAAW;AAC5C,aAAO,EAAE,SAAS,OAAO,MAAM;AAAA,IACjC;AACA,QAAI,QAAQ,UAAU;AACpB,cAAQ,aAAa,QAAQ,SAAS,OAAOA,MAAK,CAAC;AAAA,IACrD;AACA,UAAM,MAAM,QAAQ,MAAM;AAAA,EAC5B;AACF;AAEO,SAAS,eAAeA,QAAuB;AACpD,SAAO,KAAK,OAAO,KAAK,IAAI,IAAIA,UAAS,GAAI;AAC/C;AAGO,SAAS,SAAS,WAAmB,OAAuB;AACjE,SAAO,mBAAmB,KAAK,MAAM,YAAY,GAAI,CAAC,KAAK,KAAK;AAClE;;;AC5EA,IAAM,SAAS,QAAQ,OAAO,UAAU;AAYjC,SAAS,YACd,KACA,MAAM,KAAK,IAAI,GACA;AACf,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AACA,QAAM,UAAU,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,MAAM,GAAG,IAAI,OAAO,GAAM,CAAC;AACxE,MAAI,UAAU,IAAI;AAChB,WAAO,SAAS,OAAO;AAAA,EACzB;AACA,QAAM,QAAQ,KAAK,MAAO,UAAU,KAAM,EAAE,IAAI;AAChD,SAAO,SAAS,KAAK;AACvB;AAOO,SAAS,eACd,GACAC,QACA,OACQ;AACR,QAAMC,SACJ,EAAE,UAAU,OACR,GAAG,EAAE,KAAK,eAAe,CAAC,IAAI,EAAE,MAAM,eAAe,CAAC,IAAI,EAAE,IAAI,KAChE,EAAE,OAAO,IACP,GAAG,EAAE,KAAK,eAAe,CAAC,IAAI,EAAE,IAAI,KACpC;AACR,QAAM,OACJ,EAAE,kBAAkB,QAAQ,EAAE,gBAAgB,IAC1C,GAAG,KAAK,MAAM,EAAE,aAAa,EAAE,eAAe,CAAC,SAC/C;AACN,QAAM,QAAQ;AAAA,IACZ,GAAG,EAAE,KAAK;AAAA;AAAA;AAAA;AAAA,IAIV,EAAE,UAAU,WAAW,EAAE,OAAO;AAAA,IAChCA;AAAA,IACA;AAAA,IACA,YAAY,EAAE,KAAK;AAAA,IACnB,SAAS;AAAA,IACT,EAAE,UAAU,2BAA2B;AAAA,EACzC,EAAE,OAAO,CAAC,SAAyB,QAAQ,IAAI,CAAC;AAChD,QAAM,UAAUD,WAAU,SAAY,KAAK,eAAeA,MAAK,CAAC,OAAO;AACvE,SAAO,GAAG,MAAM,KAAK,QAAK,CAAC,GAAG,OAAO;AACvC;;;ACrEA,eAAsB,aACpB,QACA,OACA,UACe;AACf,QAAM,OAAO,IAAI,SAAS;AAC1B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,YAAY,GAAG;AAC9D,SAAK,OAAO,KAAK,KAAK;AAAA,EACxB;AAIA,QAAME,QAAO,IAAI;AAAA,IACf,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACA,OAAK,OAAO,QAAQ,IAAI,KAAK,CAACA,KAAI,CAAC,GAAG,QAAQ;AAE9C,QAAM,MAAM,MAAM,MAAM,OAAO,WAAW,EAAE,QAAQ,QAAQ,MAAM,KAAK,CAAC;AACxE,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,SAAS,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC9C,UAAM,IAAI;AAAA,MACR,cAAc,QAAQ,aAAa,IAAI,MAAM,IAAI,IAAI,UAAU,GAC7D,SAAS,WAAM,OAAO,MAAM,GAAG,GAAG,CAAC,KAAK,EAC1C;AAAA,IACF;AAAA,EACF;AACF;;;AJcO,IAAM,0BAA0B,KAAK,KAAK;AACjD,IAAM,UAAU;AAEhB,SAAS,KAAK,OAAuB;AACnC,SAAO,sBAAsB,KAAK;AACpC;AAQO,IAAM,YAAY,CAAC,OAAkC;AAAA,EAC1D,IAAI,EAAE;AAAA,EACN,UAAU,EAAE;AAAA,EACZ,QAAQ,EAAE;AAAA,EACV,QAAQ,EAAE;AAAA,EACV,OAAO,EAAE;AAAA,EACT,GAAI,EAAE,eAAe,EAAE,OAAO,EAAE,aAAa,IAAI,CAAC;AACpD;AAkFA,eAAsB,YACpB,KACA,QAC4B;AAC5B,QAAM,EAAE,MAAM,UAAU,SAAS,UAAU,UAAAC,WAAU,WAAW,IAAI;AACpE,QAAM,EAAE,cAAc,IAAI;AAC1B,QAAM,cAAc,WAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAErE,QAAM,QAAQ,MAAM;AAAA,IAClB;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,MAC/B,GAAIA,YAAW,EAAE,UAAAA,UAAS,IAAI,CAAC;AAAA,IACjC;AAAA,EACF;AAEA,MAAI,MAAM,gBAAgB;AACxB,iBAAa,GAAG,QAAQ,sBAAsB;AAC9C,UAAMC,aAAY,MAAM,aAAa,CAAC,MAAM,QAAQ;AACpD,WAAO;AAAA,MACL;AAAA,MACA,SAAS;AAAA,MACT,UAAU,MAAM;AAAA,MAChB,WAAAA;AAAA,MACA,eAAe,MAAM,iBAAiBA,WAAU;AAAA,IAClD;AAAA,EACF;AAEA;AAAA,IACE,GAAG,QAAQ,gBAAgB,QAAQ,SAAS,OAAO,MAAM,QAAQ,CAAC,CAAC;AAAA,EACrE;AACA,QAAM,aAAa,MAAM,QAAQ,SAAS,QAAQ;AAElD,QAAM,YAAY,MAAM;AAAA,IACtB;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,MAAM;AAAA,MACnB,MAAM,QAAQ;AAAA,MACd,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,MAC/B,GAAID,YAAW,EAAE,UAAAA,UAAS,IAAI,CAAC;AAAA,MAC/B,GAAI,kBAAkB,SAAY,EAAE,cAAc,IAAI,CAAC;AAAA,IACzD;AAAA,EACF;AAEA,QAAMC,aACJ,UAAU,cAAc,UAAU,WAAW,CAAC,UAAU,QAAQ,IAAI,CAAC;AACvE,SAAO;AAAA,IACL;AAAA,IACA,SAAS;AAAA,IACT,QAAQ,UAAU;AAAA,IAClB,UAAU,UAAU;AAAA,IACpB,WAAAA;AAAA,IACA,eAAe,UAAU,iBAAiBA,WAAU;AAAA,IACpD,SAAS,UAAU;AAAA,IACnB,SAAS,UAAU,WAAW;AAAA,IAC9B,KAAK,UAAU,OAAO;AAAA,EACxB;AACF;AA4CA,eAAsB,cACpB,KACA,QAC8B;AAC9B,QAAM,EAAE,MAAM,aAAa,WAAW,IAAI;AAC1C,QAAM,YAAY,OAAO,aAAa;AAEtC,MAAI,YAAY,WAAW,GAAG;AAC5B,WAAO,EAAE,QAAQ,cAAc,WAAW,CAAC,EAAE;AAAA,EAC/C;AAEA,QAAM,SAAS,IAAI,IAAI,WAAW;AAClC,QAAM,YAAY,CAAC,SACjB,KAAK,OAAO,CAAC,MAAM,EAAE,WAAW,YAAY;AAE9C,QAAM,UAAU,MAAM;AAAA,IACpB,YAAY;AAEV,YAAM,OAAO,MAAM,aAAa,KAAK,EAAE,MAAM,KAAK,YAAY,CAAC;AAC/D,cAAQ,QAAQ,CAAC,GAAG,OAAO,CAAC,MAAM,OAAO,IAAI,EAAE,EAAE,CAAC;AAAA,IACpD;AAAA,IACA,CAACC,aAAY,UAAUA,QAAO,EAAE,WAAW;AAAA,IAC3C;AAAA,MACE;AAAA,MACA,QAAQ;AAAA,MACR,UAAU,CAACA,UAASC,WAClB,mBAAcD,SAAQ,SAAS,UAAUA,QAAO,EAAE,MAAM,IAAIA,SAAQ,MAAM,UAAU,eAAeC,MAAK,CAAC;AAAA,MAC3G,aAAa,CAACD,aAAY,UAAUA,QAAO,EAAE;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AACA,QAAM,UAAU,QAAQ;AACxB,MAAI,CAAC,QAAQ,SAAS;AACpB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW,QAAQ,IAAI,SAAS;AAAA,MAChC,OAAO;AAAA,QACL;AAAA,QACA,QAAQ,UAAU,OAAO,EAAE,MAAM;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL,QAAQ,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,OAAO,IAAI,UAAU;AAAA,IAC9D,WAAW,QAAQ,IAAI,SAAS;AAAA,EAClC;AACF;AAuBO,IAAM,gBAAgB;AAQ7B,eAAsB,iBACpB,KACA,QACiC;AACjC,QAAM,YAAY,OAAO,aAAa;AAEtC,QAAM,UAAU,MAAM;AAAA,IACpB,YAAY;AACV,YAAM,EAAE,YAAY,IAAI,MAAME,MAAK,GAAG;AACtC,YAAM,SAAS,YAAY,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,IAAI;AAC7D,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,gBAAgB,OAAO,IAAI,cAAc;AAAA,MAC3D;AACA,aAAO,OAAO,WAAW,YAAY;AAAA,IACvC;AAAA,IACA,CAAC,aAAa,aAAa,QAAQ,SAAS,eAAe;AAAA,IAC3D;AAAA,MACE;AAAA,MACA,QAAQ;AAAA,MACR,UAAU,CAAC,UAAUD,WACnB,WACI,oBAAe,SAAS,IAAI,IAAI,SAAS,KAAK,UAAU,eAAeA,MAAK,CAAC,OAC7E,qBAAgB,eAAeA,MAAK,CAAC;AAAA,MAC3C,aAAa,CAAC,aAAa,UAAU,cAAc;AAAA,MACnD,YAAY,OAAO;AAAA,IACrB;AAAA,EACF;AACA,QAAM,SAAS,QAAQ;AACvB,QAAM,SACJ,UAAU,OAAO,QAAQ,KAEnB,MAAM,UAAU,KAAK;AAAA,IACnB,MAAM,OAAO;AAAA,IACb,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,OAAO;AAAA,EACT,CAAC,GACD,UAAU,IAAI,SAAS,IACzB,CAAC;AACP,MAAI,CAAC,QAAQ,SAAS;AACpB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA,WAAW;AAAA,MACX,OAAO;AAAA,QACL;AAAA,QACA,QAAQ,QAAQ,cAAc,CAAC;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL,QAAQ,UAAU,OAAO,QAAQ,IAAI,UAAU;AAAA,IAC/C;AAAA,IACA,WAAW;AAAA,EACb;AACF;AAwBO,IAAM,oBAAoB;AAe1B,SAAS,UAAU,KAAmB,QAAyB;AACpE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC,aAAa,GAAG;AAAA,MAChC,MAAM,OAAO;AAAA,MACb,WAAW,OAAO,aAAa;AAAA,MAC/B,KAAK,OAAO,KAAK,SAAS,OAAO,IAAI,KAAK,GAAG,IAAI;AAAA,MACjD,OAAO,OAAO;AAAA,MACd,QAAQ,OAAO;AAAA,MACf,OAAO,OAAO;AAAA,MACd,QAAQ,OAAO;AAAA,MACf,UAAU,OAAO;AAAA,IACnB,CAAC,CAAC;AAAA,EACJ;AACF;AAYA,eAAsB,aACpB,KACA,QACsC;AACtC,QAAM,SAAsC,OAAO,MAC/C,MAAM;AAAA,IACJ,EAAE,QAAQ,KAAK,KAAK,OAAO,IAAI,SAAS,iBAAiB,EAAE;AAAA,IAC3D,CAAC,GAAG,MACF,OAAO,IAAK,MAAM,IAAI,oBAAoB,IAAI,KAAK,iBAAiB;AAAA,EACxE,IACA,CAAC,MAAS;AACd,QAAM,MAAmC,CAAC;AAC1C,aAAW,OAAO,QAAQ;AACxB,QAAI;AACJ,OAAG;AACD,YAAM,OAAO,MAAM,UAAU,KAAK;AAAA,QAChC,MAAM,OAAO;AAAA,QACb,WAAW,OAAO;AAAA,QAClB;AAAA,QACA,OAAO;AAAA,QACP;AAAA,QACA,OAAO,OAAO;AAAA,QACd,QAAQ,OAAO;AAAA,QACf,UAAU,OAAO;AAAA,MACnB,CAAC;AACD,UAAI,KAAK,GAAI,KAAK,aAAa,CAAC,CAAE;AAClC,eAAS,KAAK,cAAc;AAAA,IAC9B,SAAS;AAAA,EACX;AACA,SAAO;AACT;AAWO,SAASC,MAAK,KAAmB;AACtC,SAAO,KAA4B,KAAK,OAAO,KAAK,IAAI,KAAK,CAAC;AAChE;AA0CO,SAAS,OAAO,KAAmB,QAAsB;AAC9D,QAAM;AAAA,IACJ;AAAA,IACA,OAAAC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE;AAAA,MACA,OAAAA;AAAA,MACA,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,mBAAmB,SAAY,EAAE,eAAe,IAAI,CAAC;AAAA,MACzD,GAAI,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,MACvC,GAAI,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,MACvC,GAAI,aAAa,OAAO,KAAK,SAAS,EAAE,SAAS,EAAE,UAAU,IAAI,CAAC;AAAA,IACpE;AAAA,EACF;AACF;AAwBO,SAAS,MAAM,KAAmB,QAAqB;AAC5D,QAAM,EAAE,MAAM,QAAQ,UAAU,IAAI;AACpC,SAAO,KAA6B,KAAK,QAAQ,GAAG,KAAK,IAAI,KAAK,CAAC,UAAU;AAAA,IAC3E;AAAA,IACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,EACzC,CAAC;AACH;AA0BO,SAAS,SAAS,KAAmB,QAAwB;AAClE,QAAM,EAAE,MAAM,QAAQ,OAAO,UAAU,IAAI;AAC3C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE;AAAA,MACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,MACvC,GAAI,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,IACzC;AAAA,EACF;AACF;AAyBO,SAAS,SAAS,KAAmB,QAAwB;AAClE,QAAM,EAAE,MAAM,QAAQ,QAAQ,OAAO,UAAU,IAAI;AACnD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE;AAAA,MACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,MACvC,GAAI,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,IACzC;AAAA,EACF;AACF;AAcO,SAAS,UAAU,KAAmB,MAAc;AACzD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC,gBAAgB,mBAAmB,IAAI,CAAC;AAAA,EAC5D;AACF;AAuCO,SAAS,UAAU,KAAmB,QAAyB;AACpE,QAAM,EAAE,MAAM,QAAQ,WAAW,UAAU,IAAI;AAC/C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE;AAAA,MACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MACjC,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;AAAA,IACjD;AAAA,EACF;AACF;AAgCO,SAAS,OAAO,KAAmB,QAAsB;AAC9D,QAAM,EAAE,MAAM,MAAM,QAAQ,UAAU,IAAI;AAC1C,SAAO,KAA8B,KAAK,QAAQ,KAAK,IAAI,KAAK,GAAG;AAAA,IACjE;AAAA,IACA,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACvB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;AAAA,EACjD,CAAC;AACH;AAmCO,SAAS,SAAS,KAAmB,QAA0B;AACpE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB,EAAE,MAAM,OAAO,KAAK;AAAA,EACtB;AACF;AAsBO,SAAS,KAAK,KAAmB,QAAoB;AAC1D,SAAO,KAA4B,KAAK,QAAQ,GAAG,KAAK,IAAI,KAAK,CAAC,SAAS;AAAA,IACzE,MAAM,OAAO;AAAA,IACb,WAAW,OAAO;AAAA,IAClB,GAAI,OAAO,UAAU,EAAE,SAAS,KAAK,IAAI,CAAC;AAAA,IAC1C,GAAI,OAAO,WAAW,SAAY,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,EACjE,CAAC;AACH;AAuBA,eAAsB,YACpB,KACA,QAC4B;AAC5B,QAAM,YAAY,OAAO,aAAa;AACtC,QAAM,UAAU,MAAM;AAAA,IACpB,YAAY;AACV,YAAM,EAAE,YAAY,IAAI,MAAMD,MAAK,GAAG;AACtC,YAAME,UAAS,YAAY,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,IAAI;AAC7D,UAAI,CAACA,SAAQ;AACX,cAAM,IAAI,MAAM,gBAAgB,OAAO,IAAI,cAAc;AAAA,MAC3D;AACA,aAAOA;AAAA,IACT;AAAA,IACA,CAACA,YAAW,CAACA,QAAO,aAAaA,QAAO,UAAU,UAAU;AAAA,IAC5D;AAAA,MACE;AAAA,MACA,QAAQ;AAAA,MACR,UAAU,CAACA,SAAQH,WACjB,eAAeG,QAAO,UAAW,UAAUH,MAAK;AAAA;AAAA;AAAA;AAAA;AAAA,MAKlD,aAAa,CAACG,YACZA,QAAO,YACH,GAAGA,QAAO,UAAU,MAAM,IAAIA,QAAO,UAAU,SAAS,aAAa,EAAE,KACvE;AAAA,MACN,YAAY,OAAO;AAAA,IACrB;AAAA,EACF;AACA,QAAM,SAAS,QAAQ;AACvB,QAAM,YAAY,OAAO;AACzB,MAAI,CAAC,QAAQ,SAAS;AACpB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA,OAAO;AAAA,QACL;AAAA,QACA,QAAQ,UAAW,MAAM,IAAI,UAAW,KAAK;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AACA,MAAI,WAAW,OAAO;AACpB,WAAO,EAAE,QAAQ,UAAU,QAAQ,OAAO,UAAU,MAAM;AAAA,EAC5D;AACA,SAAO,EAAE,QAAQ,QAAQ,OAAO;AAClC;AA2BO,SAAS,YAAY,KAAmB,QAA2B;AACxE,QAAM,EAAE,MAAM,OAAO,IAAI;AACzB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE;AAAA,MACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC7B;AAAA,EACF;AACF;AAuBO,SAAS,QAAQ,KAAmB,QAAuB;AAChE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE,MAAM,OAAO;AAAA,MACb,GAAI,OAAO,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;AAAA,IACxC;AAAA,EACF;AACF;AAuBO,SAAS,KAAK,KAAmB,QAAoB;AAC1D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE,MAAM,OAAO;AAAA,MACb,GAAI,OAAO,YAAY,SAAY,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,IACpE;AAAA,EACF;AACF;AAsBO,SAAS,GAAG,KAAmB,QAAkB;AACtD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE,MAAM,OAAO;AAAA,MACb,YAAY,OAAO;AAAA,IACrB;AAAA,EACF;AACF;AAqBO,SAAS,QAAQ,KAAmB,QAAuB;AAChE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB,EAAE,MAAM,OAAO,MAAM,QAAQ,OAAO,OAAO;AAAA,EAC7C;AACF;AAGA,eAAsB,WACpB,KACA,QAC8B;AAC9B,MAAI,UAAU;AACd,SAAO,MAAM;AACX,UAAM,OAAO,MAAM,QAAQ,KAAK,MAAM;AACtC,eAAW,KAAK;AAChB,QAAI,KAAK,cAAc,KAAK,KAAK,YAAY,GAAG;AAC9C,aAAO,EAAE,QAAQ;AAAA,IACnB;AACA,WAAO;AAAA,MACL,WAAW,QAAQ,eAAe,CAAC,YAAY,KAAK,UAAU,eAAe,CAAC;AAAA,IAChF;AAAA,EACF;AACF;AAeO,SAAS,aAAa,KAAmB,MAAc;AAC5D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB,EAAE,KAAK;AAAA,EACT;AACF;AASA,IAAM,0BAA0B;AAChC,IAAM,wBAAwB;AAY9B,eAAsB,eACpB,KACA,QAM0C;AAC1C,QAAM,EAAE,MAAM,QAAQ,IAAI;AAC1B,QAAM,QAAQ,MAAM;AAAA,IAClB;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE;AAAA,MACA,GAAI,OAAO,kBAAkB,SACzB,EAAE,eAAe,OAAO,cAAc,IACtC,CAAC;AAAA,IACP;AAAA,EACF;AACA,QAAM,UAAU,KAAK;AAAA,IACnB;AAAA,IACA,MAAM,kBAAkB;AAAA,EAC1B;AACA,MAAIC,SAAQ;AACZ,MAAIJ,SAAQ;AACZ,SAAOA,SAAQ,QAAQ,QAAQ;AAC7B,QAAI,MAAMA;AACV,QAAI,QAAQ;AACZ,WAAO,MAAM,QAAQ,UAAU,MAAMA,SAAQ,SAAS;AACpD,YAAM,OAAO,KAAK,UAAU,QAAQ,GAAG,CAAC,EAAE;AAC1C,UAAI,MAAMA,UAAS,QAAQ,OAAO,uBAAuB;AACvD;AAAA,MACF;AACA,eAAS;AACT,aAAO;AAAA,IACT;AACA,UAAM,KAAK,KAAK,QAAQ,GAAG,KAAK,IAAI,KAAK,CAAC,oBAAoB;AAAA,MAC5D;AAAA,MACA,SAAS,MAAM;AAAA,MACf,MAAMI;AAAA,MACN,SAAS,QAAQ,MAAMJ,QAAO,GAAG;AAAA,IACnC,CAAC;AACD,IAAAI,UAAS;AACT,IAAAJ,SAAQ;AACR,WAAO,aAAaA,QAAO,QAAQ,MAAM;AAAA,EAC3C;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB,EAAE,MAAM,SAAS,MAAM,SAAS,OAAAI,OAAM;AAAA,EACxC;AACF;AAQO,SAAS,WAAW,KAAmB,QAA0B;AACtE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,KAAK,IAAI,KAAK,CAAC;AAAA,IAClB,EAAE,MAAM,OAAO,KAAK;AAAA,EACtB;AACF;AAUO,SAAS,KACd,KACA,QACA;AACA,SAAO,KAA4B,KAAK,QAAQ,GAAG,KAAK,IAAI,KAAK,CAAC,SAAS;AAAA,IACzE,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,EACf,CAAC;AACH;;;AKjuCA;AAAA;AAAA,iCAAAC;AAAA,EAAA;AAAA;AAAA;AAAA,aAAAC;AAAA,EAAA,YAAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBO,IAAMC,2BAA0B,KAAK,KAAK;AACjD,IAAMC,WAAU;AAEhB,SAASC,MAAK,OAAuB;AACnC,SAAO,sBAAsB,KAAK;AACpC;AAoCO,SAAS,MAAM,KAAmB,QAAqB;AAC5D,QAAM,EAAE,MAAM,QAAQ,SAAAC,UAAS,eAAe,aAAa,UAAU,MAAM,IACzE;AACF,SAAO,KAA0B,KAAK,QAAQD,MAAK,IAAI,KAAK,GAAG;AAAA,IAC7D;AAAA,IACA;AAAA,IACA,GAAIC,WAAU,EAAE,SAAS,KAAK,IAAI,CAAC;AAAA,IACnC,GAAI,kBAAkB,SAAY,EAAE,cAAc,IAAI,CAAC;AAAA,IACvD,GAAI,gBAAgB,SAAY,EAAE,YAAY,IAAI,CAAC;AAAA,IACnD,GAAI,WAAW,EAAE,UAAU,KAAK,IAAI,CAAC;AAAA,IACrC,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,EACzC,CAAC;AACH;AAcA,eAAsB,eACpB,KACA,QAC0B;AAC1B,QAAM,QAAQ,MAAM;AAAA,IAClB;AAAA,IACA;AAAA,IACA,GAAGD,MAAK,IAAI,KAAK,CAAC;AAAA,IAClB,EAAE,MAAM,OAAO,KAAK;AAAA,EACtB;AACA,QAAM,aAAa,MAAM,QAAQ,OAAO,SAAS,gBAAgB;AACjE,SAAO,EAAE,KAAK,MAAM,IAAI;AAC1B;AASO,SAASE,MAAK,KAAmB,QAAqB;AAC3D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGF,MAAK,IAAI,KAAK,CAAC,GAAG,GAAG,EAAE,MAAM,QAAQ,KAAK,CAAC,CAAC;AAAA,EACjD;AACF;AAOO,SAASG,KAAI,KAAmB,QAAqB;AAC1D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGH,MAAK,IAAI,KAAK,CAAC,IAAI,mBAAmB,OAAO,EAAE,CAAC;AAAA,EACrD;AACF;AAaO,SAAS,QACd,KACA,QAMA;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,IAAI,mBAAmB,OAAO,EAAE,CAAC;AAAA,IACnD,YAAY,MAAM;AAAA,EACpB;AACF;AAGA,SAAS,YAAY,QAGmB;AACtC,QAAM,OAAO;AAAA,IACX,GAAI,OAAO,gBAAgB,SACvB,EAAE,aAAa,OAAO,YAAY,IAClC,CAAC;AAAA,IACL,GAAI,OAAO,aAAa,SAAY,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;AAAA,EACvE;AACA,SAAO,OAAO,KAAK,IAAI,EAAE,SAAS,IAAI,OAAO;AAC/C;AAGO,SAAS,MAAM,KAAmB,QAAqB;AAC5D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,IAAI,mBAAmB,OAAO,EAAE,CAAC;AAAA,EACrD;AACF;AAGO,SAAS,OACd,KACA,QAMA;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,IAAI,mBAAmB,OAAO,EAAE,CAAC;AAAA,IACnD,YAAY,MAAM;AAAA,EACpB;AACF;AAMO,SAAS,MAAM,KAAmB,QAAqB;AAC5D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,IAAI,mBAAmB,OAAO,EAAE,CAAC;AAAA,EACrD;AACF;AAGO,SAAS,OAAO,KAAmB,QAAqB;AAC7D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,IAAI,mBAAmB,OAAO,EAAE,CAAC;AAAA,EACrD;AACF;AAsBO,SAAS,YAAY,KAAmB,QAAoB;AACjE,SAAO,OAAO,KAAK,QAAQ,CAAC,QAAQ,IAAI,UAAU,UAAU;AAC9D;AAUO,SAAS,WAAW,KAAmB,QAAoB;AAChE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,CAAC,QACC,CAAC,CAAC,YAAY,WAAW,WAAW,QAAQ,EAAE,SAAS,IAAI,KAAK,KAC/D,IAAI,UAAU,cAAc,IAAI,UAAU,QAAQ,CAAC,IAAI,gBACvD,IAAI,UAAU,YAAY,CAAC,IAAI;AAAA,EACpC;AACF;AAEA,eAAe,OACb,KACA,QACA,WACqB;AACrB,QAAM,YAAY,OAAO,aAAaF;AACtC,QAAM,UAAU,MAAM;AAAA,IACpB,aAAa,MAAMK,KAAI,KAAK,EAAE,IAAI,OAAO,GAAG,CAAC,GAAG;AAAA,IAChD;AAAA,IACA;AAAA,MACE;AAAA,MACA,QAAQJ;AAAA,MACR,UAAU;AAAA;AAAA;AAAA,MAGV,aAAa,CAACK,SAAQ,GAAGA,KAAI,KAAK,IAAIA,KAAI,SAAS,IAAI;AAAA,MACvD,YAAY,OAAO;AAAA,IACrB;AAAA,EACF;AACA,QAAM,MAAM,QAAQ;AACpB,MAAI,CAAC,QAAQ,SAAS;AACpB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA,OAAO,SAAS,WAAW,kBAAkB,IAAI,KAAK,EAAE;AAAA,IAC1D;AAAA,EACF;AACA,MAAI,IAAI,UAAU,YAAY,IAAI,UAAU,aAAa;AACvD,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA,OAAO,IAAI,SAAS,eAAe,IAAI,KAAK;AAAA,IAC9C;AAAA,EACF;AACA,MAAI,IAAI,UAAU,UAAU;AAC1B,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA,OACE,IAAI,SACJ,mBAAmB,IAAI,eAAe,MAAM;AAAA,IAChD;AAAA,EACF;AACA,MAAI,IAAI,UAAU,cAAc,IAAI,UAAU,QAAQ,IAAI,cAAc;AACtE,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA,OACE,IAAI,SACJ;AAAA,IACJ;AAAA,EACF;AACA,SAAO,EAAE,QAAQ,QAAQ,IAAI;AAC/B;AAOO,SAAS,iBAAiB,KAAoBC,QAAuB;AAC1E,MAAI,IAAI,UAAU,cAAc,IAAI,iBAAiB;AACnD,WAAO;AAAA,MACL,EAAE,GAAG,IAAI,UAAU,OAAO,WAAW;AAAA,MACrCA;AAAA,MACA,uBAAuB,IAAI,OAAO,YAAY,eAAe,CAAC;AAAA,IAChE;AAAA,EACF;AACA,QAAM,QACJ,IAAI,UAAU,aACV,OACA,IAAI,IAAI,iBAAiB,QAAQ,CAAC,CAAC,GACjC,IAAI,kBAAkB,OAClB,QAAQ,IAAI,cAAc,QAAQ,CAAC,CAAC,KACpC,EACN;AACN,SAAO,eAAe,IAAI,UAAUA,QAAO,KAAK;AAClD;;;ACvVA;AAAA;AAAA;AAAA;AAAA,aAAAC;AAAA,EAAA;AAAA;AAiBA,SAASC,MAAK,OAAuB;AACnC,SAAO,sBAAsB,KAAK;AACpC;AAuCO,SAAS,QAAQ,KAAmB,QAAuB;AAChE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAI,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC;AAAA,MACzC,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,MAC7C;AAAA,MACA;AAAA,MACA,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MAC/C,GAAI,yBAAyB,SAAY,EAAE,qBAAqB,IAAI,CAAC;AAAA,IACvE;AAAA,EACF;AACF;AAKO,SAASC,KAAI,KAAmB,QAA0B;AAC/D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGD,MAAK,IAAI,KAAK,CAAC,aAAa,GAAG,EAAE,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,EAC1D;AACF;AAWO,SAAS,WAAW,KAAmB,QAA0B;AACtE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC;AAAA,IAClB,EAAE,MAAM,OAAO,KAAK;AAAA,EACtB;AACF;AAwBO,SAAS,KAAK,KAAmB,QAAoB;AAC1D,SAAO,KAA2B,KAAK,QAAQ,GAAGA,MAAK,IAAI,KAAK,CAAC,SAAS;AAAA,IACxE,MAAM,OAAO;AAAA,IACb,GAAI,OAAO,kBAAkB,SACzB,EAAE,eAAe,OAAO,cAAc,IACtC,CAAC;AAAA,IACL,GAAI,OAAO,UAAU,SAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,IAC5D,GAAI,OAAO,gBAAgB,SACvB,EAAE,aAAa,OAAO,YAAY,IAClC,CAAC;AAAA,IACL,GAAI,OAAO,WAAW,EAAE,UAAU,KAAK,IAAI,CAAC;AAAA,EAC9C,CAAC;AACH;;;ACvJA;AAAA;AAAA,iCAAAE;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AA8BO,IAAMC,2BAA0B,KAAK,KAAK;AACjD,IAAMC,WAAU;AAEhB,SAASC,MAAK,OAAuB;AACnC,SAAO,sBAAsB,KAAK;AACpC;AASO,SAAS,QAAQ,KAAmB,QAA0B;AACnE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC;AAAA,IAClB,EAAE,MAAM,OAAO,KAAK;AAAA,EACtB;AACF;AAaO,SAAS,QAAQ,KAAmB,QAA0B;AACnE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC;AAAA,IAClB,EAAE,MAAM,OAAO,KAAK;AAAA,EACtB;AACF;AAgBA,eAAsB,iBACpB,KACA,QACiC;AACjC,QAAM,YAAY,OAAO,aAAaF;AACtC,QAAM,UAAU,MAAM;AAAA,IACpB,YAAY;AACV,YAAM,EAAE,YAAY,IAAI,MAAMG,MAAY,GAAG;AAC7C,YAAMC,UAAS,YAAY,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,IAAI;AAC7D,UAAI,CAACA,SAAQ;AACX,cAAM,IAAI,MAAM,gBAAgB,OAAO,IAAI,cAAc;AAAA,MAC3D;AACA,aAAOA;AAAA,IACT;AAAA,IACA,CAACA,YAAW,CAACA,QAAO,aAAaA,QAAO,UAAU,UAAU;AAAA,IAC5D;AAAA,MACE;AAAA,MACA,QAAQH;AAAA,MACR,UAAU,CAACG,SAAQC,WACjB,eAAeD,QAAO,UAAW,UAAUC,MAAK;AAAA;AAAA;AAAA,MAGlD,aAAa,CAACD,YAAWA,QAAO,WAAW,UAAU;AAAA,MACrD,YAAY,OAAO;AAAA,IACrB;AAAA,EACF;AACA,QAAM,SAAS,QAAQ;AACvB,QAAM,YAAY,OAAO;AACzB,MAAI,CAAC,QAAQ,SAAS;AACpB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA,OAAO;AAAA,QACL;AAAA,QACA,QAAQ,UAAW,MAAM,IAAI,UAAW,KAAK;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AACA,MAAI,WAAW,OAAO;AACpB,WAAO,EAAE,QAAQ,UAAU,QAAQ,OAAO,UAAU,MAAM;AAAA,EAC5D;AACA,SAAO,EAAE,QAAQ,QAAQ,OAAO;AAClC;AA2BO,SAAS,OAAO,KAAmB,QAAsB;AAC9D,QAAM,EAAE,MAAM,MAAM,IAAI,QAAQ,UAAU,UAAU,IAAI;AACxD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGF,MAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE;AAAA,MACA;AAAA,MACA,GAAI,KAAK,EAAE,GAAG,IAAI,CAAC;AAAA,MACnB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,MAC/B,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;AAAA,IACjD;AAAA,EACF;AACF;AA2BO,SAAS,UAAU,KAAmB,QAAyB;AACpE,QAAM,EAAE,MAAM,MAAM,aAAa,MAAM,OAAO,SAAS,MAAM,KAAK,IAAI;AACtE,SAAO,KAAoB,KAAK,QAAQ,GAAGA,MAAK,IAAI,KAAK,CAAC,cAAc;AAAA,IACtE;AAAA,IACA;AAAA,IACA,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,IACrC,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,IACrC,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAI,MAAM,SAAS,EAAE,KAAK,IAAI,CAAC;AAAA,IAC/B,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,EACvC,CAAC;AACH;AAEO,SAAS,SAAS,KAAmB,QAA4B;AACtE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,aAAa,GAAG,EAAE,MAAM,QAAQ,KAAK,CAAC,CAAC;AAAA,EAC3D;AACF;AAEO,SAAS,OACd,KACA,QACA;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,cAAc,mBAAmB,OAAO,EAAE,CAAC,GAAG,GAAG;AAAA,MACjE,SAAS,OAAO,UAAU,SAAS;AAAA,IACrC,CAAC,CAAC;AAAA,EACJ;AACF;AAEO,SAAS,UAAU,KAAmB,QAAwB;AACnE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,cAAc,mBAAmB,OAAO,EAAE,CAAC;AAAA,EAC/D;AACF;AAoBO,SAAS,WACd,KACA,QACA;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,cAAc,mBAAmB,OAAO,EAAE,CAAC;AAAA,IAC7D,EAAE,SAAS,OAAO,QAAQ;AAAA,EAC5B;AACF;AAEO,SAAS,YAAY,KAAmB,QAAwB;AACrE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,cAAc,mBAAmB,OAAO,EAAE,CAAC;AAAA,EAC/D;AACF;AAEO,SAAS,YACd,KACA,QACA;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,cAAc,mBAAmB,OAAO,EAAE,CAAC;AAAA,IAC7D,EAAE,SAAS,OAAO,QAAQ;AAAA,EAC5B;AACF;AAqBO,SAASI,KAAI,KAAmB,QAAmB;AACxD,QAAM,EAAE,OAAO,MAAM,WAAW,OAAO,UAAU,IAAI;AACrD,SAAO,KAAoB,KAAK,QAAQ,GAAGJ,MAAK,IAAI,KAAK,CAAC,cAAc;AAAA,IACtE;AAAA,IACA,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACvB,GAAI,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,IACvC,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,GAAI,aAAa,OAAO,KAAK,SAAS,EAAE,SAAS,EAAE,UAAU,IAAI,CAAC;AAAA,EACpE,CAAC;AACH;AAEO,SAAS,SACd,KACA,QACA;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,aAAa,GAAG,EAAE,OAAO,QAAQ,OAAO,MAAM,QAAQ,KAAK,CAAC,CAAC;AAAA,EACjF;AACF;AAEO,SAAS,OACd,KACA,QACA;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,cAAc,mBAAmB,OAAO,EAAE,CAAC,GAAG,GAAG;AAAA,MACjE,SAAS,OAAO,UAAU,SAAS;AAAA,MACnC,OAAO,OAAO;AAAA,IAChB,CAAC,CAAC;AAAA,EACJ;AACF;AAGO,SAAS,QAAQ,KAAmB,QAAkC;AAC3E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,GAAG,OAAO,GAAG,GAAG,OAAO,EAAE,CAAC,CAAC;AAAA,EACzE;AACF;AAeA,eAAsB,WACpB,KACA,QAC2B;AAC3B,QAAM,YAAY,OAAO,aAAaF;AACtC,QAAM,UAAU,MAAM;AAAA,IACpB,aAAa,MAAM,OAAO,KAAK,EAAE,IAAI,OAAO,GAAG,CAAC,GAAG;AAAA,IACnD,CAACM,SAAQA,KAAI,UAAU,UAAUA,KAAI,UAAU;AAAA,IAC/C;AAAA,MACE;AAAA,MACA,QAAQL;AAAA,MACR,UAAU,CAACK,MAAKD,WACd,GAAGC,KAAI,KAAK,UAAKA,KAAI,SAAS,IAAIA,KAAI,KAAK,aAAa,eAAeD,MAAK,CAAC;AAAA,MAC/E,YAAY,OAAO;AAAA,IACrB;AAAA,EACF;AACA,QAAMC,OAAM,QAAQ;AACpB,MAAI,CAAC,QAAQ,SAAS;AACpB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,KAAAA;AAAA,MACA,OAAO;AAAA,QACL;AAAA,QACA,YAAYA,KAAI,KAAK,KAAKA,KAAI,SAAS,IAAIA,KAAI,KAAK;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AACA,MAAIA,KAAI,UAAU,UAAU;AAC1B,WAAO,EAAE,QAAQ,UAAU,KAAAA,MAAK,OAAOA,KAAI,SAAS,kBAAkB;AAAA,EACxE;AACA,SAAO,EAAE,QAAQ,QAAQ,KAAAA,KAAI;AAC/B;AAQA,eAAsB,WACpB,KACA,QAC2B;AAC3B,QAAM,YAAY,OAAO,aAAaN;AACtC,QAAM,UAAU,MAAM;AAAA,IACpB,aAAa,MAAM,OAAO,KAAK,EAAE,IAAI,OAAO,GAAG,CAAC,GAAG;AAAA,IACnD,CAACO,SAAQA,KAAI,UAAU,WAAWA,KAAI,UAAU;AAAA,IAChD;AAAA,MACE;AAAA,MACA,QAAQN;AAAA,MACR,UAAU,CAACM,MAAKF,WAAU,GAAGE,KAAI,KAAK,WAAM,eAAeF,MAAK,CAAC;AAAA,MACjE,YAAY,OAAO;AAAA,IACrB;AAAA,EACF;AACA,QAAME,OAAM,QAAQ;AACpB,MAAI,CAAC,QAAQ,SAAS;AACpB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,KAAAA;AAAA,MACA,OAAO,SAAS,WAAW,kBAAkBA,KAAI,KAAK,EAAE;AAAA,IAC1D;AAAA,EACF;AACA,MAAIA,KAAI,UAAU,UAAU;AAC1B,WAAO,EAAE,QAAQ,UAAU,KAAAA,MAAK,OAAOA,KAAI,SAAS,qBAAqB;AAAA,EAC3E;AACA,SAAO,EAAE,QAAQ,QAAQ,KAAAA,KAAI;AAC/B;;;AClbA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBA,SAASC,MAAK,OAAuB;AACnC,SAAO,sBAAsB,KAAK;AACpC;AAOA,SAAS,cAAc,WAAqD;AAC1E,MAAI,eAAe,WAAW;AAC5B,WAAO,EAAE,WAAW,KAAK;AAAA,EAC3B;AACA,SAAO;AAAA,IACL,OAAO,UAAU;AAAA,IACjB,GAAI,UAAU,SAAS,EAAE,QAAQ,UAAU,OAAO,IAAI,CAAC;AAAA,IACvD,GAAI,UAAU,WAAW,SAAY,EAAE,QAAQ,UAAU,OAAO,IAAI,CAAC;AAAA,EACvE;AACF;AAqBO,SAAS,QAAQ,KAAmB,QAAuB;AAChE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE,GAAI,OAAO,OAAO,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,MAC3C,GAAG,cAAc,OAAO,SAAS;AAAA,MACjC,GAAI,OAAO,OAAO,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,MAC3C,GAAI,OAAO,UAAU,SAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,IAC9D;AAAA,EACF;AACF;AA2BO,SAAS,QAAQ,KAAmB,QAAuB;AAChE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE,MAAM,OAAO;AAAA,MACb,GAAG,cAAc,OAAO,SAAS;AAAA,MACjC,GAAI,OAAO,OAAO,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,MAC3C,GAAI,OAAO,UAAU,SAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,MAC5D,GAAI,OAAO,MAAM,EAAE,KAAK,KAAK,IAAI,CAAC;AAAA,MAClC,GAAI,OAAO,YAAY,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;AAAA,IAC5D;AAAA,EACF;AACF;AAiCO,SAAS,UAAU,KAAmB,QAAyB;AACpE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC;AAAA,IAClB;AAAA,MACE,MAAM,OAAO;AAAA,MACb,GAAI,OAAO,YAAY,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;AAAA,IAC5D;AAAA,EACF;AACF;AAWO,SAAS,MAAM,KAAmB,QAAqB;AAC5D,SAAO,KAA4B,KAAK,QAAQ,GAAGA,MAAK,IAAI,KAAK,CAAC,UAAU;AAAA,IAC1E,MAAM,OAAO;AAAA,IACb,GAAI,OAAO,kBAAkB,SACzB,EAAE,eAAe,OAAO,cAAc,IACtC,CAAC;AAAA,IACL,GAAI,OAAO,UAAU,SAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,EAC9D,CAAC;AACH;AAsBO,SAAS,WAAW,KAAmB,QAA0B;AACtE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,SAAS,OAAO,EAAE,cAAc,GAAG;AAAA,MACnD,GAAI,OAAO,OAAO,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,MAC3C,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,MAC9C,GAAI,OAAO,SAAS,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,MACjD,GAAI,OAAO,SAAS,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,MACjD,GAAI,OAAO,UAAU,SAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,IAC9D,CAAC,CAAC;AAAA,EACJ;AACF;AAcO,SAAS,OAAO,KAAmB,QAAsB;AAC9D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,SAAS,OAAO,EAAE;AAAA,IACpC,OAAO,OAAO,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,EACzC;AACF;;;ACrOA;AAAA;AAAA,eAAAC;AAAA;AAgCO,SAASC,OAAM,KAAmB,KAAa;AACpD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,EAAE;AAAA,EACvB;AACF;;;ACvCA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA,aAAAC;AAAA,EAAA,YAAAC;AAAA,EAAA;AAAA;AAqCO,SAASC,MAAK,KAAmB,SAA6B,CAAC,GAAG;AACvE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,YAAY,GAAG,EAAE,OAAO,OAAO,MAAM,CAAC,CAAC;AAAA,EACxE;AACF;AAcO,SAASC,KAAI,KAAmB,WAAmB;AACxD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,aAAa,IAAI,SAAS,CAAC;AAAA,EAC5D;AACF;AAeO,SAAS,SACd,KACA,WACwE;AACxE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,uBAAuB,IAAI,SAAS,CAAC;AAAA,EACtE;AACF;AAUA,eAAsB,cACpB,KACsC;AACtC,QAAM,YAAY,MAAM;AAAA,IACtB;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,EACjC;AACA,SAAO,UAAU;AACnB;AAsCA,SAAS,iBAAiB,SAAiD;AACzE,QAAMC,WAA0B;AAAA,IAC9B,WAAW,QAAQ;AAAA,IACnB,WAAW,QAAQ;AAAA,IACnB,QAAQ,QAAQ,UAAU;AAAA,IAC1B,QAAQ,QAAQ;AAAA,IAChB,iBAAiB,QAAQ,mBAAmB;AAAA,IAC5C,aAAa,QAAQ,eAAe;AAAA,IACpC,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,EACjE;AACA,QAAM,WAAW,QAAQ,eAAe,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,MAAM;AAClE,MAAI,QAAQ,SAAS,KAAK,QAAQ,WAAW,QAAQ;AACnD,IAAAA,SAAQ,UAAU,QAAQ,IAAI,CAAC,OAAO;AAAA,MACpC,MAAM,EAAE;AAAA,MACR,QAAQ,EAAE,gBAAgB;AAAA,IAC5B,EAAE;AAAA,EACJ;AACA,MAAI,QAAQ,WAAW,UAAU;AAC/B,WAAOA;AAAA,EACT;AACA,SAAO;AAAA,IACL,GAAGA;AAAA,IACH,OACE,QAAQ,iBAAiB;AAAA,IAC3B,GAAI,QAAQ,cAAc,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,IAClE,GAAI,QAAQ,eAAe,EAAE,cAAc,QAAQ,aAAa,IAAI,CAAC;AAAA,EACvE;AACF;AA2CA,IAAMC,WAAU;AAChB,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAqC3B,eAAsB,cACpB,KACA,QAC8B;AAC9B,QAAM,EAAE,WAAW,WAAW,IAAI;AAClC,QAAM,YAAY,OAAO,aAAa;AACtC,QAAM,WAAW,UAAU,MAAM,GAAG,CAAC;AACrC,QAAMC,SAAQ,KAAK,IAAI;AAGvB,MAAI;AACJ,SAAO,MAAM;AACX,UAAM,IAAI,MAAM,SAAS,KAAK,SAAS;AACvC,QAAI,EAAE,IAAI;AACR,gBAAU,EAAE;AACZ;AAAA,IACF;AACA,QAAI,EAAE,WAAW,KAAK;AACpB,YAAM,IAAI;AAAA,QACR,iCAAiC,QAAQ,UAAU,EAAE,MAAM,IAAI,KAAK,UAAU,EAAE,IAAI,CAAC;AAAA,MACvF;AAAA,IACF;AACA,QAAI,KAAK,IAAI,IAAIA,SAAQ,kBAAkB;AACzC,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,iCAAiC,SAAS,WAAW,mBAAmB,GAAI;AAAA,MACrF;AAAA,IACF;AACA,iBAAa,yCAAyC,QAAQ,QAAG;AACjE,UAAM,MAAMD,QAAO;AAAA,EACrB;AAGA,QAAM,UAAU,oBAAI,IAAY,CAAC,QAAQ,SAAS,CAAC;AACnD,SAAO,MAAM;AACX,QAAI,QAAQ,IAAI,QAAQ,MAAM,GAAG;AAC/B,aAAO;AAAA,QACL,SAAS,QAAQ;AAAA,QACjB;AAAA,QACA,SAAS,iBAAiB,OAAO;AAAA,MACnC;AAAA,IACF;AACA,QAAI,QAAQ,WAAW,UAAU;AAC/B,aAAO,EAAE,SAAS,UAAU,SAAS,SAAS,iBAAiB,OAAO,EAAE;AAAA,IAC1E;AACA,QAAI,QAAQ,WAAW,cAAc;AACnC,aAAO;AAAA,QACL,SAAS;AAAA,QACT;AAAA,QACA,SAAS,iBAAiB,OAAO;AAAA,MACnC;AAAA,IACF;AACA,QAAI,KAAK,IAAI,IAAIC,SAAQ,WAAW;AAClC,aAAO;AAAA,QACL,SAAS;AAAA,QACT;AAAA,QACA,SAAS,iBAAiB,OAAO;AAAA,QACjC,OAAO,mBAAmB,YAAY,GAAI,mBAAmB,QAAQ,MAAM;AAAA,MAC7E;AAAA,IACF;AACA;AAAA,MACE,GAAG,QAAQ,MAAM,WAAM,KAAK,OAAO,KAAK,IAAI,IAAIA,UAAS,GAAI,CAAC;AAAA,IAChE;AACA,UAAM,MAAMD,QAAO;AACnB,UAAM,IAAI,MAAM,SAAS,KAAK,SAAS;AACvC,QAAI,EAAE,IAAI;AACR,gBAAU,EAAE;AAAA,IACd;AAAA,EAGF;AACF;;;AD/SA,eAAsB,iBACpB,KACwB;AACxB,QAAME,QAAO,MAAM,cAAc,GAAG;AACpC,SAAOA,OAAM,MAAM;AACrB;AAeO,SAAS,WAAW,KAAmB,WAAmB;AAC/D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,aAAa,IAAI,SAAS,CAAC;AAAA,EAC5D;AACF;AAWA,eAAsB,YAAY,KAA+B;AAC/D,QAAM,MAAM,MAAM;AAAA,IAChB;AAAA,IACA,CAAC;AAAA,IACD;AAAA,IACA;AAAA,EACF;AACA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,MAAM,2CAA2C,IAAI,MAAM,EAAE;AAAA,EACzE;AACA,SAAO,IAAI,KAAK;AAClB;;;AErEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAAAC;AAAA,EAAA;AAAA;AAkCO,SAASC,KAAI,KAAmB;AACrC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,EACjC;AACF;AASO,SAAS,IAAI,KAAmB,WAAmB;AACxD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B,EAAE,UAAU;AAAA,EACd;AACF;AAQO,SAAS,MAAM,KAAmB,WAAmB;AAC1D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B,EAAE,UAAU;AAAA,EACd;AACF;AAcO,SAAS,WAAW,KAAmB;AAC5C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,EACjC;AACF;AAgBO,SAAS,UAAU,KAAmB,UAAkB;AAC7D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B,EAAE,SAAS;AAAA,EACb;AACF;AAWO,SAAS,YAAY,KAAmB,UAAkB;AAC/D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B,EAAE,SAAS;AAAA,EACb;AACF;AAWA,eAAsB,aACpB,KACA,UAC2D;AAC3D,QAAM,SAAS,SAAS,YAAY;AACpC,QAAM,MAAM,MAAM,WAAW,GAAG;AAChC,QAAM,SAAS,IAAI,aAAa,CAAC,GAAG;AAAA,IAClC,CAAC,MAAM,OAAO,EAAE,aAAa,YAAY,EAAE,aAAa;AAAA,EAC1D;AACA,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,qBAAqB,QAAQ,qBAAqB;AAAA,EACpE;AACA,SAAO,EAAE,IAAI,MAAM,IAAI,MAAM;AAC/B;AAcA,eAAsB,aAAa,KAAmB,UAAkB;AACtE,QAAM,EAAE,GAAG,IAAI,MAAM,aAAa,KAAK,QAAQ;AAC/C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,4BAA4B,IAAI,EAAE,CAAC;AAAA,EACpE;AACF;AAaA,eAAsB,YAAY,KAAmB,UAAkB;AACrE,QAAM,EAAE,GAAG,IAAI,MAAM,aAAa,KAAK,QAAQ;AAC/C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,4BAA4B,IAAI,EAAE,CAAC;AAAA,EACpE;AACF;;;ACrMA;AAAA;AAAA;AAAA,eAAAC;AAAA,EAAA;AAAA;AAAA,aAAAC;AAAA,EAAA;AAAA,cAAAC;AAAA,EAAA;AAAA;AAAA,eAAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiHA,IAAM,eAAgD;AAAA,EACpD,SAAS;AAAA,EACT,SAAS;AACX;AAEA,SAAS,YAAY,KAAmB,WAAoC;AAC1E,SAAO,sBAAsB,IAAI,KAAK,aAAa,aAAa,SAAS,CAAC;AAC5E;AAEA,eAAe,gBACb,KACA,WACA,QACiB;AACjB,QAAM,EAAE,QAAQ,IAAI,MAAM;AAAA,IACxB;AAAA,IACA;AAAA,IACA,YAAY,KAAK,SAAS;AAAA,EAC5B;AACA,QAAM,SAAS,OAAO,KAAK,EAAE,YAAY;AACzC,QAAM,SAAS,WAAW,CAAC,GAAG;AAAA,IAC5B,CAAC,MAA0B,EAAE,OAAO,YAAY,MAAM;AAAA,EACxD;AACA,MAAI,CAAC,OAAO;AACV,UAAM,SAAS,WAAW,CAAC,GAAG,IAAI,CAAC,MAA0B,EAAE,MAAM;AACrE,UAAM,IAAI;AAAA,MACR,MAAM,SAAS,YAAY,MAAM,oBAC9B,MAAM,SAAS,gBAAgB,MAAM,KAAK,IAAI,CAAC,KAAK;AAAA,IACzD;AAAA,EACF;AACA,SAAO,MAAM;AACf;AAoBO,SAASC,MAAK,KAAmB,SAA0B,CAAC,GAAG;AACpE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,2BAA2B,GAAG,MAAM,CAAC;AAAA,EACtE;AACF;AAUO,SAASC,KAAI,KAAmB,WAAmB;AACxD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,4BAA4B,IAAI,SAAS,CAAC;AAAA,EAC3E;AACF;AAYO,SAASC,OAAM,KAAmB,SAA4B,CAAC,GAAG;AACvE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,0BAA0B,GAAG,MAAM,CAAC;AAAA,EACrE;AACF;AAyBO,SAAS,OAAO,KAAmB;AACxC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,EACjC;AACF;AAoBO,SAAS,QAAQ,KAAmB,SAA6B,CAAC,GAAG;AAC1E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,0BAA0B,GAAG,MAAM,CAAC;AAAA,EACrE;AACF;AAYO,SAASC,OAAM,KAAmB,SAAiB;AACxD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,2BAA2B,IAAI,OAAO,CAAC;AAAA,EACxE;AACF;AAQO,SAAS,aACd,KACA,SAAkC,CAAC,GACnC;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,+BAA+B,GAAG,MAAM,CAAC;AAAA,EAC1E;AACF;AASO,SAAS,SAAS,KAAmB,OAAe;AACzD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B,EAAE,MAAM;AAAA,EACV;AACF;AAuBO,SAAS,WAAW,KAAmB,OAAe;AAC3D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B,EAAE,MAAM;AAAA,EACV;AACF;AAYO,SAAS,MAAM,KAAmB,SAA2B,CAAC,GAAG;AACtE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,SAAS,GAAG,MAAM,CAAC;AAAA,EACpD;AACF;AAqCO,SAAS,YACd,KACA,WAGA;AACA,SAAO,KAAK,KAAK,OAAO,YAAY,KAAK,SAAS,CAAC;AAOrD;AAcO,SAAS,YACd,KACA,WACA,QAGA;AACA,SAAO,KAAK,KAAK,QAAQ,GAAG,YAAY,KAAK,SAAS,CAAC,iBAAiB;AAAA,IACtE;AAAA,EACF,CAAC;AAOH;AA2BO,SAAS,UACd,KACA,WACA,QAGA;AACA,SAAO,KAAK,KAAK,QAAQ,YAAY,KAAK,SAAS,GAAG;AAAA,IACpD;AAAA,EACF,CAAC;AAGH;AAmBA,eAAsB,aACpB,KACA,WACA,QAOA;AACA,QAAM,KAAK,MAAM,gBAAgB,KAAK,WAAW,MAAM;AACvD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,YAAY,KAAK,SAAS,CAAC,IAAI,IAAI,EAAE,CAAC;AAAA,EAC3C;AAOF;AAeA,eAAsB,aACpB,KACA,WACA,QAOA;AACA,QAAM,KAAK,MAAM,gBAAgB,KAAK,WAAW,MAAM;AACvD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,YAAY,KAAK,SAAS,CAAC,IAAI,IAAI,EAAE,CAAC;AAAA,EAC3C;AAOF;;;AC/iBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,OAAOC,WAAU;AACjB,SAAS,cAAAC,mBAAkB;AAkE3B,eAAsB,IACpB,KACA,QACuC;AACvC,QAAM,EAAE,SAAS,OAAO,QAAQ,SAAS,IAAI;AAC7C,QAAM,MACJ,OAAO,OACP,GAAGC,YAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK,CAAC,GACnD,WAAWC,MAAK,QAAQ,QAAQ,IAAI,EACtC;AACF,QAAM,eACJ,OAAO,iBACN,CAAC,OAAO,OAAO,WAAW,WACvB,wCACA;AAEN,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS,QAAQ;AAAA,MACjB,GAAI,OAAO,cAAc,EAAE,aAAa,OAAO,YAAY,IAAI,CAAC;AAAA,MAChE,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,IACzC;AAAA,EACF;AAEA,SAAO;AAAA,IACL,cAAc,QAAQ,SAAS,OAAO,MAAM,QAAQ,CAAC,CAAC;AAAA,EACxD;AACA,QAAM;AAAA,IACJ,EAAE,WAAW,QAAQ,WAAW,cAAc,QAAQ,aAAa;AAAA,IACnE;AAAA,IACA,YAAY;AAAA,EACd;AAEA,SAAO,EAAE,KAAK,QAAQ,KAAK,KAAK,QAAQ,IAAI;AAC9C;AAsBO,SAAS,KAAK,KAAmB,KAAc,YAAqB;AACzE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,oBAAoB,GAAG,EAAE,GAAG,KAAK,KAAK,WAAW,CAAC,CAAC;AAAA,EACpF;AACF;AAkBA,eAAsB,WACpB,KACA,KACwD;AACxD,QAAM,EAAE,IAAI,IAAI,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA,IAAI,WAAW,YAAY,KAAK;AAAA,EAClC;AACA,QAAM,MAAM,MAAM,MAAM,GAAG;AAC3B,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,MAAM,oBAAoB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,EACpE;AACA,SAAO;AAAA,IACL,OAAO,OAAO,KAAK,MAAM,IAAI,YAAY,CAAC;AAAA,IAC1C,aAAa,IAAI,QAAQ,IAAI,cAAc;AAAA,EAC7C;AACF;AAiBO,SAAS,KAAK,KAAmB,KAAc;AACpD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,yBAAyB,GAAG,GAAG,CAAC;AAAA,EACjE;AACF;AAgCO,SAAS,GAAG,KAAmB,QAAuB;AAC3D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,gBAAgB,GAAG,MAAM,CAAC;AAAA,EAC3D;AACF;AASO,SAAS,QAAQ,KAAmB;AACzC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,EACjC;AACF;AAUO,SAAS,OAAO,KAAmB,KAAc;AACtD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B,EAAE,OAAO,IAAI,OAAO,QAAQ,IAAI,QAAQ,MAAM,CAAC,IAAI,GAAG,EAAE;AAAA,EAC1D;AACF;;;AC7QA;AAAA;AAAA,iCAAAC;AAAA,EAAA;AAAA,aAAAC;AAAA,EAAA;AAAA,cAAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,gBAAAC;AAAA,EAAA;AAAA;AAsBO,IAAMC,2BAA0B,KAAK,KAAK;AACjD,IAAMC,WAAU;AAEhB,SAASC,MAAK,OAAuB;AACnC,SAAO,sBAAsB,KAAK;AACpC;AAgBO,SAASC,MAAK,KAAmB,QAAqB;AAC3D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGD,MAAK,IAAI,KAAK,CAAC,GAAG,QAAQ,mBAAmB,2BAA2B,EAAE;AAAA,EAC/E;AACF;AAcO,SAASE,KAAI,KAAmB,QAAmB;AACxD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGF,MAAK,IAAI,KAAK,CAAC,IAAI,mBAAmB,OAAO,EAAE,CAAC;AAAA,EACrD;AACF;AAqBO,SAAS,KAAK,KAAmB,QAAoB;AAC1D,QAAMG,SAAQ,IAAI,gBAAgB;AAClC,MAAI,OAAO,OAAO;AAChB,IAAAA,OAAM,IAAI,SAAS,OAAO,KAAK;AAAA,EACjC;AACA,MAAI,OAAO,OAAO;AAChB,IAAAA,OAAM,IAAI,SAAS,OAAO,OAAO,KAAK,CAAC;AAAA,EACzC;AACA,QAAMC,UAASD,OAAM,SAAS;AAC9B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGH,MAAK,IAAI,KAAK,CAAC,IAAI,mBAAmB,OAAO,EAAE,CAAC,QAAQI,UAAS,IAAIA,OAAM,KAAK,EAAE;AAAA,EACvF;AACF;AAwBO,SAAS,UAAU,KAAmB,QAAyB;AACpE,SAAO,KAA0B,KAAK,QAAQJ,MAAK,IAAI,KAAK,GAAG;AAAA,IAC7D,YAAY,OAAO;AAAA,IACnB,GAAI,OAAO,OAAO,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,EAC7C,CAAC;AACH;AAgBO,SAAS,UAAU,KAAmB,QAA0B;AACrE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,IAAI,mBAAmB,OAAO,EAAE,CAAC;AAAA,EACrD;AACF;AAOO,SAASK,QAAO,KAAmB,QAA0B;AAClE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGL,MAAK,IAAI,KAAK,CAAC,IAAI,mBAAmB,OAAO,EAAE,CAAC;AAAA,EACrD;AACF;AAWO,SAAS,QAAQ,KAAmB,QAA0B;AACnE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,IAAI,mBAAmB,OAAO,EAAE,CAAC;AAAA,EACrD;AACF;AA4BO,SAAS,OAAO,KAAmB,QAAsB;AAC9D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,IAAI,mBAAmB,OAAO,EAAE,CAAC;AAAA,IACnD,EAAE,YAAY,OAAO,WAAW;AAAA,EAClC;AACF;AAQO,SAAS,OAAO,KAAmB,QAAsB;AAC9D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAGA,MAAK,IAAI,KAAK,CAAC,IAAI,mBAAmB,OAAO,EAAE,CAAC;AAAA,IACnD,EAAE,MAAM,OAAO,KAAK;AAAA,EACtB;AACF;AA8BA,eAAsB,aACpB,KACA,QAC6B;AAC7B,QAAM,YAAY,OAAO,aAAaF;AACtC,QAAM,SAAS,IAAI,IAAgB,OAAO,MAAM;AAChD,QAAM,UAAU,CAACQ,cACf,OAAO,IAAIA,UAAS,KAAK,MAAM,OAAO,QAAQA,SAAQ,KAAK;AAE7D,QAAM,UAAU,MAAM;AAAA,IACpB,aAAa,MAAMJ,KAAI,KAAK,EAAE,IAAI,OAAO,GAAG,CAAC,GAAG;AAAA,IAChD,CAACI,cAAa,QAAQA,SAAQ,KAAKA,UAAS,UAAU;AAAA,IACtD;AAAA,MACE;AAAA,MACA,QAAQP;AAAA,MACR,UAAU,CAACO,WAAUC,WACnBD,UAAS,WACL;AAAA,QACEA,UAAS;AAAA,QACTC;AAAA,QACAD,UAAS,aACL,eAAeA,UAAS,WAAW,KAAK,KACxC;AAAA,MACN,IACA,GAAGA,UAAS,KAAK,GAAGA,UAAS,SAAS,SAAMA,UAAS,MAAM,KAAK,EAAE,GAChEA,UAAS,aACL,qBAAkBA,UAAS,WAAW,KAAK,KAC3C,EACN,WAAM,eAAeC,MAAK,CAAC;AAAA;AAAA;AAAA,MAGjC,aAAa,CAACD,cACZ,GAAGA,UAAS,KAAK,IAAIA,UAAS,UAAU,QAAQ,EAAE,IAAIA,UAAS,UAAU,EAAE;AAAA,MAC7E,YAAY,OAAO;AAAA,IACrB;AAAA,EACF;AACA,QAAM,WAAW,QAAQ;AACzB,MAAI,CAAC,QAAQ,SAAS;AACpB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA,OAAO,SAAS,WAAW,uBAAuB,SAAS,KAAK,EAAE;AAAA,IACpE;AAAA,EACF;AACA,MAAI,QAAQ,QAAQ,GAAG;AACrB,WAAO,EAAE,QAAQ,QAAQ,SAAS;AAAA,EACpC;AACA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,IACA,OAAO,SAAS,aAAa;AAAA,EAC/B;AACF;;;AC7TA;AAAA;AAAA;AAAA;AAAA,gBAAAE;AAAA,EAAA;AAAA;AAAA;AAAA,aAAAC;AAAA,EAAA,YAAAC;AAAA,EAAA;AAAA;AAwBA,SAAS,WAAW,KAA6C;AAC/D,SAAO,IAAI,cAAc,EAAE,aAAa,IAAI,YAAY,IAAI,CAAC;AAC/D;AAkBA,SAAS,UAAU,QAAkC;AACnD,SAAO,GAAG;AAAA,IACR,QAAQ,OAAO;AAAA,IACf,OAAO,OAAO;AAAA,IACd,aAAa,OAAO;AAAA,IACpB,OAAO,OAAO;AAAA,IACd,QAAQ,OAAO;AAAA,EACjB,CAAC;AACH;AAUO,SAASC,MAAK,KAAmB,SAA2B,CAAC,GAAG;AACrE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,UAAU,UAAU,MAAM,CAAC;AAAA,EAC5D;AACF;AAcO,SAAS,MACd,KACA,SAAgD,CAAC,GACjD;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,gBAAgB,UAAU,MAAM,CAAC;AAAA,EAClE;AACF;AAYO,SAASC,KAAI,KAAmB,QAAgB;AACrD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC;AAAA,EACvD;AACF;AAgCO,SAASC,QAAO,KAAmB,QAA4B;AACpE,QAAM,cAAuC;AAAA,IAC3C,OAAO,OAAO;AAAA,IACd,YAAY;AAAA,EACd;AACA,MAAI,OAAO,SAAS,QAAW;AAC7B,gBAAY,OAAO,OAAO;AAAA,EAC5B;AACA,MAAI,OAAO,WAAW,QAAW;AAC/B,gBAAY,SAAS,OAAO;AAAA,EAC9B;AACA,QAAM,cAAc,OAAO,eAAe,IAAI;AAC9C,MAAI,gBAAgB,QAAW;AAC7B,gBAAY,cAAc;AAAA,EAC5B;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B;AAAA,EACF;AACF;AAYO,SAAS,QAAQ,KAAmB,QAAgB,MAAc;AACvE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC;AAAA,IACrD,EAAE,MAAM,YAAY,SAAS,GAAG,WAAW,GAAG,EAAE;AAAA,EAClD;AACF;AAgBO,SAAS,MAAM,KAAmB,QAAgBC,UAAkB;AACzE,QAAM,cAAuC;AAAA,IAC3C,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,GAAG,WAAW,GAAG;AAAA,EACnB;AACA,MAAIA,aAAY,QAAW;AACzB,gBAAY,UAAUA;AAAA,EACxB;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC;AAAA,IACrD;AAAA,EACF;AACF;AAaO,SAAS,OAAO,KAAmB,QAAgB;AACxD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC;AAAA,IACrD,EAAE,QAAQ,QAAQ,YAAY,SAAS,GAAG,WAAW,GAAG,EAAE;AAAA,EAC5D;AACF;AA4BO,SAAS,KACd,KACA,QACA,QACA;AACA,QAAM,cAAuC;AAAA,IAC3C,YAAY;AAAA,IACZ,GAAG,WAAW,GAAG;AAAA,EACnB;AACA,MAAI,OAAO,UAAU,QAAW;AAC9B,gBAAY,QAAQ,OAAO;AAAA,EAC7B;AACA,MAAI,OAAO,SAAS,QAAW;AAC7B,gBAAY,OAAO,OAAO;AAAA,EAC5B;AACA,MAAI,OAAO,WAAW,QAAW;AAC/B,gBAAY,SAAS,OAAO;AAAA,EAC9B;AACA,MAAI,OAAO,WAAW,QAAW;AAC/B,gBAAY,SAAS,OAAO;AAAA,EAC9B;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC;AAAA,IACrD;AAAA,EACF;AACF;AAWO,SAAS,IAAI,KAAmB,QAAgB;AACrD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,WAAW,IAAI,MAAM,CAAC;AAAA,EACvD;AACF;;;AChTA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqCO,IAAM,uBAAuB;AAyF7B,SAAS,SAAS,KAAmB,SAAuB,CAAC,GAAG;AACrE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,mBAAmB,GAAG,MAAM,CAAC;AAAA,EAC9D;AACF;AAWO,SAAS,WACd,KACA,SAAiC,CAAC,GAClC;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,qBAAqB,GAAG,MAAM,CAAC;AAAA,EAChE;AACF;AAWO,SAAS,MAAM,KAAmB,SAA4B,CAAC,GAAG;AACvE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,gBAAgB,GAAG,MAAM,CAAC;AAAA,EAC3D;AACF;AAaO,SAAS,KAAK,KAAmB,QAAgB;AACtD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,iBAAiB,IAAI,MAAM,CAAC;AAAA,EAC7D;AACF;AAWO,SAAS,MAAM,KAAmB,SAA4B,CAAC,GAAG;AACvE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,gBAAgB,GAAG,MAAM,CAAC;AAAA,EAC3D;AACF;AAiBO,SAAS,QAAQ,KAAmB,QAA6B;AACtE,QAAM,OAAgC;AAAA,IACpC,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,EACjB;AACA,MAAI,OAAO,UAAU,QAAW;AAC9B,SAAK,QAAQ,OAAO;AAAA,EACtB;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B;AAAA,IACA;AAAA,EACF;AACF;AAiBO,SAAS,OAAO,KAAmB,QAA4B;AACpE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,WAAW,IAAI,OAAO,QAAQ,CAAC;AAAA,IAC9D,EAAE,SAAS,OAAO,QAAQ;AAAA,IAC1B;AAAA,EACF;AACF;AAeO,SAAS,cAAc,KAAmB,QAA4B;AAC3E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,iBAAiB,GAAG,MAAM,CAAC;AAAA,IAC1D;AAAA,IACA;AAAA,EACF;AACF;AAuBO,SAAS,MAAM,KAAmB,QAA2B;AAClE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B,EAAE,UAAU,OAAO,SAAS;AAAA,IAC5B;AAAA,EACF;AACF;AAWO,SAAS,KAAK,KAAmB,SAA2B,CAAC,GAAG;AACrE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,wBAAwB,GAAG,MAAM,CAAC;AAAA,EACnE;AACF;AAeO,SAASC,QAAO,KAAmB,OAAe;AACvD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,yBAAyB,IAAI,KAAK,CAAC;AAAA,EACpE;AACF;AAgBO,SAAS,MAAM,KAAmB,OAAe;AACtD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,yBAAyB,IAAI,KAAK,CAAC;AAAA,IAClE;AAAA,IACA;AAAA,EACF;AACF;;;AC1XA;AAAA;AAAA;AAAA;AAAA,cAAAC;AAAA;AAwBO,IAAM,wBAAwB;AAsBrC,eAAsBC,OACpB,KACmC;AACnC,QAAM,YAAY,MAAM;AAAA,IACtB;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,EACjC;AACA,QAAM,UAAU,UAAU;AAC1B,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,uCAAkC;AAAA,EACpD;AACA,SAAO,QAAQ,WAAW,CAAC;AAC7B;AAmBO,SAAS,OAAO,KAAmB,QAA6B;AACrE,QAAM,EAAE,UAAU,OAAO,YAAY,IAAI;AACzC,QAAM,iBACJ,gBAAgB,WACf,YAAY,UAAU,UAAa,YAAY,WAAW;AAC7D,QAAM,UAAU,iBACZ,sBAAsB,IAAI,KAAK,YAAY,IAAI,QAAQ,CAAC,eACxD,sBAAsB,IAAI,KAAK,YAAY,IAAI,QAAQ,CAAC;AAC5D,QAAM,OAAgC,iBAClC,EAAE,OAAO,YAAY,IACrB,EAAE,MAAM;AACZ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AChGA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+CO,SAAS,MAAM,KAAmB,SAA+B,CAAC,GAAG;AAC1E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,mBAAmB,GAAG,MAAM,CAAC;AAAA,EAC9D;AACF;AAcO,SAAS,KAAK,KAAmB,QAA6B;AACnE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,wBAAwB,GAAG,EAAE,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,EAClF;AACF;AAeO,SAAS,WACd,KACA,SAAoC,CAAC,GACrC;AACA,QAAM,OAAgC,CAAC;AACvC,MAAI,OAAO,UAAU,UAAa,OAAO,MAAM,SAAS,GAAG;AACzD,SAAK,QAAQ,OAAO;AAAA,EACtB;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B;AAAA,EACF;AACF;;;ACtGA;AAAA;AAAA;AAAA;AAAA,YAAAC;AAAA;AA6BO,IAAM,kBAAkB;AAiB/B,eAAsBC,IACpB,KACA,SAA+B,CAAC,GACD;AAC/B,QAAM,OAAO,MAAY,GAAG,KAAK;AAAA,IAC/B,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,GAAI,OAAO,YAAY,EAAE,QAAQ,GAAG,OAAO,SAAS,IAAI,IAAI,CAAC;AAAA,IAC7D,GAAI,OAAO,SAAS,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,IACjD,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,EAChD,CAAC;AAED,QAAM,WAAW,oBAAI,IAAgC;AACrD,aAAW,SAAS,KAAK,OAAO;AAG9B,UAAM,QAAQ,MAAM,IAAI,MAAM,GAAG;AACjC,QAAI,MAAM,WAAW,GAAG;AACtB;AAAA,IACF;AACA,UAAM,CAAC,WAAW,KAAK,IAAI;AAC3B,QAAI,UAAU,SAAS,IAAI,SAAS;AACpC,QAAI,CAAC,SAAS;AACZ,gBAAU,EAAE,WAAW,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC,EAAE;AACrD,eAAS,IAAI,WAAW,OAAO;AAAA,IACjC;AACA,QAAIC,OAAM,QAAQ,KAAK,KAAK,CAAC,MAAsB,EAAE,UAAU,KAAK;AACpE,QAAI,CAACA,MAAK;AACR,MAAAA,OAAM,EAAE,OAAO,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC,EAAE;AAC7C,cAAQ,KAAK,KAAKA,IAAG;AAAA,IACvB;AACA,UAAM,OAAO,MAAM,QAAQ;AAC3B,YAAQ,UAAU;AAClB,YAAQ,SAAS;AACjB,IAAAA,KAAI,UAAU;AACd,IAAAA,KAAI,SAAS;AACb,IAAAA,KAAI,KAAK,KAAK,MAAM,GAAG;AACvB,QAAI,MAAM,WAAW;AACnB,UAAI,CAAC,QAAQ,aAAa,MAAM,YAAY,QAAQ,WAAW;AAC7D,gBAAQ,YAAY,MAAM;AAAA,MAC5B;AACA,UAAI,CAAC,QAAQ,WAAW,MAAM,YAAY,QAAQ,SAAS;AACzD,gBAAQ,UAAU,MAAM;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AAIA,aAAW,WAAW,SAAS,OAAO,GAAG;AACvC,eAAWA,QAAO,QAAQ,MAAM;AAC9B,MAAAA,KAAI,KAAK,KAAK,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,MAAM,CAAC,CAAC;AAAA,IAC7C;AAAA,EACF;AACA,SAAO;AAAA,IACL,OAAO;AAAA,IACP,UAAU,CAAC,GAAG,SAAS,OAAO,CAAC,EAAE;AAAA,MAAK,CAAC,GAAG,OACvC,EAAE,WAAW,IAAI,cAAc,EAAE,WAAW,EAAE;AAAA,IACjD;AAAA,IACA,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;AAAA,EAC/C;AACF;AAEA,SAAS,MAAM,KAAqB;AAClC,QAAM,IAAI;AAAA,IACR,IACG,MAAM,GAAG,EACT,IAAI,GACH,QAAQ,WAAW,EAAE;AAAA,EAC3B;AACA,SAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAClC;AAkBA,IAAM,4BAA4B;AAclC,eAAsB,YACpB,MACA,QACmC;AACnC,QAAM,OAAO;AAAA,IACX,oBAAoB,OAAO;AAAA,IAC3B,SAAS,OAAO;AAAA,IAChB,OAAO,OAAO;AAAA,IACd,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,IAC9C,GAAI,OAAO,SAAS,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,EACnD;AAEA,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,GAAG,WAAW,qBAAqB;AAAA,MACnD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,MACzB,QAAQ,YAAY;AAAA,QAClB,OAAO,aAAa;AAAA,MACtB;AAAA,IACF,CAAC;AAAA,EACH,SAAS,KAAK;AAIZ,UAAM,IAAI;AAAA,MACR,kCAAkC,WAAW,KACvC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAGxD;AAAA,EACF;AAEA,QAAM,UAAW,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAIlD,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI;AAAA,MACR,OAAO,QAAQ,UAAU,WACrB,QAAQ,QACR,wCAAwC,IAAI,MAAM;AAAA,IACxD;AAAA,EACF;AACA,QAAMC,UAAS,QAAQ;AACvB,MAAI,CAACA,SAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAKA,SAAOA;AACT;;;AC9MA;AAAA;AAAA,aAAAC;AAAA,EAAA,YAAAC;AAAA,EAAA;AAAA;AAAA;AAgDO,SAASC,OAAK,KAAmB,SAA6B,CAAC,GAAG;AACvE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,YAAY,GAAG,MAAM,CAAC;AAAA,EACvD;AACF;AAYO,SAASC,MAAI,KAAmB,WAAmB;AACxD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,aAAa,IAAI,SAAS,CAAC;AAAA,EAC5D;AACF;AAYO,SAAS,aACd,KACA,SAA8B,CAAC,GAC/B;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,mBAAmB,GAAG,MAAM,CAAC;AAAA,EAC9D;AACF;AAaO,SAAS,eACd,KACA,UACA,SAA8B,CAAC,GAC/B;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,oBAAoB,IAAI,QAAQ,CAAC,GAAG,GAAG,MAAM,CAAC;AAAA,EAC/E;AACF;;;ACpHA;AAAA;AAAA,aAAAC;AAAA,EAAA,WAAAC;AAAA,EAAA,YAAAC;AAAA,EAAA,WAAAC;AAAA;AA4BO,SAASC,OAAK,KAAmB;AACtC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,EACjC;AACF;AAWO,SAASC,MAAI,KAAmB,KAAa;AAClD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,YAAY,IAAI,GAAG,CAAC;AAAA,EACrD;AACF;AA8BO,SAASC,KAAI,KAAmB,KAAa,QAA0B;AAC5E,QAAM,OAAgC,CAAC;AACvC,MAAI,cAAc,QAAQ;AACxB,SAAK,WAAW,OAAO;AAAA,EACzB;AACA,MAAI,eAAe,QAAQ;AACzB,SAAK,YAAY,OAAO;AAAA,EAC1B;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,YAAY,IAAI,GAAG,CAAC;AAAA,IACnD;AAAA,EACF;AACF;AAWO,SAASC,KAAI,KAAmB,KAAa;AAClD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,YAAY,IAAI,GAAG,CAAC;AAAA,EACrD;AACF;;;AChHA;AAAA;AAAA;AAAA;AAAA;AAwBO,SAAS,YAAY,KAA2C;AACrE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,EACjC,EAAE,KAAK,CAAC,QAAQ,IAAI,YAAY,CAAC,CAAC;AACpC;AA2BO,SAAS,eACd,KACA,SACwB;AACxB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B;AAAA,EACF,EAAE,KAAK,CAAC,QAAQ,IAAI,YAAY,CAAC,CAAC;AACpC;;;ACnEA;AAAA;AAAA;AAAA,cAAAC;AAAA,EAAA;AAAA;AAAA;AA+BO,SAASC,OAAK,KAAmB,SAA0B,CAAC,GAAG;AACpE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,SAAS,GAAG,MAAM,CAAC;AAAA,EACpD;AACF;AAaO,SAAS,QAAQ,KAAmB,QAAgB,MAAc;AACvE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,UAAU,IAAI,MAAM,CAAC;AAAA,IACpD,EAAE,OAAO,CAAC,IAAI,EAAE;AAAA,EAClB;AACF;AAeO,SAAS,aAAa,KAAmB,QAAgB;AAC9D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,UAAU,IAAI,MAAM,CAAC;AAAA,EACtD;AACF;AAWO,SAAS,aAAa,KAAmB,QAAgB;AAC9D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,UAAU,IAAI,MAAM,CAAC;AAAA,EACtD;AACF;;;AC/FA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiCA,SAAS,cAAc,OAAuB;AAC5C,QAAM,WAAW,MAAM,QAAQ,aAAa,EAAE;AAC9C,MAAI,WAAW,KAAK,QAAQ,GAAG;AAC7B,WAAO,KAAK,QAAQ;AAAA,EACtB;AACA,MAAI,YAAY,KAAK,QAAQ,GAAG;AAC9B,WAAO,IAAI,QAAQ;AAAA,EACrB;AACA,SAAO;AACT;AAYO,SAAS,YAAY,KAAmB;AAC7C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,EACjC;AACF;AA0BO,SAAS,cAAc,KAAmB,QAA6B;AAC5E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B;AAAA,MACE,UAAU,OAAO;AAAA,MACjB,UAAU,OAAO;AAAA,MACjB,oBAAoB,OAAO;AAAA,MAC3B,OAAO,OAAO;AAAA,IAChB;AAAA,EACF;AACF;AAkCO,SAAS,WAAW,KAAmB,QAA0B;AACtE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B;AAAA,MACE,aAAa,OAAO;AAAA,MACpB,UAAU,OAAO;AAAA,MACjB,oBAAoB,OAAO;AAAA,MAC3B,aAAa,OAAO;AAAA,IACtB;AAAA,EACF;AACF;AAMA,eAAe,aAAa,KAAmB,MAA+B;AAC5E,QAAM,aAAa,cAAc,IAAI;AACrC,QAAM,MAAM,MAAM,YAAY,GAAG;AACjC,QAAM,SAAS,IAAI,WAAW,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,SAAS,UAAU;AACnE,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,oBAAoB,IAAI,eAAe;AAAA,EACzD;AACA,SAAO,MAAM;AACf;AAiBA,eAAsB,eAAe,KAAmB,MAAc;AACpE,QAAM,KAAK,MAAM,aAAa,KAAK,IAAI;AACvC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,iCAAiC,IAAI,EAAE,CAAC;AAAA,EACzE;AACF;AAqBA,eAAsB,eACpB,KACA,MACA,aACA;AACA,QAAM,KAAK,MAAM,aAAa,KAAK,IAAI;AACvC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,iCAAiC,IAAI,EAAE,CAAC;AAAA,IACvE,EAAE,YAAY;AAAA,EAChB;AACF;AAuBO,SAAS,aACd,KACA,SAA6B,CAAC,GAC9B;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,kBAAkB,GAAG,MAAM,CAAC;AAAA,EAC7D;AACF;AAaO,SAAS,YAAY,KAAmB,WAAmB;AAChE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK,mBAAmB,IAAI,SAAS,CAAC;AAAA,EAClE;AACF;AAcO,SAAS,YAAY,KAAmB;AAC7C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,EACjC;AACF;AAoBO,SAAS,YAAY,KAAmB,QAAgC;AAC7E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,sBAAsB,IAAI,KAAK;AAAA,IAC/B;AAAA,MACE,uBAAuB,OAAO;AAAA,MAC9B,iCAAiC,OAAO;AAAA,MACxC,wBAAwB,OAAO;AAAA,IACjC;AAAA,EACF;AACF;;;ACpPA,SAAS,QAA0B,KAAQ,KAAgC;AACzE,QAAM,QAAiC,CAAC;AACxC,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC/C,QAAI,OAAO,UAAU,YAAY;AAC/B,YAAM,IAAI,IAAI,IAAI,SAAoB,MAAM,KAAK,GAAG,IAAI;AAAA,IAC1D;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,eAAe,SAA2C;AACjE,QAAM,SAAS,QAAQ,UAAU,QAAQ,IAAI,oBAAoB,KAAK;AACtE,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA;AAAA;AAAA,IAGA,OAAO,QAAQ,SAAS,mBAAmB;AAAA,IAC3C,SACE,QAAQ,WAAW,QAAQ,IAAI,qBAAqB,KAAK;AAAA,EAC7D;AACF;AAEA,SAAS,YAAY,KAAmB;AACtC,SAAO;AAAA;AAAA,IAEL,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAST,OAAO,OAAe;AACpB,aAAO,YAAY;AAAA,QACjB,GAAG;AAAA,QACH;AAAA,QACA,aACE,UAAU,IAAI,QACV,IAAI,cACH,IAAI,eAAe,IAAI;AAAA,MAChC,CAAC;AAAA,IACH;AAAA,IAEA,OAAO,QAAQ,eAAO,GAAG;AAAA,IACzB,OAAO,QAAQ,eAAO,GAAG;AAAA,IACzB,WAAW,QAAQ,mBAAW,GAAG;AAAA,IACjC,QAAQ,QAAQ,gBAAW,GAAG;AAAA,IAC9B,SAAS,QAAQ,iBAAS,GAAG;AAAA,IAC7B,MAAM,QAAQ,cAAM,GAAG;AAAA,IACvB,MAAM,QAAQ,cAAM,GAAG;AAAA,IACvB,aAAa,QAAQ,qBAAa,GAAG;AAAA,IACrC,gBAAgB,QAAQ,wBAAgB,GAAG;AAAA,IAC3C,sBAAsB,QAAQ,8BAAsB,GAAG;AAAA,IACvD,iBAAiB,QAAQ,yBAAiB,GAAG;AAAA,IAC7C,mBAAmB,QAAQ,2BAAmB,GAAG;AAAA,IACjD,IAAI,QAAQ,YAAI,GAAG;AAAA,IACnB,aAAa,QAAQ,qBAAa,GAAG;AAAA,IACrC,SAAS,QAAQ,iBAAS,GAAG;AAAA,IAC7B,OAAO;AAAA,MACL,GAAG,QAAQ,eAAO,GAAG;AAAA;AAAA;AAAA;AAAA,MAIrB,aAAa,CAAkC,cACvC,YAAY,KAAK,SAAS;AAAA,MAClC,aAAa,CACX,WACA,WACS,YAAY,KAAK,WAAW,MAAM;AAAA,MAC7C,WAAW,CACT,WACA,WACS,UAAU,KAAK,WAAW,MAAM;AAAA,MAC3C,cAAc,CACZ,WACA,WACS,aAAa,KAAK,WAAW,MAAM;AAAA,MAC9C,cAAc,CACZ,WACA,WACS,aAAa,KAAK,WAAW,MAAM;AAAA,IAChD;AAAA,IACA,OAAO,QAAQ,eAAO,GAAG;AAAA,IACzB,OAAO,QAAQ,eAAO,GAAG;AAAA,IACzB,QAAQ,QAAQ,gBAAQ,GAAG;AAAA,IAC3B,QAAQ,QAAQ,gBAAQ,GAAG;AAAA,IAC3B,SAAS,QAAQ,iBAAS,GAAG;AAAA,IAC7B,WAAW,QAAQ,mBAAW,GAAG;AAAA,IACjC,cAAc,QAAQ,sBAAc,GAAG;AAAA,IACvC,UAAU,QAAQ,kBAAU,GAAG;AAAA,IAC/B,UAAU,QAAQ,kBAAU,GAAG;AAAA,IAC/B,SAAS,QAAQ,iBAAS,GAAG;AAAA,IAC7B,UAAU,QAAQ,kBAAU,GAAG;AAAA,IAC/B,OAAO,QAAQ,eAAO,GAAG;AAAA,IACzB,OAAO,QAAQ,eAAO,GAAG;AAAA,EAC3B;AACF;AAaO,SAAS,kBACd,UAA8B,CAAC,GAClB;AACb,SAAO,YAAY,eAAe,OAAO,CAAC;AAC5C;;;AC7JA,IAAI;AACG,IAAM,QAAqB,IAAI,MAAM,CAAC,GAAkB;AAAA,EAC7D,IAAI,GAAG,MAAM;AACX,iBAAa,kBAAkB;AAC/B,UAAM,QAAQ,QAAQ,IAAI,UAAU,MAAM,QAAQ;AAClD,WAAO,OAAO,UAAU,aAAa,MAAM,KAAK,QAAQ,IAAI;AAAA,EAC9D;AACF,CAAC;AAED,IAAO,gBAAQ;","names":["path","status","search","get","list","list","get","list","list","list","start","start","count","view","entities","documents","tracked","start","list","query","source","pages","DEFAULT_WAIT_TIMEOUT_MS","get","list","DEFAULT_WAIT_TIMEOUT_MS","POLL_MS","base","approve","list","get","job","start","get","base","get","DEFAULT_WAIT_TIMEOUT_MS","run","DEFAULT_WAIT_TIMEOUT_MS","POLL_MS","base","list","source","start","run","set","base","query","query","get","list","list","get","summary","POLL_MS","start","live","get","get","batch","get","list","stats","list","get","stats","batch","path","createHash","createHash","path","DEFAULT_WAIT_TIMEOUT_MS","get","list","resume","DEFAULT_WAIT_TIMEOUT_MS","POLL_MS","base","list","get","query","search","resume","resource","start","create","get","list","list","get","create","comment","getRun","getRun","list","list","ls","ls","run","status","get","list","list","get","del","get","list","set","list","get","set","del","list","list"]}
|
|
1
|
+
{"version":3,"sources":["../src/ctx.ts","../src/config.ts","../src/parseJsonConfig.ts","../src/ops/agent.ts","../src/errors.ts","../src/http.ts","../src/ops/tasks.ts","../src/ops/analytics.ts","../src/ops/events.ts","../src/ops/crashes.ts","../src/ops/cron.ts","../src/ops/data.ts","../src/ops/dataSources.ts","../src/sleep.ts","../src/poll.ts","../src/output.ts","../src/upload.ts","../src/ops/dataSourceJobs.ts","../src/ops/dataSourceConnectors.ts","../src/ops/dataSourceEvals.ts","../src/ops/dataSourceMappers.ts","../src/ops/db.ts","../src/ops/diagnostics.ts","../src/ops/releases.ts","../src/ops/domains.ts","../src/ops/email.ts","../src/ops/files.ts","../src/ops/infra.ts","../src/ops/issues.ts","../src/ops/jewels.ts","../src/ops/methods.ts","../src/ops/prerender.ts","../src/ops/qaRecordings.ts","../src/ops/requests.ts","../src/ops/secrets.ts","../src/ops/settings.ts","../src/ops/users.ts","../src/ops/voice.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["/**\n * The bound context every operation runs against: which app, as whom, where.\n *\n * Ops in src/ops/ take this as their first argument and are otherwise pure —\n * no env reads, no process coupling — so the same functions serve both the\n * CLI (context from the environment, built once in prod.ts) and the importable\n * client (context from createAdminClient's options).\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { WORKSPACE_DIR } from './config.js';\nimport { parseJsonConfig } from './parseJsonConfig.js';\n\nexport interface AdminContext {\n /** Org-scoped `sk_` API key. */\n apiKey: string;\n /** The app every operation is scoped to. */\n appId: string;\n /**\n * Who is acting, when that is not `appId` itself — set only when the caller\n * has retargeted at another app (`--app`, or `forApp()`), and carrying the\n * app they came FROM.\n *\n * Writes that record authorship attach it, so a cross-app issue says which\n * app filed it without the caller having to remember a second flag. That\n * matters more than it sounds: the information was always available here and\n * being optional at the call site is precisely how it came to be omitted\n * everywhere.\n */\n originAppId?: string;\n /** API origin, no trailing slash. */\n baseUrl: string;\n}\n\nexport const DEFAULT_BASE_URL = 'https://api.mindstudio.ai';\n\n/**\n * Resolve the appId the way the CLI always has: `mindstudio.json` in the\n * workspace. Throws a plain Error with the CLI's historical message text —\n * prod.ts's catch turns it into `{error}` + exit 10, and the client surfaces\n * it as-is.\n */\nexport function loadWorkspaceAppId(workspaceDir = WORKSPACE_DIR): string {\n const manifestPath = path.join(workspaceDir, 'mindstudio.json');\n let raw: string;\n try {\n raw = fs.readFileSync(manifestPath, 'utf-8');\n } catch (err: any) {\n if (err.code === 'ENOENT') {\n throw new Error(`mindstudio.json not found at ${manifestPath}`);\n }\n throw new Error(`Failed to read mindstudio.json: ${err.message}`);\n }\n // Tolerant parse, but deliberately read-only: this is a short-lived process\n // and shouldn't mutate the workspace out from under the running sandbox.\n const result = parseJsonConfig<{ appId?: string }>(raw);\n if (!result.ok) {\n throw new Error(`Failed to parse mindstudio.json: ${result.error}`);\n }\n if (!result.value.appId) {\n throw new Error('mindstudio.json exists but has no appId');\n }\n return result.value.appId;\n}\n","/**\n * Local-environment locations for the commands that touch the box rather than\n * the management API: the workspace (files put/get, datasources add, releases\n * wait's git HEAD sniff) and the sandbox sidecar (qa-recordings export). API\n * credentials and appId resolution live in ctx.ts.\n */\n\n// The dev box sets `WORKSPACE_DIR`, so the fallback is only reached outside one. It names the box's\n// own layout rather than a stale provider path so that a caller without the env var lands somewhere\n// recognisable instead of on a directory that has not existed for two sandbox generations.\nexport const WORKSPACE_DIR =\n process.env['WORKSPACE_DIR'] || '/home/remy/workspace';\n\n// The sandbox's local sidecar, on a fixed port started by the sandbox\n// supervisor (mindstudio-sandbox/src/index.ts). Only `qa-recordings export` uses\n// it — the one operation needing the dev box's headless Chrome and ffmpeg\n// rather than the management API. Nothing answering is what running outside a\n// sandbox looks like, and that command says so.\nexport const SIDECAR_URL =\n process.env['REMY_SIDECAR_URL'] || 'http://127.0.0.1:4388';\n","/**\n * Pure parser for MindStudio-owned JSON config files. No I/O, no repair.\n *\n * App configs (`mindstudio.json`, interface configs like `web.json`) are\n * authored by remy, so they pick up the usual LLM-JSON slop — most often a\n * trailing comma left behind when an array entry is deleted.\n *\n * Strategy: strict JSON.parse first, JSON5 as a rescue. Strict-first means the\n * steady state is unaffected; the JSON5 path only engages for a file that would\n * otherwise have failed outright.\n *\n * Deliberately pure and read-only: this short-lived CLI must not mutate the\n * workspace out from under the running sandbox, whose own read path\n * (`jsonConfig.ts` in mindstudio-sandbox, where this module originated)\n * repairs the file on disk for the callers that DO write.\n */\n\nimport JSON5 from 'json5';\n\nexport type ParseResult<T> =\n | { ok: true; value: T; repaired: false }\n /** Strict parse failed; JSON5 rescued it. `error` is the strict failure. */\n | { ok: true; value: T; repaired: true; error: string }\n /** `notFound` separates \"no such file\" from \"file exists but is broken\" —\n * callers log those very differently. */\n | { ok: false; error: string; notFound: boolean };\n\nexport function msg(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * Parse a config string. Pure — no I/O, no repair. Use this when the caller\n * already holds the file contents, or must not write (e.g. the CLI).\n */\nexport function parseJsonConfig<T>(raw: string): ParseResult<T> {\n let strictError: string;\n try {\n return { ok: true, value: JSON.parse(raw) as T, repaired: false };\n } catch (err) {\n strictError = msg(err);\n }\n\n try {\n return {\n ok: true,\n value: JSON5.parse(raw) as T,\n repaired: true,\n error: strictError,\n };\n } catch (err) {\n // Report the JSON5 error, not the strict one. JSON5 got further — it\n // tolerated the slop and failed on whatever is genuinely broken (a\n // truncated write, say), so its position is the actionable one. The\n // strict error would point at the first trailing comma and mislead.\n return { ok: false, error: msg(err), notFound: false };\n }\n}\n","/**\n * Agent-chat thread log operations.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/agent.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n AgentThreadsListResult,\n AgentThreadsGetResult,\n} from '../types/agent.js';\n\nexport interface ThreadsListParams {\n /** Max threads per page (default 20, server clamps to 100). */\n limit?: number;\n /** Pagination cursor from a prior page's `nextCursor`. */\n cursor?: string;\n}\n\n/**\n * Every conversation the app's agent has had, newest activity first.\n *\n * Returns cursored pages; pass `nextCursor` from one page as `cursor` for the\n * next. Transcripts are not included — fetch a thread with `threadsGet`.\n *\n * `toolErrorCount` and `hasTurnError` are how you find the conversations worth\n * reading, and `devSession` separates your own test threads from real traffic.\n *\n * @example\n * const { threads } = await admin.agent.threadsList({ limit: 20 });\n * const broken = threads.filter((t) => t.toolErrorCount > 0 || t.hasTurnError);\n */\nexport function threadsList(ctx: AdminContext, params: ThreadsListParams = {}) {\n return call<AgentThreadsListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/agent-threads${qs(params)}`,\n );\n}\n\n/**\n * One thread with its full transcript: what the user said, what the agent\n * replied, which tools it called with which arguments, and what came back.\n *\n * This is the primary tool for iterating on an agent's system prompt and tool\n * descriptions — read what actually happened rather than guessing. Each method\n * tool call carries a `requestId`; pass it to `requests.get()` for that call's\n * input, output, stdout and error.\n *\n * @throws AdminApiError `thread_not_found` (404).\n * @example\n * const thread = await admin.agent.threadsGet('4f6c…');\n * console.log(thread.messages);\n */\nexport function threadsGet(ctx: AdminContext, threadId: string) {\n return call<AgentThreadsGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/agent-threads/${seg(threadId)}`,\n );\n}\n","/**\n * Error + exit-code vocabulary for the remy-admin CLI.\n *\n * Exit codes are a contract remy can branch on without parsing stdout. The\n * 0-4 range belongs to `releases wait` (see HELP_RELEASES) and predates this\n * module; `generic` is deliberately 10 so that a bad API key or an unparseable\n * mindstudio.json can never be mistaken for exit 1 = \"build failed\".\n */\n\nexport const EXIT = {\n /** live (or preview, for a feature branch) */\n ok: 0,\n /** `releases wait` only: the build failed */\n buildFailed: 1,\n /** `releases wait` only: still building when --timeout elapsed */\n timeout: 2,\n /** `releases wait` only: no release ever appeared for the commit */\n notFound: 3,\n /** `releases wait` only: built, but a newer release replaced it */\n superseded: 4,\n /** Any other failure: bad arguments, missing config, API error, timeout. */\n generic: 10,\n} as const;\n\n/**\n * A failure that should be reported as `{\"error\": ...}` on stdout.\n *\n * Thrown rather than exiting so that main()'s catch can print the message and\n * set `process.exitCode`, letting node flush stdout naturally. Calling\n * process.exit() here would truncate the message at one pipe buffer (64 KiB) —\n * which is exactly how remy invokes this CLI.\n */\nexport class CliError extends Error {\n constructor(\n message: string,\n readonly code: number = EXIT.generic,\n ) {\n super(message);\n this.name = 'CliError';\n }\n}\n\n/**\n * A failure caused by bad input. Carries the command's verbatim usage string\n * so the caller sees exactly what it should have typed.\n */\nexport class UsageError extends CliError {\n constructor(detail: string | null, usage: string) {\n super([detail, usage].filter(Boolean).join('\\n'));\n this.name = 'UsageError';\n }\n}\n\n/**\n * Report a failure and stop.\n *\n * Throws rather than calling process.exit(): exit() does not drain an async\n * stdout write, so a message larger than one pipe buffer (64 KiB) was truncated\n * mid-JSON — and a pipe is exactly how remy invokes this CLI. The entry point's\n * catch prints and sets process.exitCode, letting node flush on its own. Typed\n * `never`, so callers use it as a terminator.\n */\nexport function fatal(message: string): never {\n throw new CliError(message);\n}\n\n/**\n * A non-2xx API response, thrown by the ops core (src/http.ts) so both skins\n * share one error surface: the CLI's entry-point catch prints `.message`\n * (built to the CLI's historical string) and exits 10; an importing caller\n * gets the structured fields.\n */\nexport class AdminApiError extends Error {\n constructor(\n readonly method: string,\n readonly path: string,\n readonly status: number,\n readonly body: unknown,\n ) {\n super(`API ${method} ${path} returned ${status}: ${JSON.stringify(body)}`);\n this.name = 'AdminApiError';\n }\n}\n\n/** A request that exceeded its time bound before a response arrived. */\nexport class AdminTimeoutError extends Error {\n constructor(label: string, timeoutMs: number) {\n super(`${label} timed out after ${timeoutMs / 1000}s`);\n this.name = 'AdminTimeoutError';\n }\n}\n","/**\n * The authed HTTP core under every operation, context-bound and process-free:\n * it throws typed errors (AdminApiError / AdminTimeoutError) and never prints\n * or exits, so the same functions serve the CLI and the importable client.\n *\n * Two entry points, because ops need two failure shapes: `call` throws on a\n * bad status (most ops), `tryCall` returns the status so a caller can tolerate\n * one (releases waitForCommit polls through 404s). The CLI-only raw/SSE\n * passthroughs live in cliStream.ts — they are output devices, not API calls.\n */\n\nimport type { AdminContext } from './ctx.js';\nimport { AdminApiError, AdminTimeoutError } from './errors.js';\n\n/** Bound one request, so a hung API call can't hang the caller indefinitely. */\nexport const REQUEST_TIMEOUT_MS = 30_000;\n/**\n * How long a poll loop keeps retrying through transient failures before it\n * gives up. A `--wait` can run for many minutes over a tunnel; one 502 from a\n * gateway says nothing about the thing being waited on.\n */\nexport const TRANSIENT_GRACE_MS = 2 * 60_000;\n\n/**\n * A failure worth retrying inside a poll loop: the API answered 5xx (a gateway\n * or tunnel between the CLI and the platform hiccupped), the request timed out,\n * or the socket never connected. A 4xx is a real answer and is not.\n */\nexport function isTransientError(err: unknown): boolean {\n if (err instanceof AdminApiError) {\n return err.status >= 500;\n }\n if (err instanceof AdminTimeoutError) {\n return true;\n }\n // undici surfaces a failed connection as a TypeError('fetch failed').\n return err instanceof TypeError;\n}\n/** The raw Lighthouse report is a large artifact pulled from object storage. */\nexport const REPORT_TIMEOUT_MS = 60_000;\n\n/** Percent-encode one URL path segment. */\nexport function seg(value: string | number): string {\n return encodeURIComponent(String(value));\n}\n\n/**\n * Query string ('' or '?a=1&b=2') from a params object; undefined/null values\n * are skipped. The ops-side counterpart of the CLI's Args.query().\n *\n * Takes `object` rather than a Record so ops can pass their typed params\n * interfaces directly (interfaces lack index signatures, so a Record\n * constraint would force a cast at every call site).\n */\nexport function qs(params: object): string {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined || value === null) {\n continue;\n }\n // An array repeats the key (`?label=a&label=b`) rather than joining with a\n // comma, which is the form express parses back into an array.\n if (Array.isArray(value)) {\n for (const entry of value) {\n search.append(key, String(entry));\n }\n continue;\n }\n search.set(key, String(value));\n }\n const text = search.toString();\n return text ? `?${text}` : '';\n}\n\nfunction authHeaders(ctx: AdminContext): Record<string, string> {\n return {\n Authorization: `Bearer ${ctx.apiKey}`,\n 'Content-Type': 'application/json',\n };\n}\n\n/**\n * Read a response body without assuming it is JSON.\n *\n * A 204 or an empty body is a legitimate success for the DELETE endpoints\n * (`secrets delete`, `users revoke-api-key`). res.json() throws on those, which\n * turned a successful mutation into a reported failure.\n */\nexport async function readBody(res: Response): Promise<any> {\n if (res.status === 204) {\n return { ok: true, status: 204 };\n }\n const text = await res.text().catch(() => '');\n if (!text.trim()) {\n return { ok: true, status: res.status };\n }\n try {\n return JSON.parse(text);\n } catch {\n return { raw: text };\n }\n}\n\nexport async function fetchWithTimeout(\n url: string,\n init: RequestInit,\n timeoutMs: number,\n label: string,\n): Promise<Response> {\n try {\n return await fetch(url, {\n ...init,\n signal: AbortSignal.timeout(timeoutMs),\n });\n } catch (err: any) {\n if (err?.name === 'TimeoutError') {\n throw new AdminTimeoutError(label, timeoutMs);\n }\n throw err;\n }\n}\n\n/**\n * `T` is the endpoint's response shape, transcribed from the youai-api route\n * in `src/types/`. Defaults to `unknown` so an unannotated call site that\n * touches the result fails to compile rather than silently going untyped.\n * Note: 204/empty responses surface as `{ ok: true, status }` (see readBody) —\n * delete-style result types reflect that, not the route's (absent) JSON.\n */\nexport async function call<T = unknown>(\n ctx: AdminContext,\n method: string,\n apiPath: string,\n body?: Record<string, unknown>,\n // Ops that hold the request for a full method/jewel run (jewels resolve\n // --approve, jewels dryrun) pass their own bound.\n timeoutMs: number = REQUEST_TIMEOUT_MS,\n): Promise<T> {\n const res = await fetchWithTimeout(\n `${ctx.baseUrl}${apiPath}`,\n {\n method,\n headers: authHeaders(ctx),\n ...(body ? { body: JSON.stringify(body) } : {}),\n },\n timeoutMs,\n `API ${method} ${apiPath}`,\n );\n\n if (!res.ok) {\n throw new AdminApiError(method, apiPath, res.status, await readBody(res));\n }\n\n return readBody(res);\n}\n\n/**\n * Like `call`, but never throws on an HTTP status — returns a structured\n * result so a caller can react to one (e.g. tolerate a 404 while a release\n * row is still being created after a push).\n */\nexport async function tryCall<T = unknown>(\n ctx: AdminContext,\n method: string,\n apiPath: string,\n): Promise<{ ok: boolean; status: number; body: T }> {\n const res = await fetchWithTimeout(\n `${ctx.baseUrl}${apiPath}`,\n { method, headers: authHeaders(ctx) },\n REQUEST_TIMEOUT_MS,\n `API ${method} ${apiPath}`,\n );\n return { ok: res.ok, status: res.status, body: await readBody(res) };\n}\n\n/** @internal Exposed for cliStream.ts, which shares the auth header shape. */\nexport { authHeaders };\n","/**\n * Task log operations: every task agent (`runTask`) the app ran.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/tasks.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type { TasksListResult, TasksGetResult } from '../types/tasks.js';\n\nexport interface TasksListParams {\n /** Max traces per page (default 20, server clamps to 100). */\n limit?: number;\n /** Pagination cursor from a prior page's `nextCursor`. */\n cursor?: string;\n}\n\n/**\n * Every task the app ran, newest started first, kept for 90 days.\n *\n * Returns cursored pages; pass `nextCursor` from one page as `cursor` for the\n * next. Transcripts are not included — fetch one with `get`.\n *\n * `outcome`, `toolErrorCount` and `hasTurnError` are how you find the runs\n * worth reading, and `devSession` separates your own dev runs from real\n * traffic.\n *\n * @example\n * const { traces } = await admin.tasks.list({ limit: 10 });\n * const broken = traces.filter((t) => t.outcome !== 'answered' || t.toolErrorCount > 0);\n */\nexport function list(ctx: AdminContext, params: TasksListParams = {}) {\n return call<TasksListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/task-traces${qs(params)}`,\n );\n}\n\n/**\n * One task with its full transcript: the prompt and tools it was given, its\n * input, each turn's reply and reasoning, and every tool call with what came\n * back.\n *\n * This is the primary tool for iterating on a task agent's prompt and tool\n * descriptions — read what actually happened rather than guessing. A method\n * tool's result carries a `requestId`; pass it to `requests.get()` for that\n * call's input, output, stdout and error. `result.traceId` from `runTask()`\n * is the id.\n *\n * @throws AdminApiError `task_trace_not_found` (404).\n * @example\n * const trace = await admin.tasks.get('0b9e…');\n * console.log(trace.outcome, trace.messages);\n */\nexport function get(ctx: AdminContext, traceId: string) {\n return call<TasksGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/task-traces/${seg(traceId)}`,\n );\n}\n","/**\n * Analytics (insights) operations.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/analytics.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n AnalyticsAiSourcesResult,\n AnalyticsBatchResult,\n AnalyticsCrawlersResult,\n AnalyticsLiveResult,\n AnalyticsMapResult,\n AnalyticsQueryResult,\n AnalyticsSourcesResult,\n} from '../types/analytics.js';\n\n/** Scope + time-window + click-filter params accepted by `sources`. */\nexport interface SourcesParams {\n /** Scope to a specific release id. */\n releaseId?: string;\n /** ISO date string for the start of the query window. */\n start?: string;\n /** ISO date string for the end of the query window. */\n end?: string;\n /** Max rows to return (default 25). */\n limit?: number;\n /** Row offset for paging. */\n offset?: number;\n /** Click-filter: equality match on path. Per-event-table backed (90-day retention). */\n path?: string;\n /** Click-filter: equality match on referrer host. Per-event-table backed (90-day retention). */\n referrerHost?: string;\n /** Click-filter: equality match on country. Per-event-table backed (90-day retention). */\n country?: string;\n /** Click-filter: equality match on city. Per-event-table backed (90-day retention). */\n city?: string;\n /** Click-filter: equality match on device type. Per-event-table backed (90-day retention). */\n device?: string;\n /** Click-filter: equality match on browser. Per-event-table backed (90-day retention). */\n browser?: string;\n /** Click-filter: equality match on OS. Per-event-table backed (90-day retention). */\n os?: string;\n /** Click-filter: equality match on language. Per-event-table backed (90-day retention). */\n language?: string;\n /** Click-filter: equality match on UTM source. Per-event-table backed (90-day retention). */\n utmSource?: string;\n /** Click-filter: equality match on UTM medium. Per-event-table backed (90-day retention). */\n utmMedium?: string;\n /** Click-filter: equality match on UTM campaign. Per-event-table backed (90-day retention). */\n utmCampaign?: string;\n}\n\n/** Same click-filter + scope params as `SourcesParams`; accepted by `map`. */\nexport interface MapParams {\n /** Scope to a specific release id. */\n releaseId?: string;\n /** ISO date string for the start of the query window. */\n start?: string;\n /** ISO date string for the end of the query window. */\n end?: string;\n /** Max points to return (default 500). */\n limit?: number;\n /** Row offset for paging. */\n offset?: number;\n /** Click-filter: equality match on path. Per-event-table backed (90-day retention). */\n path?: string;\n /** Click-filter: equality match on referrer host. Per-event-table backed (90-day retention). */\n referrerHost?: string;\n /** Click-filter: equality match on country. Per-event-table backed (90-day retention). */\n country?: string;\n /** Click-filter: equality match on city. Per-event-table backed (90-day retention). */\n city?: string;\n /** Click-filter: equality match on device type. Per-event-table backed (90-day retention). */\n device?: string;\n /** Click-filter: equality match on browser. Per-event-table backed (90-day retention). */\n browser?: string;\n /** Click-filter: equality match on OS. Per-event-table backed (90-day retention). */\n os?: string;\n /** Click-filter: equality match on language. Per-event-table backed (90-day retention). */\n language?: string;\n /** Click-filter: equality match on UTM source. Per-event-table backed (90-day retention). */\n utmSource?: string;\n /** Click-filter: equality match on UTM medium. Per-event-table backed (90-day retention). */\n utmMedium?: string;\n /** Click-filter: equality match on UTM campaign. Per-event-table backed (90-day retention). */\n utmCampaign?: string;\n}\n\nexport interface AiSourcesParams {\n /** Scope to a specific release id. */\n releaseId?: string;\n /** ISO date string for the start of the query window. */\n start?: string;\n /** ISO date string for the end of the query window. */\n end?: string;\n /** Max vendor rows to return (default 50). */\n limit?: number;\n}\n\nexport interface CrawlersParams {\n /**\n * Sub-endpoint to dispatch to:\n * - `overview` — vendor totals + top-crawled pages.\n * - `timeseries` — stacked-per-vendor hit counts bucketed over time.\n * - `recent` — last N raw crawler hit rows (curiosity feed).\n */\n kind: 'overview' | 'timeseries' | 'recent';\n /** Scope to a specific release id. */\n releaseId?: string;\n /** ISO date string for the start of the query window. */\n start?: string;\n /** ISO date string for the end of the query window. */\n end?: string;\n /** Max rows to return (default varies by sub). */\n limit?: number;\n /** Number of time buckets for `timeseries` (default 24). */\n buckets?: number;\n /** Max top-pages rows for `overview` (default 20, max 100). */\n topPagesLimit?: number;\n}\n\n/**\n * Run a single analytics query: metrics × dimensions × filters × time.\n *\n * The query body shape (all fields optional except `metrics`):\n * ```\n * metrics [\"pageviews\" | \"visitors\" | \"visits\" | \"events\", ...]\n * dimensions at most ONE entity dimension OR \"time\" (not both):\n * path referrerHost sourceCategory country city deviceType\n * browser os language visitorType utmSource utmMedium\n * utmCampaign utmTerm utmContent eventName\n * granularity required with \"time\": \"5m\" | \"hour\" | \"day\" | \"week\" | \"month\"\n * timezone IANA zone for day/week/month boundaries (default UTC)\n * filters [[op, dimension, [values...]], ...]\n * ops: \"is\" (any of) | \"is_not\" (none of) | \"contains\"\n * dateRange \"1h\" | \"24h\" | \"7d\" | \"30d\" | \"90d\" | \"all\"\n * or [\"<startISO>\", \"<endISO>\"] (default \"24h\")\n * orderBy grouped only: [[\"pageviews\" | \"events\", \"asc\" | \"desc\"]]\n * limit grouped only; default 25, max 1000\n * offset paging\n * releaseId optional release scope\n * ```\n *\n * Routing (rollup vs per-event table), window clamping, and metric\n * availability are determined by the query shape; the response `meta`\n * reports `source`, `window.served`, `clamped`, and `metricsOmitted`.\n * Summary KPIs, timeseries, every top-N, and event stats are all query\n * compositions — no dedicated endpoints exist for them.\n *\n * @example\n * const { results, meta } = await admin.analytics.query({\n * metrics: ['pageviews', 'visitors'],\n * dimensions: ['path'],\n * dateRange: '30d',\n * limit: 10,\n * });\n */\nexport function query(ctx: AdminContext, body: Record<string, unknown>) {\n return call<AnalyticsQueryResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/insights/query`,\n body,\n );\n}\n\n/**\n * Run up to 10 independent query bodies in one round trip.\n *\n * Results are in request order; each entry is a full `AnalyticsQueryResult`\n * (with its own `meta`). Accepts a bare array of query bodies or the wire\n * shape `{ queries: [...] }`.\n *\n * @example\n * const { results } = await admin.analytics.batch([\n * { metrics: ['pageviews', 'visits', 'visitors'] },\n * { metrics: ['pageviews'], dimensions: ['path'], limit: 10 },\n * ]);\n */\nexport function batch(ctx: AdminContext, queries: unknown[] | undefined) {\n return call<AnalyticsBatchResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/insights/query-batch`,\n { queries },\n );\n}\n\n/**\n * Ranked traffic sources: per-session first source (UTM > referrer > direct),\n * with category and vendor classification applied server-side.\n *\n * Per-event-table backed — bounded by 90-day retention. Click-filter params\n * accept equality only; use `query` with `\"is_not\"` / `\"contains\"` filters or\n * multi-dimension grouping for richer analysis.\n *\n * @example\n * const { results, total } = await admin.analytics.sources({ limit: 10 });\n */\nexport function sources(ctx: AdminContext, params: SourcesParams = {}) {\n return call<AnalyticsSourcesResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/insights/sources${qs(params)}`,\n );\n}\n\n/**\n * City lat/lon points for geo rendering.\n *\n * When any click-filter is present the per-event table is queried (90-day\n * retention); without filters the rollup table is used (full history).\n *\n * @example\n * const { points, total } = await admin.analytics.map({ country: 'US' });\n */\nexport function map(ctx: AdminContext, params: MapParams = {}) {\n return call<AnalyticsMapResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/insights/map${qs(params)}`,\n );\n}\n\n/**\n * One-shot live visitor snapshot: current unique count, country breakdown,\n * and up to 60 one-minute sparkline samples from the last hour.\n *\n * Backed by Redis presence keys; no analytics-table query.\n *\n * @example\n * const { count, countries, sparkline } = await admin.analytics.live();\n */\nexport function live(ctx: AdminContext) {\n return call<AnalyticsLiveResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/insights/live`,\n );\n}\n\n/**\n * Per-vendor AI-referral breakdown.\n *\n * Filters referrer-host rows to known AI-assistant hosts and aggregates up\n * to vendor level at read time. Multiple hosts may map to the same vendor\n * (e.g. `chat.openai.com` + `chatgpt.com` → OpenAI). Returns both the\n * vendor-level aggregates and the raw host-level rows.\n *\n * @example\n * const { results, hosts } = await admin.analytics.aiSources();\n */\nexport function aiSources(ctx: AdminContext, params: AiSourcesParams = {}) {\n return call<AnalyticsAiSourcesResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/insights/ai-sources${qs(params)}`,\n );\n}\n\n/**\n * AI-crawler / bot ingestion views.\n *\n * Dispatches to one of three sub-endpoints via `kind`:\n * - `overview` — total hits + per-vendor breakdown + top-crawled pages.\n * - `timeseries` — stacked-per-vendor hit counts bucketed over time.\n * - `recent` — last N raw crawler hit rows.\n *\n * Covers all bot traffic (AI assistants, search-engine crawlers, and a\n * generic \"Other\" bucket), not just AI crawlers.\n *\n * @example\n * const overview = await admin.analytics.crawlers({ kind: 'overview', topPagesLimit: 10 });\n */\nexport function crawlers(ctx: AdminContext, params: CrawlersParams) {\n const { kind, ...rest } = params;\n return call<AnalyticsCrawlersResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/insights/crawlers/${seg(kind)}${qs(rest)}`,\n );\n}\n","/**\n * App-events observability operations.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. The live tail is CLI-only (src/cliStream.ts) — the\n * import layer stays non-streaming by design.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport type {\n EventsChannelsListResult,\n EventsPublishResult,\n} from '../types/events.js';\n\nexport interface EventsScopeParams {\n /**\n * Environment scope to inspect: `live` (the default for reads),\n * `preview:<releaseId>`, or `dev:<sessionId>` — publishes and subscriptions\n * never cross scopes, so a dev session's events are visible only under its\n * `dev:` scope. A publish without one goes to the caller's own dev session.\n */\n scope?: string;\n}\n\nexport interface EventsPublishParams extends EventsScopeParams {\n /** Exact channel name(s) — no wildcards anywhere in app events. */\n channels: string | string[];\n /** The payload subscribers receive (≤256k serialized characters). */\n data: unknown;\n}\n\n/**\n * Channels with a publish or a subscription in the last 24h, with live\n * subscriber counts — recency-sorted, capped at 200.\n *\n * The debugging read: a channel with subscribers but no publishes (or the\n * reverse) usually means the frontend and backend spell the channel\n * differently.\n *\n * @example\n * const { channels } = await admin.events.channelsList();\n * const mismatch = channels.filter((c) => c.subscribers > 0 && !c.lastPublishAt);\n */\nexport function channelsList(\n ctx: AdminContext,\n params: EventsScopeParams = {},\n) {\n return call<EventsChannelsListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/events/channels${qs(params)}`,\n );\n}\n\n/**\n * Publish a test event, exactly as the app's own `events.publish` would —\n * same validation, same delivery, same metering. Lets a frontend subscriber\n * be verified before the backend trigger exists.\n *\n * Without `scope` it goes to the caller's own dev session, the preview they\n * are building in; `scope: 'live'` reaches real users. The result's `scope`\n * says where it went. `delivered` counts live subscriber connections per\n * published channel; `0` is normal (nobody listening), never an error.\n *\n * @throws AdminApiError `invalid_channels` / `payload_too_large` (400), and\n * `no_dev_session` (400) with no `scope` when the caller has no dev session.\n * @example\n * const { delivered } = await admin.events.publish({\n * channels: 'jobs:usr_123',\n * data: { type: 'ping' },\n * });\n */\nexport function publish(ctx: AdminContext, params: EventsPublishParams) {\n return call<EventsPublishResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/events/publish`,\n { channels: params.channels, data: params.data, scope: params.scope },\n );\n}\n","/**\n * Crash (frontend-error) operations.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/crashes.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n CrashesGetResult,\n CrashesListResult,\n CrashesOccurrencesResult,\n CrashesStatsResult,\n} from '../types/crashes.js';\n\nexport interface CrashesListParams {\n /** Filter to a specific release id. */\n releaseId?: string;\n /** Sort order: `'recent'` (default) or `'frequent'`. */\n sort?: string;\n /** Maximum crash groups to return (default 50). */\n limit?: number;\n /** Window start as an ISO 8601 date string. Defaults to 7 days ago. */\n start?: string;\n /** Window end as an ISO 8601 date string. Defaults to now. */\n end?: string;\n}\n\nexport interface CrashesOccurrencesParams {\n /** Filter to a specific release id. */\n releaseId?: string;\n /** Pagination cursor from a prior response's `nextCursor`. */\n cursor?: string;\n /** Maximum events to return (default 50). */\n limit?: number;\n /** Window start as an ISO 8601 date string. */\n start?: string;\n /** Window end as an ISO 8601 date string. */\n end?: string;\n}\n\nexport interface CrashesStatsParams {\n /** Filter to a specific release id. */\n releaseId?: string;\n /** Window start as an ISO 8601 date string. */\n start?: string;\n /** Window end as an ISO 8601 date string. */\n end?: string;\n /** Number of time buckets to return (default 24). */\n buckets?: number;\n}\n\n/**\n * Crash groups (one row per fingerprint) with occurrence counts and affected users.\n *\n * Groups are Sentry-style fingerprints. Each row carries an `exampleEventId`\n * — pass it to `crashes.get()` for a quick drill-in without iterating\n * occurrences. Time window defaults to the last 7 days when `start`/`end`\n * are omitted.\n *\n * @example\n * const { errors } = await admin.crashes.list({ sort: 'frequent', limit: 10 });\n */\nexport function list(ctx: AdminContext, params: CrashesListParams = {}) {\n return call<CrashesListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/frontend-errors${qs(params)}`,\n );\n}\n\n/**\n * Individual crash events for one fingerprint, cursor-paginated.\n *\n * Pass `nextCursor` from a prior response as `cursor` to fetch the next page.\n *\n * @param fingerprint The fingerprint string from a `list` row.\n * @example\n * const { errors, nextCursor } = await admin.crashes.occurrences('abc123fingerprint', { limit: 25 });\n */\nexport function occurrences(\n ctx: AdminContext,\n fingerprint: string,\n params: CrashesOccurrencesParams = {},\n) {\n return call<CrashesOccurrencesResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/frontend-errors/${seg(fingerprint)}/events${qs(params)}`,\n );\n}\n\n/**\n * Full crash event detail — stack trace, source location, breadcrumbs, and browser context.\n *\n * @param eventId The event id (e.g. `exampleEventId` from a `list` row, or\n * any id from an `occurrences` response).\n * @throws AdminApiError `not_found` (404) — the event id does not exist or\n * belongs to a different app.\n * @example\n * const event = await admin.crashes.get('evt_xyz789');\n */\nexport function get(ctx: AdminContext, eventId: string) {\n return call<CrashesGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/frontend-errors/events/${seg(eventId)}`,\n );\n}\n\n/**\n * Bucketed time series of total crash occurrence volume for the app.\n *\n * Returns per-bucket counts and overall totals for the window. When\n * `start`/`end` are omitted the server applies its own default window.\n *\n * @example\n * const { buckets, totals } = await admin.crashes.stats({ buckets: 24 });\n */\nexport function stats(ctx: AdminContext, params: CrashesStatsParams = {}) {\n return call<CrashesStatsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/frontend-errors/metrics/summary${qs(params)}`,\n );\n}\n","/**\n * Cron (scheduled job) operations.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/cron.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type { CronOverviewResult, CronRunResult } from '../types/cron.js';\n\nexport interface CronListParams {\n /** Recent runs to include per job (default 15, clamped 1–120). */\n runs?: number;\n}\n\n/**\n * Every scheduled job with its status and recent runs.\n *\n * Job status is `active | paused | blocked` (`statusReason` says why); a run's\n * id doubles as its request-log id, so a failing job's story continues with\n * `requests.get(runId)`.\n *\n * @example\n * const { jobs } = await admin.cron.list({ runs: 50 });\n * const blocked = jobs.filter((j) => j.status === 'blocked');\n */\nexport function list(ctx: AdminContext, params: CronListParams = {}) {\n return call<CronOverviewResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/cron/overview${qs(params)}`,\n );\n}\n\n/**\n * Trigger a job now (does not affect its schedule).\n *\n * Returns 202 immediately — the run continues in the background; check the\n * outcome via `requests.get(requestId)`.\n *\n * @param route The job's method id, as shown by `list`.\n * @throws AdminApiError `cron_job_not_found` (404) — the route isn't a\n * scheduled method; `run_already_triggered` (429) — a manual run is in\n * flight, or within the 30s debounce; `creator_unavailable` (400) — the\n * creator account is gone.\n * @example\n * const { requestId } = await admin.cron.run('dailyDigest');\n */\nexport function run(ctx: AdminContext, route: string) {\n return call<CronRunResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/cron/${seg(route)}/run`,\n );\n}\n","/**\n * Database sync operations: lift dev→live and live→dev.\n *\n * Ops are pure: (ctx, params) → typed result. No printing, no process coupling.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call } from '../http.js';\nimport type {\n DataLiftFromDevResult,\n DataLiftFromLiveResult,\n} from '../types/data.js';\n\nexport interface LiftFromDevParams {\n /**\n * Which of YOUR dev sessions to lift from, by dev release id. An app has a dev session per\n * workspace (one per person's box, one per person's CLI), and a lift only ever touches the\n * caller's own: without this it takes your newest, and a colleague's id is refused\n * (`not_your_dev_session`). Name it when you have more than one open. The ids are on the\n * dashboard's `devSessions`.\n */\n releaseId?: string;\n}\n\n/**\n * Destructively copy every dev-release database over the live-release databases.\n *\n * Whole-DB overwrite by name match, including auth tables — wipes whatever\n * live had, including signed-up users. Intended for first-publish / pre-launch\n * data sync only; do not run on a production app with real users. Writes an\n * audit row tagged `lift-dev-to-live`. The CLI skin requires the literal appId\n * AND `--confirm` as a double-gate; the op always sends `{ confirm: true }`.\n *\n * @throws AdminApiError `no_dev_session` (404) — no dev release exists (start a dev session first);\n * `no_live_release` (404) — app has never been published (publish first, then lift);\n * `not_your_dev_session` (403) — `releaseId` names someone else's dev session.\n * @example\n * const result = await admin.data.liftFromDev();\n * console.log(`Lifted ${result.databasesAffected.length} databases to live`);\n * // With more than one of your dev sessions open, name the one you mean:\n * await admin.data.liftFromDev({ releaseId: '8f2c1e04-...' });\n */\nexport function liftFromDev(ctx: AdminContext, params: LiftFromDevParams = {}) {\n return call<DataLiftFromDevResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/manage/lift-dev-to-live`,\n {\n confirm: true,\n ...(params.releaseId ? { releaseId: params.releaseId } : {}),\n },\n );\n}\n\nexport interface LiftFromLiveParams {\n /**\n * Empty dev databases in place — clears all rows, keeps schema and IDs,\n * no data read from live. Defaults to false (full copy from live).\n */\n truncate?: boolean;\n /**\n * Which of your dev sessions to overwrite, by dev release id; your newest when absent. See\n * `LiftFromDevParams.releaseId`.\n */\n releaseId?: string;\n}\n\n/**\n * Destructively replace dev-release databases with the live-release databases,\n * or truncate dev databases without reading from live.\n *\n * Only dev is overwritten — live/prod data is never touched. Useful for\n * reproducing a prod bug against real data or re-syncing a stale sandbox.\n * With `truncate: true` it instead empties the dev databases (keeps schema\n * and IDs, no data read from live). Writes an audit row tagged\n * `lift-live-to-dev`.\n *\n * @throws AdminApiError `no_dev_session` (404) — no dev release exists (start a dev session first);\n * `no_live_release` (404) — no live release (copy mode only; not thrown when `truncate` is true);\n * `not_your_dev_session` (403) — `releaseId` names someone else's dev session.\n * @example\n * // Pull live data into dev for debugging:\n * await admin.data.liftFromLive();\n * // Or just empty dev without pulling from live:\n * await admin.data.liftFromLive({ truncate: true });\n */\nexport function liftFromLive(\n ctx: AdminContext,\n params: LiftFromLiveParams = {},\n) {\n return call<DataLiftFromLiveResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/manage/lift-live-to-dev`,\n {\n confirm: true,\n ...(params.truncate ? { mode: 'truncate' } : {}),\n ...(params.releaseId ? { releaseId: params.releaseId } : {}),\n },\n );\n}\n","/**\n * Data-sources operations: document ingestion, corpus search, pipeline\n * configuration, and version management.\n *\n * Ops are pure (ctx, params) → typed result; no printing, no process coupling.\n * The CLI skin in commands/dataSources.ts owns everything flag-shaped (path\n * resolution, parseKeyValuePairs, configFromFlags, out/progress calls,\n * process.exit for wait-path exit codes).\n */\n\nimport { createHash } from 'node:crypto';\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport { renderProgress } from '../output.js';\nimport { elapsedSeconds, pollUntil, timedOut } from '../poll.js';\nimport { uploadDirect } from '../upload.js';\nimport type {\n DataSourcesBuildProgress,\n DataSourcesConfigResult,\n DataSourcesConfigUpdateResult,\n DataSourcesCreateResult,\n DataSourcesDeleteResult,\n DataSourcesDocument,\n DataSourcesDocumentConfirmResult,\n DataSourcesDocumentDeleteManyResult,\n DataSourcesDocumentDeleteResult,\n DataSourcesDocumentSelector,\n DataSourcesDocumentsResult,\n DataSourcesDocumentStatus,\n DataSourcesDropResult,\n DataSourcesIngestUpdate,\n DataSourcesListEntry,\n DataSourcesListResult,\n DataSourcesMoveResult,\n DataSourcesPromoteResult,\n DataSourcesRetrievalUpdate,\n DataSourcesRevectorizeResult,\n DataSourcesSearchResult,\n DataSourcesCountResult,\n DataSourcesDictionaryPushResult,\n DataSourcesDictionaryStatus,\n DataSourcesLinkResult,\n DataSourcesEntitiesResult,\n DataSourcesPassagesResult,\n DataSourcesUploadTokenResult,\n} from '../types/dataSources.js';\nimport type { DataSourceJob } from '../types/dataSourceJobs.js';\n\n/** @internal Consumed by the CLI skin; waitForIngest documents the default. */\nexport const DEFAULT_WAIT_TIMEOUT_MS = 15 * 60 * 1000;\nconst POLL_MS = 3000;\n\nfunction base(appId: string): string {\n return `/_internal/v2/apps/${appId}/datasources`;\n}\n\n/**\n * The per-document summary projection used by waitForIngest, status, and the\n * revectorize watch loop in the skin. Exported so the skin can reuse it for\n * the revectorize path without re-implementing it.\n * @internal Presentation helper for the CLI skin, not client surface.\n */\nexport const summarize = (d: DataSourcesDocumentStatus) => ({\n id: d.id,\n filename: d.filename,\n status: d.status,\n chunks: d.chunkCount,\n pages: d.pageCount,\n ...(d.errorMessage ? { error: d.errorMessage } : {}),\n});\n\n// ─── addDocument ─────────────────────────────────────────────────────────────\n\nexport interface AddDocumentParams {\n /** Data source slug. Created on first use. */\n slug: string;\n /** Original filename — used as the key and for MIME-type inference. */\n filename: string;\n /** File bytes to upload. */\n content: Buffer;\n /**\n * Scalar tags filterable at search time (≤ 16 keys,\n * `string | number | boolean` values).\n */\n metadata?: Record<string, string | number | boolean>;\n /**\n * What the document is about, as the app's own ids (≤ 256, printable ASCII,\n * no whitespace or commas). Every passage carries them; `[]` clears them.\n */\n entities?: string[];\n /**\n * The budget in dollars of the job that takes the rest of a file mapping\n * to more than a thousand documents (`AddDocumentResult.job`).\n */\n budgetDollars?: number;\n /**\n * Receives the exact progress strings the CLI prints today:\n * - `${filename}: unchanged, skipped`\n * - `${filename}: uploading N MB…`\n */\n onProgress?: (message: string) => void;\n}\n\nexport interface AddDocumentResult {\n filename: string;\n skipped: boolean;\n queued?: boolean;\n /**\n * The document, or the first of them on a mapped source. Null only when the\n * source's mapper answered `deletes` for the file.\n */\n document: DataSourcesDocument | null;\n /**\n * Every document the file became — one on an unmapped source — or the\n * first thousand of a file that maps to more.\n */\n documents: DataSourcesDocument[];\n /** How many documents the file maps to in all. */\n documentCount: number;\n /** How the source took the file; absent when it was already current. */\n outcome?: 'unmapped' | 'documents' | 'passthrough' | 'deletes';\n /** Documents the mapper produced that failed validation and were not registered. */\n invalid?: {\n count: number;\n examples: { document: number; reason: string }[];\n } | null;\n /**\n * The job registering and building the rest of a file that maps to more\n * than a thousand documents; it plans and starts on its own.\n */\n job?: DataSourceJob | null;\n}\n\n/**\n * Add one document to a data source.\n *\n * Three-step flow: hash → token → (skip-if-current) → upload → confirm.\n * Re-adding an unchanged file short-circuits at the token step and moves no\n * bytes. Re-adding with different `metadata` updates the tags in-place, also\n * without a re-upload. The data source is created on first use.\n *\n * @throws AdminApiError `invalid_content_hash` (400) — malformed hash\n * (internal; `addDocument` computes this from `content`).\n * @example\n * const result = await admin.dataSources.addDocument({\n * slug: 'policies',\n * filename: 'contract.pdf',\n * content: pdfBuffer,\n * metadata: { department: 'legal', year: 2026 },\n * });\n */\nexport async function addDocument(\n ctx: AdminContext,\n params: AddDocumentParams,\n): Promise<AddDocumentResult> {\n const { slug, filename, content, metadata, entities, onProgress } = params;\n const { budgetDollars } = params;\n const contentHash = createHash('sha256').update(content).digest('hex');\n\n const token = await call<DataSourcesUploadTokenResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/upload-token`,\n {\n slug,\n filename,\n contentHash,\n ...(metadata ? { metadata } : {}),\n ...(entities ? { entities } : {}),\n },\n );\n\n if (token.alreadyCurrent) {\n onProgress?.(`${filename}: unchanged, skipped`);\n const documents = token.documents ?? [token.document];\n return {\n filename,\n skipped: true,\n document: token.document,\n documents,\n documentCount: token.documentCount ?? documents.length,\n };\n }\n\n onProgress?.(\n `${filename}: uploading ${(content.length / 1024 / 1024).toFixed(1)}MB…`,\n );\n await uploadDirect(token.upload, content, filename);\n\n const confirmed = await call<DataSourcesDocumentConfirmResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/documents`,\n {\n slug,\n filename,\n contentHash,\n contentType: token.contentType,\n size: content.length,\n ...(metadata ? { metadata } : {}),\n ...(entities ? { entities } : {}),\n ...(budgetDollars !== undefined ? { budgetDollars } : {}),\n },\n );\n\n const documents =\n confirmed.documents ?? (confirmed.document ? [confirmed.document] : []);\n return {\n filename,\n skipped: false,\n queued: confirmed.queued,\n document: confirmed.document,\n documents,\n documentCount: confirmed.documentCount ?? documents.length,\n outcome: confirmed.outcome,\n invalid: confirmed.invalid ?? null,\n job: confirmed.job ?? null,\n };\n}\n\n// ─── waitForIngest ────────────────────────────────────────────────────────────\n\nexport interface WaitForIngestParams {\n slug: string;\n documentIds: string[];\n /** How long without movement before giving up. Defaults to DEFAULT_WAIT_TIMEOUT_MS (15 min). */\n timeoutMs?: number;\n /**\n * Receives the exact progress strings the CLI prints today:\n * `ingesting… X/Y done (Ns)`\n */\n onProgress?: (message: string) => void;\n}\n\nexport type SummarizedDocument = ReturnType<typeof summarize>;\n\nexport interface WaitForIngestResult {\n status: 'up-to-date' | 'done' | 'error' | 'timeout';\n documents: SummarizedDocument[];\n /** Present only on status === 'timeout'. */\n error?: string;\n}\n\n/**\n * Poll until every queued document reaches a terminal state.\n *\n * Terminal states: `done` (all succeeded), `error` (at least one failed),\n * `timeout` (still processing after `timeoutMs`, default 15 minutes). Polls\n * every 3 seconds. Returns a typed result so the caller can branch on\n * `status` without parsing strings.\n *\n * The `dataSource: slug` envelope and exit-code handling stay in the CLI skin\n * so the printed JSON is byte-identical to the pre-refactor CLI.\n *\n * @example\n * const result = await admin.dataSources.waitForIngest({\n * slug: 'policies',\n * documentIds: [doc.id],\n * onProgress: console.error,\n * });\n * if (result.status === 'error') { ... }\n */\nexport async function waitForIngest(\n ctx: AdminContext,\n params: WaitForIngestParams,\n): Promise<WaitForIngestResult> {\n const { slug, documentIds, onProgress } = params;\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n\n if (documentIds.length === 0) {\n return { status: 'up-to-date', documents: [] };\n }\n\n const wanted = new Set(documentIds);\n const pendingOf = (docs: DataSourcesDocumentStatus[]) =>\n docs.filter((d) => d.status === 'processing');\n\n const outcome = await pollUntil(\n async () => {\n // Only the documents being waited on: the source may hold millions.\n const docs = await allDocuments(ctx, { slug, ids: documentIds });\n return (docs ?? []).filter((d) => wanted.has(d.id));\n },\n (tracked) => pendingOf(tracked).length === 0,\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (tracked, start) =>\n `ingesting… ${tracked.length - pendingOf(tracked).length}/${tracked.length} done (${elapsedSeconds(start)}s)`,\n progressKey: (tracked) => pendingOf(tracked).length,\n onProgress,\n },\n );\n const tracked = outcome.value;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n documents: tracked.map(summarize),\n error: timedOut(\n timeoutMs,\n `with ${pendingOf(tracked).length} document(s) still processing`,\n ),\n };\n }\n return {\n status: tracked.some((d) => d.status === 'error') ? 'error' : 'done',\n documents: tracked.map(summarize),\n };\n}\n\n// ─── waitForCandidate ─────────────────────────────────────────────────────────\n\nexport interface WaitForCandidateParams {\n slug: string;\n /** How long without movement before giving up. Defaults to DEFAULT_WAIT_TIMEOUT_MS (15 min). */\n timeoutMs?: number;\n /** Receives `rebuilding… X/Y done (Ns)`. */\n onProgress?: (message: string) => void;\n}\n\nexport interface WaitForCandidateResult {\n status: 'ready' | 'error' | 'timeout';\n /** The candidate's build counts when the wait ended; null when it had no candidate. */\n counts: DataSourcesBuildProgress | null;\n /** The failed documents, first page, when any failed. */\n documents: SummarizedDocument[];\n /** Present only on status === 'timeout'. */\n error?: string;\n}\n\n/** Failed documents fetched for a status or a candidate wait. */\nexport const FAILURES_PAGE = 50;\n\n/**\n * Poll a candidate version (`revectorize`) until every document has built.\n * Reads the candidate's counts from the source list — one row, whatever the\n * corpus holds — and fetches the failures only at the end. `error` means at\n * least one failed; `promote` with `force` accepts that.\n */\nexport async function waitForCandidate(\n ctx: AdminContext,\n params: WaitForCandidateParams,\n): Promise<WaitForCandidateResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n\n const outcome = await pollUntil(\n async () => {\n const { dataSources } = await list(ctx);\n const source = dataSources.find((s) => s.slug === params.slug);\n if (!source) {\n throw new Error(`Data source \"${params.slug}\" not found.`);\n }\n return source.candidate?.progress ?? null;\n },\n (progress) => progress === null || progress.processing === 0,\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (progress, start) =>\n progress\n ? `rebuilding… ${progress.done}/${progress.total} done (${elapsedSeconds(start)}s)`\n : `rebuilding… (${elapsedSeconds(start)}s)`,\n progressKey: (progress) => progress?.processing ?? null,\n onProgress: params.onProgress,\n },\n );\n const counts = outcome.value;\n const failed =\n counts && counts.error > 0\n ? (\n await documents(ctx, {\n slug: params.slug,\n candidate: true,\n status: 'error',\n limit: FAILURES_PAGE,\n })\n ).documents.map(summarize)\n : [];\n if (!outcome.settled) {\n return {\n status: 'timeout',\n counts,\n documents: failed,\n error: timedOut(\n timeoutMs,\n `with ${counts?.processing ?? 0} document(s) still building`,\n ),\n };\n }\n return {\n status: counts && counts.error > 0 ? 'error' : 'ready',\n counts,\n documents: failed,\n };\n}\n\n// ─── documents ───────────────────────────────────────────────────────────────\n\nexport interface DocumentsParams {\n /** Data source slug. */\n slug: string;\n /** true → watch a candidate pipeline (revectorize in progress). */\n candidate?: boolean;\n /** Only these documents (at most DOCUMENTS_IDS_MAX per request). */\n ids?: string[];\n /** Page size, 1..1000 (server default 500). */\n limit?: number;\n /** `nextCursor` from the previous page. */\n cursor?: string;\n /** By the time the document was added; oldest first unless said otherwise. */\n order?: 'oldest' | 'newest';\n /** The failed builds only, newest failure first. */\n status?: 'error';\n /** Filenames starting with this. */\n filename?: string;\n}\n\n/** The server's cap on `ids` per request; `allDocuments` chunks to it. */\nexport const DOCUMENTS_IDS_MAX = 200;\n\n/**\n * Fetch one page of per-document ingest state for one pipeline, oldest first\n * unless `order` says otherwise; `status: 'error'` narrows to the failures and\n * `filename` to a name prefix.\n *\n * Returns an empty document list when the data source does not exist yet.\n * Pass `candidate: true` to watch a revectorization in progress. Follow\n * `nextCursor` for the next page, or use `allDocuments` to walk them all.\n *\n * @example\n * const { documents, nextCursor } = await admin.dataSources.documents({ slug: 'policies' });\n * const failed = await admin.dataSources.documents({ slug: 'policies', status: 'error' });\n */\nexport function documents(ctx: AdminContext, params: DocumentsParams) {\n return call<DataSourcesDocumentsResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/documents${qs({\n slug: params.slug,\n candidate: params.candidate || undefined,\n ids: params.ids?.length ? params.ids.join(',') : undefined,\n limit: params.limit,\n cursor: params.cursor,\n order: params.order,\n status: params.status,\n filename: params.filename,\n })}`,\n );\n}\n\n/**\n * Every document (or every one of `ids`), following pages to the end.\n *\n * With `ids`, requests are chunked to the server's per-request cap, so a wait\n * over hundreds of just-added files stays a handful of small calls rather than\n * a walk of the whole source.\n *\n * @example\n * const docs = await admin.dataSources.allDocuments({ slug: 'policies' });\n */\nexport async function allDocuments(\n ctx: AdminContext,\n params: Omit<DocumentsParams, 'cursor' | 'limit'>,\n): Promise<DataSourcesDocumentStatus[]> {\n const groups: Array<string[] | undefined> = params.ids\n ? Array.from(\n { length: Math.ceil(params.ids.length / DOCUMENTS_IDS_MAX) },\n (_, i) =>\n params.ids!.slice(i * DOCUMENTS_IDS_MAX, (i + 1) * DOCUMENTS_IDS_MAX),\n )\n : [undefined];\n const out: DataSourcesDocumentStatus[] = [];\n for (const ids of groups) {\n let cursor: string | undefined;\n do {\n const page = await documents(ctx, {\n slug: params.slug,\n candidate: params.candidate,\n ids,\n limit: 1000,\n cursor,\n order: params.order,\n status: params.status,\n filename: params.filename,\n });\n out.push(...(page.documents ?? []));\n cursor = page.nextCursor ?? undefined;\n } while (cursor);\n }\n return out;\n}\n\n// ─── list ─────────────────────────────────────────────────────────────────────\n\n/**\n * List all data sources with document counts, build progress, and active\n * version metadata.\n *\n * @example\n * const { dataSources } = await admin.dataSources.list();\n */\nexport function list(ctx: AdminContext) {\n return call<DataSourcesListResult>(ctx, 'GET', base(ctx.appId));\n}\n\n// ─── search ──────────────────────────────────────────────────────────────────\n\nexport interface SearchParams {\n /** Data source slug. */\n slug: string;\n /** Natural-language or keyword query. */\n query: string;\n /** Results to return (default 5, max 50). */\n topK?: number;\n /** 'hybrid' (default) | 'semantic' | 'lexical'. */\n mode?: string;\n /** Metadata equality filter or the full filter grammar as a plain object. */\n filter?: Record<string, unknown>;\n /** Cap hits per document; backfills from others. */\n maxPerDocument?: number;\n /** Return query-term offsets per hit. */\n highlight?: boolean;\n /** Search the candidate version instead of the live one. */\n candidate?: boolean;\n /** Assembled from triState(a, 'rerank'/'hybrid') in the skin. */\n retrieval?: Record<string, boolean>;\n}\n\n/**\n * Query a data source and return ranked passages with citations.\n *\n * `mode` in the response reports what actually ran (e.g. `reranked: false`\n * after an adaptive skip) rather than what was requested, so measurements\n * attribute numbers to the right path. Pass `candidate: true` to evaluate a\n * candidate pipeline before promoting it.\n *\n * @throws AdminApiError `no_candidate_pipeline` (404) — `candidate: true` but\n * no revectorization is in flight; `invalid_query` (400); `invalid_mode`\n * (400).\n * @example\n * const { results } = await admin.dataSources.search({\n * slug: 'policies',\n * query: 'what are the payment terms?',\n * });\n */\nexport function search(ctx: AdminContext, params: SearchParams) {\n const {\n slug,\n query,\n topK,\n mode,\n filter,\n maxPerDocument,\n highlight,\n candidate,\n retrieval,\n } = params;\n return call<DataSourcesSearchResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/search`,\n {\n slug,\n query,\n ...(topK ? { topK } : {}),\n ...(mode ? { mode } : {}),\n ...(filter ? { filter } : {}),\n ...(maxPerDocument !== undefined ? { maxPerDocument } : {}),\n ...(highlight ? { highlight: true } : {}),\n ...(candidate ? { candidate: true } : {}),\n ...(retrieval && Object.keys(retrieval).length ? { retrieval } : {}),\n },\n );\n}\n\nexport interface CountParams {\n /** Data source slug. */\n slug: string;\n /** Same grammar as search's filter; absent counts the whole corpus. */\n filter?: Record<string, unknown>;\n /** Count the candidate version instead of the live one. */\n candidate?: boolean;\n}\n\n/**\n * How many chunks match a filter — exact, over the whole corpus.\n *\n * `count({ slug, filter: { contains: query } })` is how many passages contain\n * all the query's words: the honest figure to show beside a search's hits.\n * Not a relevance count (none exists) and not the set `search` returns.\n *\n * @throws AdminApiError `invalid_filter` (400); `no_candidate_pipeline` (404)\n * with `candidate: true` and no revectorization in flight; `index_warming` /\n * `index_building` (503) while the corpus is loading or building.\n * @example\n * const { chunks } = await admin.dataSources.count({ slug: 'policies', filter: { contains: 'notice period' } });\n */\nexport function count(ctx: AdminContext, params: CountParams) {\n const { slug, filter, candidate } = params;\n return call<DataSourcesCountResult>(ctx, 'POST', `${base(ctx.appId)}/count`, {\n slug,\n ...(filter ? { filter } : {}),\n ...(candidate ? { candidate: true } : {}),\n });\n}\n\nexport interface EntitiesParams {\n /** Data source slug. */\n slug: string;\n /** Same grammar as search's filter; absent covers the whole corpus. */\n filter?: Record<string, unknown>;\n /** Entities to return, most first (default 20, at most 1,000). */\n limit?: number;\n /** Read the candidate version instead of the live one. */\n candidate?: boolean;\n}\n\n/**\n * Which entities the passages matching a filter are about, most first.\n *\n * Filtered on one entity, it answers what appears beside it: a co-mention\n * graph. `chunks` counts passages carrying each id, not documents, and is\n * approximate.\n *\n * @throws AdminApiError `invalid_filter` (400); `no_candidate_pipeline` (404)\n * with `candidate: true` and no revectorization in flight; `index_warming` /\n * `index_building` (503) while the corpus is loading or building.\n * @example\n * const { entities } = await admin.dataSources.entities({ slug: 'manuals', filter: { entities: ['P-101A'] } });\n */\nexport function entities(ctx: AdminContext, params: EntitiesParams) {\n const { slug, filter, limit, candidate } = params;\n return call<DataSourcesEntitiesResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/entities`,\n {\n slug,\n ...(filter ? { filter } : {}),\n ...(limit !== undefined ? { limit } : {}),\n ...(candidate ? { candidate: true } : {}),\n },\n );\n}\n\nexport interface PassagesParams {\n /** Data source slug. */\n slug: string;\n /** Same grammar as search's filter; absent lists the whole corpus. */\n filter?: Record<string, unknown>;\n /** The previous page's `nextCursor`. */\n cursor?: string;\n /** Passages per page (default 50, at most 200). */\n limit?: number;\n /** Read the candidate version instead of the live one. */\n candidate?: boolean;\n}\n\n/**\n * One page of every passage matching a filter, unranked: all the pages that\n * mention an entity, rather than search's best few. Passages come document by\n * document, each document's in order.\n *\n * @throws AdminApiError `invalid_filter` (400); `invalid_cursor` (400);\n * `no_candidate_pipeline` (404); `index_warming` / `index_building` (503).\n * @example\n * const { passages, nextCursor } = await admin.dataSources.passages({ slug: 'manuals', filter: { entities: ['P-1004A'] } });\n */\nexport function passages(ctx: AdminContext, params: PassagesParams) {\n const { slug, filter, cursor, limit, candidate } = params;\n return call<DataSourcesPassagesResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/passages`,\n {\n slug,\n ...(filter ? { filter } : {}),\n ...(cursor ? { cursor } : {}),\n ...(limit !== undefined ? { limit } : {}),\n ...(candidate ? { candidate: true } : {}),\n },\n );\n}\n\n// ─── config ───────────────────────────────────────────────────────────────────\n\n/**\n * Read the full pipeline configuration for one data source.\n *\n * Returns `ingest` (pinned — requires a revectorize to change) and\n * `retrieval` (live — takes effect on the next query, no rebuild needed).\n *\n * @throws AdminApiError `data_source_not_found` (404).\n * @example\n * const { ingest, retrieval } = await admin.dataSources.configGet('policies');\n */\nexport function configGet(ctx: AdminContext, slug: string) {\n return call<DataSourcesConfigResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/config?slug=${encodeURIComponent(slug)}`,\n );\n}\n\nexport interface ConfigSetParams {\n /** Data source slug. */\n slug: string;\n /**\n * Ingest settings (pinned). Changes are rejected on a populated source —\n * use `revectorize` instead to rebuild alongside the live one.\n */\n ingest?: DataSourcesIngestUpdate;\n /**\n * Retrieval settings (live). Take effect on the next query; no rebuild\n * required.\n */\n retrieval?: DataSourcesRetrievalUpdate;\n /**\n * Where the corpus lives: a dedicated resource (see `admin.infra`) or the\n * shared pool. An empty source moves on the spot; a populated one starts a\n * background move (see `move`) and the response carries its `migration`.\n */\n placement?: { resourceId: string } | 'shared';\n}\n\n/**\n * Update pipeline configuration.\n *\n * `retrieval` changes take effect on the next query at no cost. `ingest`\n * changes are rejected once the source has documents — use `revectorize`\n * instead, which builds a new version alongside the live one so search never\n * degrades.\n *\n * @throws AdminApiError `data_source_not_found` (404),\n * `data_source_migrating` (422) while a move is in flight.\n * @example\n * await admin.dataSources.configSet({\n * slug: 'policies',\n * retrieval: { rerank: { enabled: true } },\n * });\n */\nexport function configSet(ctx: AdminContext, params: ConfigSetParams) {\n const { slug, ingest, retrieval, placement } = params;\n return call<DataSourcesConfigUpdateResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/config`,\n {\n slug,\n ...(ingest ? { ingest } : {}),\n ...(retrieval ? { retrieval } : {}),\n ...(placement !== undefined ? { placement } : {}),\n },\n );\n}\n\n// ─── create ──────────────────────────────────────────────────────────────────\n\nexport interface CreateParams {\n /** Data source slug: lowercase [a-z0-9_-], up to 64 characters. */\n slug: string;\n /** Display name. */\n name?: string;\n /** Pinned ingest settings for the new pipeline; platform defaults otherwise. */\n ingest?: DataSourcesIngestUpdate;\n /**\n * Where the corpus lives from the start: a dedicated resource (see\n * `admin.infra`) or the shared pool (the default).\n */\n placement?: { resourceId: string } | 'shared';\n}\n\n/**\n * Create an empty data source, optionally on dedicated capacity.\n *\n * The one-step way to start a corpus on a resource. `add` also creates a\n * source on first use, but on the shared pool. Calling this for a source that\n * already exists returns it; a placement given then follows `configSet`'s\n * rule — an empty source moves on the spot, a populated one starts a move.\n *\n * @throws AdminApiError `invalid_data_source` (400), `data_source_limit` (422),\n * `resource_not_found` (404), `resource_destroyed` (422),\n * `data_source_migrating` (422), `capacity_exceeded` (422).\n * @example\n * await admin.dataSources.create({ slug: 'archive', placement: { resourceId } });\n */\nexport function create(ctx: AdminContext, params: CreateParams) {\n const { slug, name, ingest, placement } = params;\n return call<DataSourcesCreateResult>(ctx, 'POST', base(ctx.appId), {\n slug,\n ...(name ? { name } : {}),\n ...(ingest ? { ingest } : {}),\n ...(placement !== undefined ? { placement } : {}),\n });\n}\n\n// ─── move ────────────────────────────────────────────────────────────────────\n\nexport interface MoveParams {\n /** Data source slug. */\n slug: string;\n /** A dedicated resource (see `admin.infra`) or the shared pool. */\n placement: { resourceId: string } | 'shared';\n /**\n * Start the copy over instead of resuming a move already under way to the\n * same target: fresh chains cut at the target's current count, progress so\n * far discarded (points already copied are written again, harmlessly).\n */\n restart?: boolean;\n /**\n * Parallel chains to copy with, instead of the target size's default (XL 32,\n * Large 16, Medium 8, Small 4; max 128). The platform runs four chains per\n * worker, so this is the worker count times four. Takes effect when the\n * copy's windows are cut: with a move already under way, pair it with\n * `restart`.\n */\n chains?: number;\n}\n\n/**\n * Halt a move under way. Its chains stop at their next checkpoint and the\n * record reads `error: \"Stopped by operator.\"`; a plain `move` to the same\n * target resumes from the chains' cursors.\n *\n * @throws AdminApiError `data_source_not_found` (404), `no_move_in_flight`\n * (422) when nothing is being moved.\n * @example\n * await admin.dataSources.stopMove({ slug: 'archive' });\n */\nexport function stopMove(ctx: AdminContext, params: { slug: string }) {\n return call<DataSourcesMoveResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/move/stop`,\n { slug: params.slug },\n );\n}\n\n/**\n * Move a data source between placements: shared → dedicated, dedicated →\n * shared, or one resource to another.\n *\n * A populated source is copied onto the target in the background from its\n * stored vectors — nothing is re-extracted or re-embedded — and flips when the\n * copy lands. Search keeps serving from the old placement meanwhile. Adding,\n * removing or reconfiguring documents is refused with `data_source_migrating`\n * until it finishes; `waitForMove` blocks on that. Moving to `'shared'` is how\n * a source leaves a resource that is about to be destroyed.\n *\n * @throws AdminApiError `data_source_not_found` (404), `same_placement` (400),\n * `data_source_busy` (422) while documents are still building or a\n * candidate version exists, `data_source_migrating` (422), `capacity_<phase>`\n * (422) when the target resource is not active, `capacity_exceeded` (422)\n * when the target is too small, `resource_not_found` (404).\n * @example\n * await admin.dataSources.move({ slug: 'archive', placement: { resourceId } });\n * const result = await admin.dataSources.waitForMove({ slug: 'archive' });\n */\nexport function move(ctx: AdminContext, params: MoveParams) {\n return call<DataSourcesMoveResult>(ctx, 'POST', `${base(ctx.appId)}/move`, {\n slug: params.slug,\n placement: params.placement,\n ...(params.restart ? { restart: true } : {}),\n ...(params.chains !== undefined ? { chains: params.chains } : {}),\n });\n}\n\nexport interface WaitForMoveParams {\n slug: string;\n /** How long without movement before giving up. Defaults to DEFAULT_WAIT_TIMEOUT_MS (15 min). */\n timeoutMs?: number;\n /** Receives `copying… X/Y documents · N/min · about M min left (Ns)`. */\n onProgress?: (message: string) => void;\n}\n\nexport type WaitForMoveResult =\n | { status: 'done'; source: DataSourcesListEntry }\n | { status: 'failed'; source: DataSourcesListEntry; error: string }\n | { status: 'timeout'; source: DataSourcesListEntry; error: string };\n\n/**\n * Poll until a source's move has landed, failed, or the timeout elapses.\n *\n * Reads the source from `list` each poll; done when no move is in flight. A\n * failed move returns immediately with the platform's error.\n *\n * @throws AdminApiError `data_source_not_found` (404).\n */\nexport async function waitForMove(\n ctx: AdminContext,\n params: WaitForMoveParams,\n): Promise<WaitForMoveResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const outcome = await pollUntil(\n async () => {\n const { dataSources } = await list(ctx);\n const source = dataSources.find((s) => s.slug === params.slug);\n if (!source) {\n throw new Error(`Data source \"${params.slug}\" not found.`);\n }\n return source;\n },\n (source) => !source.migration || source.migration.error !== null,\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (source, start) =>\n renderProgress(source.migration!.progress, start),\n // A corpus of any size moves as long as it keeps moving; the timeout\n // bounds silence. The settle moves without copying — it builds the\n // target's full-text index and reports coverage — so its sample time\n // counts as movement too.\n progressKey: (source) =>\n source.migration\n ? `${source.migration.copied}|${source.migration.progress.updatedAt ?? ''}`\n : null,\n onProgress: params.onProgress,\n },\n );\n const source = outcome.value;\n const migration = source.migration;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n source,\n error: timedOut(\n timeoutMs,\n `with ${migration!.copied}/${migration!.total} documents copied`,\n ),\n };\n }\n if (migration?.error) {\n return { status: 'failed', source, error: migration.error };\n }\n return { status: 'done', source };\n}\n\n// ─── revectorize ──────────────────────────────────────────────────────────────\n\nexport interface RevectorizeParams {\n /** Data source slug. */\n slug: string;\n /** Ingest settings for the new version. Omit to adopt platform defaults. */\n ingest?: DataSourcesIngestUpdate;\n}\n\n/**\n * Start a new candidate pipeline alongside the live one.\n *\n * Builds a new version with the supplied settings, or platform defaults when\n * none are given (the upgrade path for a source pinned to an older chunker).\n * Search keeps serving the active version throughout. Reuses stored\n * extractions, so changing chunking never re-runs document extraction — only\n * re-chunking and re-embedding. Call `promote` to cut over.\n *\n * @throws AdminApiError `data_source_not_found` (404).\n * @example\n * const { candidateVersion } = await admin.dataSources.revectorize({\n * slug: 'policies',\n * ingest: { chunking: { maxChars: 900 } },\n * });\n */\nexport function revectorize(ctx: AdminContext, params: RevectorizeParams) {\n const { slug, ingest } = params;\n return call<DataSourcesRevectorizeResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/revectorize`,\n {\n slug,\n ...(ingest ? { ingest } : {}),\n },\n );\n}\n\n// ─── promote ──────────────────────────────────────────────────────────────────\n\nexport interface PromoteParams {\n /** Data source slug. */\n slug: string;\n /** Promote even if some candidate documents failed. */\n force?: boolean;\n}\n\n/**\n * Make the candidate pipeline version live.\n *\n * Atomically swaps the candidate for the active version and retires the old\n * one. Without `force`, promotion is blocked when any candidate document\n * failed. The retired version is kept; discard it with `drop` once rollback\n * is no longer wanted.\n *\n * @throws AdminApiError `data_source_not_found` (404).\n * @example\n * const { activeVersion } = await admin.dataSources.promote({ slug: 'policies' });\n */\nexport function promote(ctx: AdminContext, params: PromoteParams) {\n return call<DataSourcesPromoteResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/promote`,\n {\n slug: params.slug,\n ...(params.force ? { force: true } : {}),\n },\n );\n}\n\n// ─── drop ─────────────────────────────────────────────────────────────────────\n\nexport interface DropParams {\n /** Data source slug. */\n slug: string;\n /** Version number to drop. Omitted → the candidate is dropped. */\n version?: number;\n}\n\n/**\n * Discard a candidate or retired pipeline version.\n *\n * Never touches the active version. Omit `version` to drop the candidate;\n * pass a specific number to drop a retired version once rollback is no longer\n * wanted.\n *\n * @throws AdminApiError `data_source_not_found` (404); `pipeline_not_found`\n * (404) — no candidate exists, or the version number is unknown.\n * @example\n * await admin.dataSources.drop({ slug: 'policies' }); // drops the candidate\n */\nexport function drop(ctx: AdminContext, params: DropParams) {\n return call<DataSourcesDropResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/versions/drop`,\n {\n slug: params.slug,\n ...(params.version !== undefined ? { version: params.version } : {}),\n },\n );\n}\n\n// ─── rm (document delete) ─────────────────────────────────────────────────────\n\nexport interface RmParams {\n /** Data source slug. */\n slug: string;\n /** UUID of the document to remove. */\n documentId: string;\n}\n\n/**\n * Remove one document and its vectors from a data source.\n *\n * Deletes across every pipeline version, not just the active one — a document\n * deleted mid-migration is gone from the candidate too.\n *\n * @throws AdminApiError `data_source_not_found` (404); `document_not_found`\n * (404).\n * @example\n * await admin.dataSources.rm({ slug: 'policies', documentId });\n */\nexport function rm(ctx: AdminContext, params: RmParams) {\n return call<DataSourcesDocumentDeleteResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/documents/delete`,\n {\n slug: params.slug,\n documentId: params.documentId,\n },\n );\n}\n\n// ─── rmWhere (documents by filter) ───────────────────────────────────────────\n\nexport interface RmWhereParams {\n /** Data source slug. */\n slug: string;\n filter: DataSourcesDocumentSelector;\n}\n\n/**\n * Remove one page (up to 1,000) of the documents matching a selector, across\n * every pipeline version, and report how many still match. Loop while\n * `remaining > 0`; `rmWhereAll` does that.\n *\n * @throws AdminApiError `data_source_not_found` (404), `invalid_filter` (400),\n * `data_source_busy` (422) while a job is in flight, `data_source_migrating`\n * (422) during a move.\n * @example\n * await admin.dataSources.rmWhere({ slug: 'archive', filter: { metadata: { year: 2019 } } });\n */\nexport function rmWhere(ctx: AdminContext, params: RmWhereParams) {\n return call<DataSourcesDocumentDeleteManyResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/documents/delete-many`,\n { slug: params.slug, filter: params.filter },\n );\n}\n\n/** `rmWhere` until nothing matches. Reports each page through `onProgress`. */\nexport async function rmWhereAll(\n ctx: AdminContext,\n params: RmWhereParams & { onProgress?: (message: string) => void },\n): Promise<{ deleted: number }> {\n let deleted = 0;\n while (true) {\n const page = await rmWhere(ctx, params);\n deleted += page.deleted;\n if (page.remaining === 0 || page.deleted === 0) {\n return { deleted };\n }\n params.onProgress?.(\n `removed ${deleted.toLocaleString()} so far, ${page.remaining.toLocaleString()} remaining…`,\n );\n }\n}\n\n// ─── deleteSource ─────────────────────────────────────────────────────────────\n\n/**\n * Delete a whole data source — every version, every document, and every byte.\n *\n * Extraction caches survive (shared across sources by content hash), so\n * re-ingesting the same files into a new source costs no re-extraction.\n * Manage-plane only: running app code has no equivalent.\n *\n * @throws AdminApiError `data_source_not_found` (404).\n * @example\n * const { documents, versions } = await admin.dataSources.deleteSource('policies');\n */\nexport function deleteSource(ctx: AdminContext, slug: string) {\n return call<DataSourcesDeleteResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/delete`,\n { slug },\n );\n}\n\n/** One dictionary entry: the app's id for a thing and the names it goes by. */\nexport interface DictionaryEntryInput {\n id: string;\n names: string[];\n}\n\n/** Entries per page, and the bytes one page's JSON may run to. */\nconst DICTIONARY_PAGE_ENTRIES = 10_000;\nconst DICTIONARY_PAGE_BYTES = 4_000_000;\n\n/**\n * Push a source's dictionary, replacing the one it had: a stage, its pages\n * (each retried alone), and the commit. A new version re-tags the source's\n * passages in the background; an unchanged one commits nothing.\n *\n * @throws AdminApiError `invalid_dictionary` / `dictionary_name_too_short` (400)\n * on a page, naming the entry; `dictionary_too_large` (400) at the commit.\n * @example\n * await admin.dataSources.pushDictionary({ slug: 'manuals', entries: [{ id: 'P-101A', names: ['P-101A', 'Main Feed Pump'] }] });\n */\nexport async function pushDictionary(\n ctx: AdminContext,\n params: {\n slug: string;\n entries: DictionaryEntryInput[];\n linkerVersion?: number;\n onProgress?: (sent: number, total: number) => void;\n },\n): Promise<DataSourcesDictionaryPushResult> {\n const { slug, entries } = params;\n const stage = await call<{ stageId: string; pageMaxEntries: number }>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/dictionary/stage`,\n {\n slug,\n ...(params.linkerVersion !== undefined\n ? { linkerVersion: params.linkerVersion }\n : {}),\n },\n );\n const perPage = Math.min(\n DICTIONARY_PAGE_ENTRIES,\n stage.pageMaxEntries || DICTIONARY_PAGE_ENTRIES,\n );\n let pages = 0;\n let start = 0;\n while (start < entries.length) {\n let end = start;\n let bytes = 0;\n while (end < entries.length && end - start < perPage) {\n const size = JSON.stringify(entries[end]).length;\n if (end > start && bytes + size > DICTIONARY_PAGE_BYTES) {\n break;\n }\n bytes += size;\n end += 1;\n }\n await call(ctx, 'POST', `${base(ctx.appId)}/dictionary/page`, {\n slug,\n stageId: stage.stageId,\n page: pages,\n entries: entries.slice(start, end),\n });\n pages += 1;\n start = end;\n params.onProgress?.(start, entries.length);\n }\n return call<DataSourcesDictionaryPushResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/dictionary/commit`,\n { slug, stageId: stage.stageId, pages },\n );\n}\n\n/**\n * A source's current dictionary, and the relinks re-tagging its versions\n * while they run.\n *\n * @throws AdminApiError `data_source_not_found` (404).\n */\nexport function dictionary(ctx: AdminContext, params: { slug: string }) {\n return call<DataSourcesDictionaryStatus>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/dictionary`,\n { slug: params.slug },\n );\n}\n\n/**\n * What the source's current dictionary finds in a piece of text: each\n * mention, in order, with the ids it tags.\n *\n * @throws AdminApiError `data_source_not_found` (404).\n * @example\n * const { mentions } = await admin.dataSources.link({ slug: 'manuals', text: 'Replaced the seal on P101A.' });\n */\nexport function link(\n ctx: AdminContext,\n params: { slug: string; text: string },\n) {\n return call<DataSourcesLinkResult>(ctx, 'POST', `${base(ctx.appId)}/link`, {\n slug: params.slug,\n text: params.text,\n });\n}\n","/**\n * Do NOT unref() this timer, and do not \"dedupe\" it against the identically\n * named helper in DraftSnapshotManager, which does.\n *\n * Inside the CLI's polling loops (`releases wait`, `releases status --wait`,\n * `diagnostics get --wait`) this timer is often the only live handle, so an\n * unref'd version lets node exit mid-wait: the poll silently abandons and never\n * reports a result. Verified — the process exits 13 and the code after the\n * sleep never runs. The server can unref safely because its sockets keep the\n * loop alive; a short-lived CLI cannot.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","/**\n * The one polling loop under every `--wait`: read the thing, ask whether it\n * has settled, sleep, repeat, with a bounded grace for gateway errors and a\n * timeout. The waits differ only in what they read, what \"settled\" means and\n * how they describe progress; none of them owns a loop.\n */\n\nimport { isTransientError, TRANSIENT_GRACE_MS } from './http.js';\nimport { sleep } from './sleep.js';\n\nexport interface PollOptions<T> {\n /**\n * How long the thing may go WITHOUT MOVING before the wait gives up. With\n * `progressKey`, every change of the key restarts this clock, so an\n * operation of any length is waited out as long as it keeps moving and the\n * timeout bounds silence, not duration. Without it, the whole wait.\n */\n timeoutMs: number;\n pollMs: number;\n /** One line of progress for a value that has not settled; `start` is when the wait began. */\n describe?: (value: T, start: number) => string;\n /** Something that changes when the operation moves: a count, a phase, a timestamp. */\n progressKey?: (value: T) => string | number | null | undefined;\n onProgress?: (message: string) => void;\n}\n\nexport type PollOutcome<T> =\n { settled: true; value: T } | { settled: false; value: T };\n\n/**\n * Poll `read` until `isSettled` says so or the timeout elapses. A wait can run\n * for minutes through a tunnel; one gateway error is not an answer about the\n * thing being waited on, so it is retried for `TRANSIENT_GRACE_MS` before it\n * counts. Any other error propagates.\n */\nexport async function pollUntil<T>(\n read: () => Promise<T>,\n isSettled: (value: T) => boolean,\n options: PollOptions<T>,\n): Promise<PollOutcome<T>> {\n const start = Date.now();\n let movedAt = start;\n let lastKey: string | number | null | undefined;\n let transientSince: number | null = null;\n\n while (true) {\n let value: T;\n try {\n value = await read();\n transientSince = null;\n } catch (err) {\n if (!isTransientError(err)) {\n throw err;\n }\n transientSince ??= Date.now();\n if (Date.now() - transientSince > TRANSIENT_GRACE_MS) {\n throw err;\n }\n options.onProgress?.(\n `retrying after a gateway error… (${elapsedSeconds(start)}s)`,\n );\n await sleep(options.pollMs);\n continue;\n }\n\n if (isSettled(value)) {\n return { settled: true, value };\n }\n if (options.progressKey) {\n const key = options.progressKey(value);\n if (key !== lastKey) {\n lastKey = key;\n movedAt = Date.now();\n }\n }\n if (Date.now() - movedAt > options.timeoutMs) {\n return { settled: false, value };\n }\n if (options.describe) {\n options.onProgress?.(options.describe(value, start));\n }\n await sleep(options.pollMs);\n }\n}\n\nexport function elapsedSeconds(start: number): number {\n return Math.round((Date.now() - start) / 1000);\n}\n\n/** The standard timeout line: how long, and where the thing still is. */\nexport function timedOut(timeoutMs: number, still: string): string {\n return `Timed out after ${Math.round(timeoutMs / 1000)}s ${still}`;\n}\n","/**\n * The CLI's output contract, both halves in one place:\n * results and errors go to stdout as JSON, human progress goes to stderr.\n *\n * That split is what lets a caller pipe stdout straight into a JSON parser\n * while a person watching a long poll still sees something happen.\n */\n\nimport { elapsedSeconds } from './poll.js';\nimport type { OperationProgress } from './types/progress.js';\n\n/**\n * Compact JSON for machine callers, indented for a human at a terminal. remy\n * always reads this through a pipe, so it gets one JSON value per line — which\n * is what makes `--stream` output parseable line by line.\n */\nconst PRETTY = process.stdout.isTTY === true;\n\nexport function out(data: unknown): void {\n process.stdout.write(`${JSON.stringify(data, null, PRETTY ? 2 : 0)}\\n`);\n}\n\n/** Progress to stderr so stdout stays a clean stream of JSON values. */\nexport function progress(message: string): void {\n process.stderr.write(`${message}\\n`);\n}\n\n/** \"about 12 min left\" or \"about 2.5 h left\"; null without an ETA. */\nexport function describeEta(\n eta: string | null,\n now = Date.now(),\n): string | null {\n if (!eta) {\n return null;\n }\n const minutes = Math.max(1, Math.round((Date.parse(eta) - now) / 60_000));\n if (minutes < 90) {\n return `about ${minutes} min left`;\n }\n const hours = Math.round((minutes / 60) * 10) / 10;\n return `about ${hours} h left`;\n}\n\n/**\n * The one progress line every `--wait` prints: the operation's phase, its\n * count, the platform's measured rate and ETA, and how long this wait has run.\n * `extra` is the operation's own addendum (a job's spend, say).\n */\nexport function renderProgress(\n p: OperationProgress,\n start?: number,\n extra?: string | null,\n): string {\n const count =\n p.total !== null\n ? `${p.done.toLocaleString()}/${p.total.toLocaleString()} ${p.unit}`\n : p.done > 0\n ? `${p.done.toLocaleString()} ${p.unit}`\n : null;\n const rate =\n p.ratePerMinute !== null && p.ratePerMinute > 0\n ? `${Math.round(p.ratePerMinute).toLocaleString()}/min`\n : null;\n const parts = [\n `${p.phase}…`,\n // The operation's own word on what it is doing when the count does not\n // say (a settle building its full-text index); a failure's note is its\n // error and prints on its own line instead.\n p.phase !== 'failed' ? p.note : null,\n count,\n rate,\n describeEta(p.etaAt),\n extra ?? null,\n p.stalled ? 'no progress for 30 min' : null,\n ].filter((part): part is string => Boolean(part));\n const elapsed = start !== undefined ? ` (${elapsedSeconds(start)}s)` : '';\n return `${parts.join(' · ')}${elapsed}`;\n}\n","/**\n * Presigned-POST upload — bytes go straight to storage, never through the API,\n * so size isn't bounded by the API's JSON body limit. Shared by `files put`\n * and `datasources add`; the server mints `{ uploadUrl, uploadFields }` scoped\n * to one key, and this submits the multipart form (no auth headers — the\n * signature is in the fields).\n */\n\nexport async function uploadDirect(\n upload: { uploadUrl: string; uploadFields: Record<string, string> },\n bytes: Buffer,\n filename: string,\n): Promise<void> {\n const form = new FormData();\n for (const [key, value] of Object.entries(upload.uploadFields)) {\n form.append(key, value);\n }\n // Zero-copy view (a pooled Buffer can sit at an offset in a larger\n // ArrayBuffer, so slice by view — matters for the 100MB+ uploads this\n // path exists for). The cast is safe: fs reads never yield SharedArrayBuffer.\n const view = new Uint8Array(\n bytes.buffer as ArrayBuffer,\n bytes.byteOffset,\n bytes.byteLength,\n );\n form.append('file', new Blob([view]), filename);\n\n const res = await fetch(upload.uploadUrl, { method: 'POST', body: form });\n if (!res.ok) {\n const detail = await res.text().catch(() => '');\n throw new Error(\n `Upload of \"${filename}\" failed: ${res.status} ${res.statusText}${\n detail ? ` — ${detail.slice(0, 300)}` : ''\n }`,\n );\n }\n}\n","/**\n * Bulk ingestion jobs: load a corpus into a data source from a file-store\n * prefix or a manifest of URLs, with a plan (cost, size, duration) shown\n * before anything is spent.\n *\n * Ops are pure (ctx, params) → typed result. The CLI skin in\n * commands/dataSourceJobs.ts owns flags, progress printing and exit codes.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport { renderProgress } from '../output.js';\nimport { pollUntil, timedOut } from '../poll.js';\nimport { uploadDirect } from '../upload.js';\nimport type {\n DataSourceJob,\n DataSourceJobGetResult,\n DataSourceJobManifestTokenResult,\n DataSourceJobResult,\n DataSourceJobsListResult,\n DataSourceJobSource,\n} from '../types/dataSourceJobs.js';\n\n/** @internal Consumed by the CLI skin. */\nexport const DEFAULT_WAIT_TIMEOUT_MS = 60 * 60 * 1000;\nconst POLL_MS = 5000;\n\nfunction base(appId: string): string {\n return `/_internal/v2/apps/${appId}/datasources/jobs`;\n}\n\n// ─── start ───────────────────────────────────────────────────────────────────\n\nexport interface StartParams {\n /** Data source slug. Created on first use, like `add`. */\n slug: string;\n source: DataSourceJobSource;\n /** Run as soon as the plan passes the gates, without a separate approve. */\n approve?: boolean;\n /** Stop when estimated spend reaches this; default 1.5× the projection. */\n budgetDollars?: number;\n /** Batches in flight at once (default 64, max 128). */\n concurrency?: number;\n /**\n * Embed at the provider's priority tier: calls are admitted ahead of the\n * provider's queue at 1.5x the embedding price. Off by default.\n */\n priority?: boolean;\n /** Process only the first N objects — a sample of the corpus. */\n limit?: number;\n}\n\n/**\n * Start a job. The platform enumerates the source, reads a sample, and writes\n * a plan; the job then waits in `planned` for `approve` unless `approve` was\n * set. Nothing is embedded until it runs.\n *\n * @throws AdminApiError `data_source_busy` (422) — a move, a candidate\n * version or another job is in flight; `invalid_source` (400).\n * @example\n * const { job } = await admin.dataSourceJobs.start({\n * slug: 'archive',\n * source: { type: 'store', store: 'raw', access: 'private', prefix: '2024/' },\n * });\n */\nexport function start(ctx: AdminContext, params: StartParams) {\n const { slug, source, approve, budgetDollars, concurrency, priority, limit } =\n params;\n return call<DataSourceJobResult>(ctx, 'POST', base(ctx.appId), {\n slug,\n source,\n ...(approve ? { approve: true } : {}),\n ...(budgetDollars !== undefined ? { budgetDollars } : {}),\n ...(concurrency !== undefined ? { concurrency } : {}),\n ...(priority ? { priority: true } : {}),\n ...(limit !== undefined ? { limit } : {}),\n });\n}\n\n// ─── manifests ───────────────────────────────────────────────────────────────\n\nexport interface UploadManifestParams {\n slug: string;\n /** JSONL: one `{ url, filename?, externalId?, metadata? }` per line. */\n content: Buffer;\n}\n\n/**\n * Upload a manifest for `start` with a `manifest` source. Returns the key to\n * pass as `source.key`.\n */\nexport async function uploadManifest(\n ctx: AdminContext,\n params: UploadManifestParams,\n): Promise<{ key: string }> {\n const token = await call<DataSourceJobManifestTokenResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/manifest-token`,\n { slug: params.slug },\n );\n await uploadDirect(token.upload, params.content, 'manifest.jsonl');\n return { key: token.key };\n}\n\n// ─── read ────────────────────────────────────────────────────────────────────\n\nexport interface ListParams {\n /** Only this source's jobs; omit for every job on the app. */\n slug?: string;\n}\n\nexport function list(ctx: AdminContext, params?: ListParams) {\n return call<DataSourceJobsListResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}${qs({ slug: params?.slug })}`,\n );\n}\n\nexport interface JobIdParams {\n id: string;\n}\n\n/** @throws AdminApiError `job_not_found` (404). */\nexport function get(ctx: AdminContext, params: JobIdParams) {\n return call<DataSourceJobGetResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}`,\n );\n}\n\n// ─── controls ────────────────────────────────────────────────────────────────\n\n/**\n * Approve a planned job: the yes to the plan's spend. Refused when the\n * projection does not fit the source's placement or the workspace cannot\n * cover it.\n *\n * @throws AdminApiError `job_not_found` (404), `invalid_transition` (422),\n * `plan_requires_dedicated` (422), `plan_exceeds_capacity` (422),\n * `insufficient_credits/*` (402).\n */\nexport function approve(\n ctx: AdminContext,\n params: JobIdParams & {\n /** Batches in flight from here on (max 128); the plan was made at the job's current value. */\n concurrency?: number;\n /** Embed at the provider's priority tier from here on (1.5x the embedding price). */\n priority?: boolean;\n },\n) {\n return call<DataSourceJobResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/approve`,\n controlBody(params),\n );\n}\n\n/** The optional knobs approve and resume share; undefined when none is set. */\nfunction controlBody(params: {\n concurrency?: number;\n priority?: boolean;\n}): Record<string, unknown> | undefined {\n const body = {\n ...(params.concurrency !== undefined\n ? { concurrency: params.concurrency }\n : {}),\n ...(params.priority !== undefined ? { priority: params.priority } : {}),\n };\n return Object.keys(body).length > 0 ? body : undefined;\n}\n\n/** Stop dispatching batches; the ones in flight finish. */\nexport function pause(ctx: AdminContext, params: JobIdParams) {\n return call<DataSourceJobResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/pause`,\n );\n}\n\n/** Continue from the checkpoint; failed batches with attempts left are retried. */\nexport function resume(\n ctx: AdminContext,\n params: JobIdParams & {\n /** Batches in flight from here on (max 128). */\n concurrency?: number;\n /** Embed at the provider's priority tier from here on (1.5x the embedding price). */\n priority?: boolean;\n },\n) {\n return call<DataSourceJobResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/resume`,\n controlBody(params),\n );\n}\n\n/**\n * Run a finished job's failed batches again, after fixing what failed them.\n * The job goes back to `running`; `nothing_to_retry` when none failed.\n */\nexport function retry(ctx: AdminContext, params: JobIdParams) {\n return call<DataSourceJobResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/retry`,\n );\n}\n\n/** End the job. Documents already indexed stay. */\nexport function cancel(ctx: AdminContext, params: JobIdParams) {\n return call<DataSourceJobResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/cancel`,\n );\n}\n\n// ─── waits ───────────────────────────────────────────────────────────────────\n\nexport interface WaitParams {\n id: string;\n /** How long without movement before giving up. Default one hour. */\n timeoutMs?: number;\n onProgress?: (message: string) => void;\n}\n\nexport type WaitResult =\n | { status: 'done'; job: DataSourceJob }\n /** The plan is ready but the job will not run on its own: a gate refused, or it waits for approval. */\n | { status: 'planned'; job: DataSourceJob; error: string }\n | { status: 'failed'; job: DataSourceJob; error: string }\n | { status: 'timeout'; job: DataSourceJob; error: string };\n\n/**\n * Poll until the job leaves `planning`: the plan is ready (`done`), or a gate\n * refused it (`planned` with the job's error), or it could not be planned.\n */\nexport function waitForPlan(ctx: AdminContext, params: WaitParams) {\n return settle(ctx, params, (job) => job.state !== 'planning');\n}\n\n/**\n * Poll until the job reaches a terminal state, pauses for the owner, or\n * settles in `planned` with nothing about to move it: a gate refused an\n * auto-approved plan, or the plan waits for an approval nobody asked this wait\n * to give. A pause for errors that will resume itself (`autoResumeAt` set) is\n * ridden through; a pause that waits for the owner is reported as `failed`\n * with the pause reason, since nothing more will happen without them.\n */\nexport function waitForJob(ctx: AdminContext, params: WaitParams) {\n return settle(\n ctx,\n params,\n (job) =>\n !['planning', 'planned', 'running', 'paused'].includes(job.state) ||\n (job.state === 'planned' && (job.error !== null || !job.autoApprove)) ||\n (job.state === 'paused' && !job.autoResumeAt),\n );\n}\n\nasync function settle(\n ctx: AdminContext,\n params: WaitParams,\n isSettled: (job: DataSourceJob) => boolean,\n): Promise<WaitResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const outcome = await pollUntil(\n async () => (await get(ctx, { id: params.id })).job,\n isSettled,\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: describeProgress,\n // A load of any length is waited out while it moves; the timeout bounds\n // silence. Planning moves by objects listed, a run by documents.\n progressKey: (job) => `${job.state}:${job.progress.done}`,\n onProgress: params.onProgress,\n },\n );\n const job = outcome.value;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n job,\n error: timedOut(timeoutMs, `; job is still ${job.state}`),\n };\n }\n if (job.state === 'failed' || job.state === 'cancelled') {\n return {\n status: 'failed',\n job,\n error: job.error ?? `The job was ${job.state}.`,\n };\n }\n if (job.state === 'paused') {\n return {\n status: 'failed',\n job,\n error:\n job.error ??\n `The job paused (${job.pauseReason ?? 'user'}). Resume it to continue.`,\n };\n }\n if (job.state === 'planned' && (job.error !== null || job.autoApprove)) {\n return {\n status: 'planned',\n job,\n error:\n job.error ??\n 'The plan is ready but the job did not start. Approve it once the cause is fixed.',\n };\n }\n return { status: 'done', job };\n}\n\n/**\n * One line of progress in the job's own terms: the platform's phase, count,\n * rate and ETA, with the spend so far beside them. A planning walk that has\n * finished listing says so, since its count has stopped moving on purpose.\n */\nexport function describeProgress(job: DataSourceJob, start: number): string {\n if (job.state === 'planning' && job.enumerationDone) {\n return renderProgress(\n { ...job.progress, phase: 'planning' },\n start,\n `reading a sample of ${job.counts.objectsSeen.toLocaleString()} objects`,\n );\n }\n const spend =\n job.state === 'planning'\n ? null\n : `$${job.estimatedDollars.toFixed(2)}${\n job.budgetDollars !== null\n ? ` of $${job.budgetDollars.toFixed(2)}`\n : ''\n }`;\n return renderProgress(job.progress, start, spend);\n}\n","/**\n * S3 connectors: make a bucket the customer owns the origin of a data source,\n * and keep the source in sync with it.\n *\n * Ops are pure (ctx, params) → typed result. The CLI skin in\n * commands/dataSourceConnectors.ts owns flags, progress and exit codes.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport type {\n DataSourceConnectorDeletions,\n DataSourceConnectorGetResult,\n DataSourceConnectorResult,\n DataSourceSyncResult,\n} from '../types/dataSourceConnectors.js';\n\nfunction base(appId: string): string {\n return `/_internal/v2/apps/${appId}/datasources`;\n}\n\n// ─── connect ─────────────────────────────────────────────────────────────────\n\nexport interface ConnectParams {\n /** Data source slug. Created on first use, like `add`. */\n slug: string;\n bucket: string;\n /** AWS region of the bucket, e.g. `us-east-1`. */\n region: string;\n /** Key prefix to follow; omit for the whole bucket. */\n prefix?: string;\n /** S3-compatible endpoint (https; http for localhost). Omit for AWS. */\n endpoint?: string;\n /** NAME of the app secret holding the access key id. */\n accessKeyIdSecret: string;\n /** NAME of the app secret holding the secret access key. */\n secretAccessKeySecret: string;\n /** Default `mirror`. */\n deletions?: DataSourceConnectorDeletions;\n /** Ceiling a sync auto-approves under. */\n budgetDollarsPerSync?: number;\n}\n\n/**\n * Connect a source to a bucket. The two secrets must already exist on the app\n * (`secrets set`), and the keys must be able to list the prefix — both are\n * checked before anything is recorded. Calling again with the same bucket,\n * region, prefix and endpoint updates credentials and policy in place; a\n * different origin is refused until the source is disconnected.\n *\n * @throws AdminApiError `invalid_connector` (400), `connector_secret_missing`\n * (422), `connector_probe_failed` (422), `connector_exists` (422).\n * @example\n * await admin.dataSourceConnectors.connect({\n * slug: 'archive', bucket: 'acme-docs', region: 'us-east-1', prefix: 'contracts/',\n * accessKeyIdSecret: 'ARCHIVE_S3_KEY', secretAccessKeySecret: 'ARCHIVE_S3_SECRET',\n * });\n */\nexport function connect(ctx: AdminContext, params: ConnectParams) {\n const {\n slug,\n bucket,\n region,\n prefix,\n endpoint,\n accessKeyIdSecret,\n secretAccessKeySecret,\n deletions,\n budgetDollarsPerSync,\n } = params;\n return call<DataSourceConnectorResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/connector`,\n {\n slug,\n bucket,\n region,\n ...(prefix !== undefined ? { prefix } : {}),\n ...(endpoint !== undefined ? { endpoint } : {}),\n accessKeyIdSecret,\n secretAccessKeySecret,\n ...(deletions !== undefined ? { deletions } : {}),\n ...(budgetDollarsPerSync !== undefined ? { budgetDollarsPerSync } : {}),\n },\n );\n}\n\n// ─── read ────────────────────────────────────────────────────────────────────\n\n/** The source's connector with its object counts, or `connector: null`. */\nexport function get(ctx: AdminContext, params: { slug: string }) {\n return call<DataSourceConnectorGetResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/connector${qs({ slug: params.slug })}`,\n );\n}\n\n// ─── disconnect ──────────────────────────────────────────────────────────────\n\n/**\n * Stop following the bucket. The documents stay; only the connector and its\n * object index go.\n *\n * @throws AdminApiError `connector_not_found` (422), `data_source_busy` (422)\n * while a job is in flight.\n */\nexport function disconnect(ctx: AdminContext, params: { slug: string }) {\n return call<DataSourceConnectorResult & { removed: true }>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/connector/remove`,\n { slug: params.slug },\n );\n}\n\n// ─── sync ────────────────────────────────────────────────────────────────────\n\nexport interface SyncParams {\n slug: string;\n /** Override the connector's per-sync budget for this run, in dollars. */\n budgetDollars?: number;\n /** Only the first N objects of the listing — a slice to measure or check. */\n limit?: number;\n /** Batches in flight (default 64, max 128). */\n concurrency?: number;\n /** Embed at the provider's priority tier (1.5x the embedding price). Off by default. */\n priority?: boolean;\n}\n\n/**\n * Start a sync: list the bucket, diff by ETag, run a job over what changed.\n * Auto-approved under the connector's per-sync budget; a plan over it (or over\n * the placement's capacity) waits in `planned` for `dataSourceJobs.approve`.\n * Block on the result with `dataSourceJobs.waitForJob`.\n *\n * @throws AdminApiError `connector_not_found` (422), `data_source_busy` (422).\n */\nexport function sync(ctx: AdminContext, params: SyncParams) {\n return call<DataSourceSyncResult>(ctx, 'POST', `${base(ctx.appId)}/sync`, {\n slug: params.slug,\n ...(params.budgetDollars !== undefined\n ? { budgetDollars: params.budgetDollars }\n : {}),\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n ...(params.concurrency !== undefined\n ? { concurrency: params.concurrency }\n : {}),\n ...(params.priority ? { priority: true } : {}),\n });\n}\n","/**\n * Warming an index, sampling a source, and retrieval evals: query sets, runs,\n * comparisons. Ops are pure (ctx, params) → typed result; the CLI skin in\n * commands/dataSourceEvals.ts owns flags, progress printing and exit codes.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport { renderProgress } from '../output.js';\nimport { elapsedSeconds, pollUntil, timedOut } from '../poll.js';\nimport { list as listSources } from './dataSources.js';\nimport type { DataSourcesListEntry } from '../types/dataSources.js';\nimport type {\n DataSourcesHydrateResult,\n DataSourcesSampleResult,\n EvalCompareResult,\n EvalQueriesAddResult,\n EvalQueriesListResult,\n EvalQueryStyle,\n EvalRetrieval,\n EvalRun,\n EvalRunResult,\n EvalRunsListResult,\n EvalSet,\n EvalSetGetResult,\n EvalSetResult,\n EvalSetsListResult,\n} from '../types/dataSourceEvals.js';\n\n/** @internal Consumed by the CLI skin. */\nexport const DEFAULT_WAIT_TIMEOUT_MS = 30 * 60 * 1000;\nconst POLL_MS = 4000;\n\nfunction base(appId: string): string {\n return `/_internal/v2/apps/${appId}/datasources`;\n}\n\n// ─── hydrate ─────────────────────────────────────────────────────────────────\n\n/**\n * Warm a source's index if it is cold. A search on a large cold index answers\n * `index_warming` until the reload lands; call this before a demo, or after an\n * eviction you know about. Answers `resident: true` when nothing was needed.\n */\nexport function hydrate(ctx: AdminContext, params: { slug: string }) {\n return call<DataSourcesHydrateResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/hydrate`,\n { slug: params.slug },\n );\n}\n\n/**\n * Recreate a dedicated source's collection with the platform's current shape\n * and refill it from the stored vectors. Nothing is re-embedded. Dedicated\n * capacity only; refused while a job, move, hydration or candidate version is\n * in flight, and with `collection_shared` when another source shares the\n * collection on that capacity. Same response as `hydrate`: follow it with\n * `waitForHydration`.\n *\n * @throws AdminApiError `reindex_requires_dedicated` (422), `data_source_busy`\n * (422), `collection_shared` (422).\n */\nexport function reindex(ctx: AdminContext, params: { slug: string }) {\n return call<DataSourcesHydrateResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/reindex`,\n { slug: params.slug },\n );\n}\n\nexport interface WaitForHydrationParams {\n slug: string;\n /** How long without movement before giving up. Defaults to DEFAULT_WAIT_TIMEOUT_MS (30 min). */\n timeoutMs?: number;\n /** Receives `copying… X/Y documents · N/min · about M min left (Ns)`. */\n onProgress?: (message: string) => void;\n}\n\nexport type WaitForHydrationResult =\n | { status: 'done'; source: DataSourcesListEntry }\n | { status: 'failed'; source: DataSourcesListEntry; error: string }\n | { status: 'timeout'; source: DataSourcesListEntry; error: string };\n\n/** Poll the source list until its `hydration` clears, fails, or the timeout elapses. */\nexport async function waitForHydration(\n ctx: AdminContext,\n params: WaitForHydrationParams,\n): Promise<WaitForHydrationResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const outcome = await pollUntil(\n async () => {\n const { dataSources } = await listSources(ctx);\n const source = dataSources.find((s) => s.slug === params.slug);\n if (!source) {\n throw new Error(`Data source \"${params.slug}\" not found.`);\n }\n return source;\n },\n (source) => !source.hydration || source.hydration.error !== null,\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (source, start) =>\n renderProgress(source.hydration!.progress, start),\n // A reload of any size is waited out while it moves; the timeout\n // bounds silence.\n progressKey: (source) => source.hydration?.copied ?? null,\n onProgress: params.onProgress,\n },\n );\n const source = outcome.value;\n const hydration = source.hydration;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n source,\n error: timedOut(\n timeoutMs,\n `with ${hydration!.copied}/${hydration!.total} documents loaded`,\n ),\n };\n }\n if (hydration?.error) {\n return { status: 'failed', source, error: hydration.error };\n }\n return { status: 'done', source };\n}\n\n// ─── sample ──────────────────────────────────────────────────────────────────\n\nexport interface SampleParams {\n /** The source to draw from. */\n slug: string;\n /** Documents to draw (at most 2,000). */\n size: number;\n /** Slug for the sample; default `<slug>-sample`. */\n as?: string;\n /** Scope the draw: metadata equality, or the full document selector. */\n filter?: Record<string, unknown>;\n /** Metadata key to stratify on, proportional per value. */\n stratify?: string;\n placement?: { resourceId: string } | 'shared';\n}\n\n/**\n * Draw a sample of a source into a new source with the same pinned config.\n * The copy is a job (auto-approved; extraction is reused by content hash, so\n * the plan is chunk + embed only). Documents keep their content hashes, which\n * is what lets an eval set built on the sample score the parent too.\n *\n * @throws AdminApiError `invalid_size` (400), `slug_in_use` (422),\n * `data_source_limit` (422), `data_source_busy` (422).\n */\nexport function sample(ctx: AdminContext, params: SampleParams) {\n const { slug, size, as, filter, stratify, placement } = params;\n return call<DataSourcesSampleResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/sample`,\n {\n slug,\n size,\n ...(as ? { as } : {}),\n ...(filter ? { filter } : {}),\n ...(stratify ? { stratify } : {}),\n ...(placement !== undefined ? { placement } : {}),\n },\n );\n}\n\n// ─── query sets ──────────────────────────────────────────────────────────────\n\nexport interface CreateSetParams {\n slug: string;\n /** Lowercase [a-z0-9_-], unique per source. */\n name: string;\n description?: string;\n /** Queries to generate from the corpus; 0 (default) makes an empty set to add to. */\n size?: number;\n /** `cloze` (default, free) or `question` (a chat model writes them). */\n style?: EvalQueryStyle;\n /** Chat model for `question`; default the source's contextual model or the platform's. */\n modelId?: string;\n tags?: string[];\n /** Makes generation reproducible; default the current time. */\n seed?: number;\n}\n\n/**\n * Create a query set, generating queries from the corpus when `size` is set.\n * Generation runs in the background; the set is `generating` until it is\n * `ready` (see `waitForSet`).\n *\n * @throws AdminApiError `eval_set_exists` (422), `invalid_name` (400).\n */\nexport function createSet(ctx: AdminContext, params: CreateSetParams) {\n const { slug, name, description, size, style, modelId, tags, seed } = params;\n return call<EvalSetResult>(ctx, 'POST', `${base(ctx.appId)}/eval/sets`, {\n slug,\n name,\n ...(description ? { description } : {}),\n ...(size !== undefined ? { size } : {}),\n ...(style ? { style } : {}),\n ...(modelId ? { modelId } : {}),\n ...(tags?.length ? { tags } : {}),\n ...(seed !== undefined ? { seed } : {}),\n });\n}\n\nexport function listSets(ctx: AdminContext, params?: { slug?: string }) {\n return call<EvalSetsListResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/eval/sets${qs({ slug: params?.slug })}`,\n );\n}\n\nexport function getSet(\n ctx: AdminContext,\n params: { id: string; queries?: boolean },\n) {\n return call<EvalSetGetResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/eval/sets/${encodeURIComponent(params.id)}${qs({\n queries: params.queries ? 'true' : undefined,\n })}`,\n );\n}\n\nexport function deleteSet(ctx: AdminContext, params: { id: string }) {\n return call<{ deleted: true; set: EvalSet }>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/eval/sets/${encodeURIComponent(params.id)}/delete`,\n );\n}\n\nexport interface QueryInput {\n query: string;\n /** Which documents should come back; each reference must exist on the set's source. */\n expect: {\n documentIds?: string[];\n filenames?: string[];\n externalIds?: string[];\n contentHashes?: string[];\n };\n passage?: string;\n tags?: string[];\n}\n\n/**\n * Add hand-written queries (≤ 500 per call). Every reference is resolved\n * before anything is written; an unknown filename refuses the whole call by\n * name (`expected_document_not_found`).\n */\nexport function addQueries(\n ctx: AdminContext,\n params: { id: string; queries: QueryInput[] },\n) {\n return call<EvalQueriesAddResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/eval/sets/${encodeURIComponent(params.id)}/queries`,\n { queries: params.queries },\n );\n}\n\nexport function listQueries(ctx: AdminContext, params: { id: string }) {\n return call<EvalQueriesListResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/eval/sets/${encodeURIComponent(params.id)}/queries`,\n );\n}\n\nexport function deleteQuery(\n ctx: AdminContext,\n params: { id: string; queryId: string },\n) {\n return call<{ deleted: string; queryCount: number }>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/eval/sets/${encodeURIComponent(params.id)}/queries/delete`,\n { queryId: params.queryId },\n );\n}\n\n// ─── runs ────────────────────────────────────────────────────────────────────\n\nexport interface RunParams {\n setId: string;\n /** Target source; default the set's own. Expectations resolve by content hash. */\n slug?: string;\n /** Evaluate the target's candidate version instead of the active one. */\n candidate?: boolean;\n label?: string;\n retrieval?: EvalRetrieval;\n}\n\n/**\n * Score a set against a target. Runs in the background; block with\n * `waitForRun`. Each query is a real search (embedding + rerank spend).\n *\n * @throws AdminApiError `eval_set_not_ready` (422), `eval_set_empty` (422),\n * `no_candidate_pipeline` (404), `invalid_retrieval` (400).\n */\nexport function run(ctx: AdminContext, params: RunParams) {\n const { setId, slug, candidate, label, retrieval } = params;\n return call<EvalRunResult>(ctx, 'POST', `${base(ctx.appId)}/eval/runs`, {\n setId,\n ...(slug ? { slug } : {}),\n ...(candidate ? { candidate: true } : {}),\n ...(label ? { label } : {}),\n ...(retrieval && Object.keys(retrieval).length ? { retrieval } : {}),\n });\n}\n\nexport function listRuns(\n ctx: AdminContext,\n params?: { setId?: string; slug?: string },\n) {\n return call<EvalRunsListResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/eval/runs${qs({ setId: params?.setId, slug: params?.slug })}`,\n );\n}\n\nexport function getRun(\n ctx: AdminContext,\n params: { id: string; queries?: boolean; worst?: number },\n) {\n return call<EvalRunResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/eval/runs/${encodeURIComponent(params.id)}${qs({\n queries: params.queries ? 'true' : undefined,\n worst: params.worst,\n })}`,\n );\n}\n\n/** Two runs side by side: aggregate deltas, and per-query wins/losses when they share a set. */\nexport function compare(ctx: AdminContext, params: { a: string; b: string }) {\n return call<EvalCompareResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/eval/runs/compare${qs({ a: params.a, b: params.b })}`,\n );\n}\n\n// ─── waits ───────────────────────────────────────────────────────────────────\n\nexport interface WaitParams {\n id: string;\n timeoutMs?: number;\n onProgress?: (message: string) => void;\n}\n\nexport type WaitForRunResult =\n | { status: 'done'; run: EvalRun }\n | { status: 'failed'; run: EvalRun; error: string }\n | { status: 'timeout'; run: EvalRun; error: string };\n\nexport async function waitForRun(\n ctx: AdminContext,\n params: WaitParams,\n): Promise<WaitForRunResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const outcome = await pollUntil(\n async () => (await getRun(ctx, { id: params.id })).run,\n (run) => run.state === 'done' || run.state === 'failed',\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (run, start) =>\n `${run.state}… ${run.completed}/${run.total} queries (${elapsedSeconds(start)}s)`,\n onProgress: params.onProgress,\n },\n );\n const run = outcome.value;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n run,\n error: timedOut(\n timeoutMs,\n `; run is ${run.state} (${run.completed}/${run.total})`,\n ),\n };\n }\n if (run.state === 'failed') {\n return { status: 'failed', run, error: run.error ?? 'The run failed.' };\n }\n return { status: 'done', run };\n}\n\nexport type WaitForSetResult =\n | { status: 'done'; set: EvalSet }\n | { status: 'failed'; set: EvalSet; error: string }\n | { status: 'timeout'; set: EvalSet; error: string };\n\n/** Poll until generation lands (`ready`) or fails; a set waits `queued` for a worker first. */\nexport async function waitForSet(\n ctx: AdminContext,\n params: WaitParams,\n): Promise<WaitForSetResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const outcome = await pollUntil(\n async () => (await getSet(ctx, { id: params.id })).set,\n (set) => set.state === 'ready' || set.state === 'failed',\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (set, start) => `${set.state}… (${elapsedSeconds(start)}s)`,\n onProgress: params.onProgress,\n },\n );\n const set = outcome.value;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n set,\n error: timedOut(timeoutMs, `; set is still ${set.state}`),\n };\n }\n if (set.state === 'failed') {\n return { status: 'failed', set, error: set.error ?? 'Generation failed.' };\n }\n return { status: 'done', set };\n}\n","/**\n * Data-source mappers: the loop around customer code that turns raw objects\n * into documents — inspect the objects, test the mapper, make a build's mapper\n * the source's active one, remap after a fix, read and replay what a job\n * quarantined.\n *\n * Ops are pure (ctx, params) → typed result. The CLI skin in\n * commands/dataSourceMappers.ts owns flags, progress and exit codes.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport type {\n DataSourceInspectResult,\n DataSourceMapDeployResult,\n DataSourceMapTestResult,\n DataSourceQuarantineResult,\n DataSourceRemapResult,\n} from '../types/dataSourceMappers.js';\n\nfunction base(appId: string): string {\n return `/_internal/v2/apps/${appId}/datasources`;\n}\n\n/** Which objects to look at: a prefix of an app file store, or the connected bucket. */\nexport type ObjectSelection =\n | { store: string; access?: 'private' | 'public'; prefix?: string }\n | { connector: true };\n\nfunction selectionBody(selection: ObjectSelection): Record<string, unknown> {\n if ('connector' in selection) {\n return { connector: true };\n }\n return {\n store: selection.store,\n ...(selection.access ? { access: selection.access } : {}),\n ...(selection.prefix !== undefined ? { prefix: selection.prefix } : {}),\n };\n}\n\n// ─── inspect ─────────────────────────────────────────────────────────────────\n\nexport interface InspectParams {\n /** Required for a connector selection; optional for a store. */\n slug?: string;\n selection: ObjectSelection;\n /** Only these keys. */\n keys?: string[];\n /** Objects to list (default 5,000, max 50,000). */\n limit?: number;\n}\n\n/**\n * Profile raw objects before writing a mapper: counts and bytes by extension\n * and by key shape, size buckets, and ten sampled heads with their JSON key\n * signatures. Read-only.\n *\n * @throws AdminApiError `invalid_source` (400), `connector_not_found` (422).\n */\nexport function inspect(ctx: AdminContext, params: InspectParams) {\n return call<DataSourceInspectResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/inspect`,\n {\n ...(params.slug ? { slug: params.slug } : {}),\n ...selectionBody(params.selection),\n ...(params.keys ? { keys: params.keys } : {}),\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n },\n );\n}\n\n// ─── map test ────────────────────────────────────────────────────────────────\n\nexport interface MapTestParams {\n slug: string;\n selection: ObjectSelection;\n keys?: string[];\n /** Objects to map (default 20, max 200). */\n limit?: number;\n /** Run the LOCAL mapper through the app's dev session instead of the live bundle. */\n dev?: boolean;\n /**\n * With `dev`, which of your dev sessions: its dev release id. Default your\n * newest. Only ever your own.\n */\n releaseId?: string;\n}\n\n/**\n * Run the source's mapper over real objects and return the outcomes — nothing\n * is ingested. With `dev` the mapper runs from local source through the\n * running dev session, which is how a mapper is checked before a deploy.\n *\n * @throws AdminApiError `no_mapper` (422), `no_dev_session` (422),\n * `invalid_source` (400).\n */\nexport function mapTest(ctx: AdminContext, params: MapTestParams) {\n return call<DataSourceMapTestResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/map-test`,\n {\n slug: params.slug,\n ...selectionBody(params.selection),\n ...(params.keys ? { keys: params.keys } : {}),\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n ...(params.dev ? { dev: true } : {}),\n ...(params.releaseId ? { releaseId: params.releaseId } : {}),\n },\n );\n}\n\n// ─── remap ───────────────────────────────────────────────────────────────────\n\nexport interface RemapParams {\n slug: string;\n /** Pause when estimated spend reaches this; default the plan's headroom. */\n budgetDollars?: number;\n /** Only the first N raw objects. */\n limit?: number;\n}\n\n// ─── deploy ──────────────────────────────────────────────────────────────────\n\nexport interface MapDeployParams {\n slug: string;\n /**\n * The release to take the mapper from. Default: the newest built release —\n * live or the head of any branch — that carries a compiled mapper for the\n * slug.\n */\n releaseId?: string;\n}\n\n/**\n * Make a built release's compiled mapper the source's active mapper — what\n * jobs, syncs and `add()` run from now on. A branch build is enough: the app\n * need never have been published. Publishing to main also activates the\n * mapper main declares. Idempotent (`changed: false` when already active).\n *\n * @throws AdminApiError `no_built_mapper` (422) when no build carries a\n * compiled mapper for the slug, `release_not_found` (404).\n */\nexport function mapDeploy(ctx: AdminContext, params: MapDeployParams) {\n return call<DataSourceMapDeployResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/mapper/deploy`,\n {\n slug: params.slug,\n ...(params.releaseId ? { releaseId: params.releaseId } : {}),\n },\n );\n}\n\n/**\n * Run the active mapper over every raw object the source holds a copy of.\n * Auto-approved: unchanged markdown is skipped by hash, so a remap after a\n * metadata tweak costs frames and little else. Block on the job with\n * `dataSourceJobs.waitForJob`.\n *\n * @throws AdminApiError `no_mapper` (422), `nothing_to_remap` (422),\n * `data_source_busy` (422).\n */\nexport function remap(ctx: AdminContext, params: RemapParams) {\n return call<DataSourceRemapResult>(ctx, 'POST', `${base(ctx.appId)}/remap`, {\n slug: params.slug,\n ...(params.budgetDollars !== undefined\n ? { budgetDollars: params.budgetDollars }\n : {}),\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n });\n}\n\n// ─── quarantine + replay ─────────────────────────────────────────────────────\n\nexport interface QuarantineParams {\n id: string;\n kind?: 'skip' | 'error';\n /** Only the mapper's (`map`) or only the reader's (`read`). */\n stage?: 'map' | 'read';\n /** Only objects quarantined with exactly this reason. */\n reason?: string;\n cursor?: string;\n /** Page size (default 100, max 1,000). */\n limit?: number;\n}\n\n/**\n * What a job's mapper skipped or failed on, and what its reader failed on:\n * counts, reasons by frequency, and a page of objects.\n *\n * @throws AdminApiError `job_not_found` (404).\n */\nexport function quarantine(ctx: AdminContext, params: QuarantineParams) {\n return call<DataSourceQuarantineResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/jobs/${params.id}/quarantine${qs({\n ...(params.kind ? { kind: params.kind } : {}),\n ...(params.stage ? { stage: params.stage } : {}),\n ...(params.reason ? { reason: params.reason } : {}),\n ...(params.cursor ? { cursor: params.cursor } : {}),\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n })}`,\n );\n}\n\nexport interface ReplayParams {\n id: string;\n kind?: 'skip' | 'error';\n}\n\n/**\n * Run a job's quarantined objects through the current mapper, from their raw\n * copies. Starts a job; block on it with `dataSourceJobs.waitForJob`.\n *\n * @throws AdminApiError `nothing_to_replay` (422), `no_mapper` (422),\n * `data_source_busy` (422).\n */\nexport function replay(ctx: AdminContext, params: ReplayParams) {\n return call<DataSourceRemapResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/jobs/${params.id}/replay`,\n params.kind ? { kind: params.kind } : {},\n );\n}\n","/**\n * Database query operations.\n *\n * Ops are pure (ctx, sql) → typed result; the CLI skin in commands/db.ts\n * owns SQL assembly (the raw-spec mode, the tables introspection query) and\n * all output.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call } from '../http.js';\nimport type { DbQueryResult } from '../types/db.js';\n\n/**\n * Execute one SQL statement against the app's live-release database.\n *\n * The statement is passed verbatim — no parsing or rewriting. Both read\n * (`SELECT`) and write (`INSERT`, `UPDATE`, `DELETE`) statements are\n * accepted. The `results` array always has exactly one element for a single\n * statement; `changes` is 0 for SELECT.\n *\n * A statement the database refuses (a syntax error, a constraint, a result\n * too large) throws with `errorString: 'sql_error'`, and the body's\n * `errorMessage` is the database's own message.\n *\n * @param sql The SQL statement to execute.\n * @throws AdminApiError `no_live_release` (404) — the app has not been\n * deployed; `no_database` (404) — the live release has no database;\n * `invalid_request` (400) — `queries[]` missing or malformed;\n * `sql_error` (400) — the database refused the statement.\n * @example\n * const { results } = await admin.db.query('SELECT * FROM users LIMIT 10');\n */\nexport function query(ctx: AdminContext, sql: string) {\n return call<DbQueryResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/db/query`,\n { queries: [{ sql }] },\n );\n}\n","/**\n * Diagnostics operations: live-release id resolution (delegates to\n * ops/releases.ts to avoid duplicating the dashboard call), release diagnostics\n * fetch, and raw Lighthouse report download.\n *\n * Ops are pure: (ctx, params) → typed result. No printing, no process coupling.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, fetchWithTimeout, REPORT_TIMEOUT_MS, seg } from '../http.js';\nimport { dashboardLive } from './releases.js';\nimport type { DiagnosticsReleaseResult } from '../types/diagnostics.js';\n\n/**\n * Resolve the id of the currently-live release, or null if the app has not\n * been published. Delegates to the releases dashboardLive op to avoid\n * duplicating the dashboard endpoint call.\n *\n * @example\n * const releaseId = await admin.diagnostics.getLiveReleaseId();\n */\nexport async function getLiveReleaseId(\n ctx: AdminContext,\n): Promise<string | null> {\n const live = await dashboardLive(ctx);\n return live?.id ?? null;\n}\n\n/**\n * Fetch a release by id, including its Lighthouse diagnostics payload.\n *\n * `diagnostics` is null when the audit has not yet landed (~30–60s after\n * go-live). The `lighthouseJsonUrl` inside `diagnostics` is a short-lived\n * signed GET URL re-minted on each call — do not cache the URL.\n *\n * @param releaseId The release id to fetch (e.g. from `getLiveReleaseId`).\n * @throws AdminApiError `release_not_found` (404) — the release id does not\n * exist or belongs to a different app.\n * @example\n * const { diagnostics } = await admin.diagnostics.getRelease('rel_abc123');\n */\nexport function getRelease(ctx: AdminContext, releaseId: string) {\n return call<DiagnosticsReleaseResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/releases/${seg(releaseId)}`,\n );\n}\n\n/**\n * Fetch the raw Lighthouse JSON report from its signed URL. Uses\n * REPORT_TIMEOUT_MS since the report is a large artifact pulled from object\n * storage.\n *\n * @param url The short-lived signed URL from `diagnostics.lighthouseJsonUrl`.\n * @example\n * const report = await admin.diagnostics.fetchReport(url);\n */\nexport async function fetchReport(url: string): Promise<unknown> {\n const res = await fetchWithTimeout(\n url,\n {},\n REPORT_TIMEOUT_MS,\n 'Lighthouse report fetch',\n );\n if (!res.ok) {\n throw new Error(`Failed to fetch Lighthouse report: HTTP ${res.status}`);\n }\n return res.json();\n}\n","/**\n * Release operations: list, get, by-commit, dashboard live-release, and the\n * composite waitForCommit op that owns the two poll loops.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError (or a plain Error for application-level failures such as\n * an unexpected non-404 during commit resolve). No printing, no process\n * coupling — the CLI skin in commands/releases.ts and the importable client\n * both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, tryCall, qs, seg } from '../http.js';\nimport { sleep } from '../sleep.js';\nimport type {\n ReleasesListResult,\n ReleasesGetResult,\n ReleasesByCommitResult,\n DashboardResult,\n DashboardLiveRelease,\n V2ReleaseStatus,\n} from '../types/releases.js';\n\nexport interface ReleasesListParams {\n /** Max releases to return per page (default 20, clamped 1–100). */\n limit?: number;\n}\n\n/**\n * Paginated list of releases, newest first (non-dev only).\n *\n * Returns up to `limit` releases. `nextCursor` in the response is non-null\n * when further pages exist; pass it as a raw query parameter to walk all pages.\n *\n * @example\n * const { releases } = await admin.releases.list({ limit: 50 });\n */\nexport function list(ctx: AdminContext, params: ReleasesListParams = {}) {\n return call<ReleasesListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/releases${qs({ limit: params.limit })}`,\n );\n}\n\n/**\n * Full detail for a single release by id.\n *\n * Includes build log, methods, interfaces, databases, a short-lived signed\n * commit-diff URL, a signed Lighthouse diagnostics URL, and the async\n * post-deploy progress state.\n *\n * @throws AdminApiError `release_not_found` (404) — no release with that id exists on this app.\n * @example\n * const release = await admin.releases.get('rel_abc123');\n * console.log(release.status, release.buildDurationMs);\n */\nexport function get(ctx: AdminContext, releaseId: string) {\n return call<ReleasesGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/releases/${seg(releaseId)}`,\n );\n}\n\n/**\n * By-commit lookup. Returns the raw tryCall result so callers can tolerate\n * 404s during the resolve-grace window (used internally by waitForCommit and\n * exposed for programmatic callers that want a one-shot lookup).\n *\n * HTTP errors arrive as `{ ok: false, status, body }` rather than thrown —\n * the API returns `invalid_commit_sha` (400) for non-hex input and\n * `release_not_found` (404) when the commit has no release yet.\n *\n * @example\n * const r = await admin.releases.byCommit('91ca67a');\n * if (r.ok) console.log(r.body.status);\n */\nexport function byCommit(\n ctx: AdminContext,\n commitSha: string,\n): Promise<{ ok: boolean; status: number; body: ReleasesByCommitResult }> {\n return tryCall<ReleasesByCommitResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/releases/by-commit/${seg(commitSha)}`,\n );\n}\n\n/**\n * The currently-live release, or null when the app has never been published.\n * Fetched from the dashboard endpoint — same source as `releases current`.\n *\n * @example\n * const live = await admin.releases.dashboardLive();\n * if (live) console.log(live.commitSha, live.publishedAt);\n */\nexport async function dashboardLive(\n ctx: AdminContext,\n): Promise<DashboardLiveRelease | null> {\n const dashboard = await call<DashboardResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/dashboard`,\n );\n return dashboard.liveRelease;\n}\n\n// ---- waitForCommit internals ----\n\n/**\n * Compact, stable projection of a release for the wait result.\n *\n * `previewUrl` is present for a feature-branch build (status 'preview') and is\n * where that build is actually reachable — gated to anyone who can open the app\n * in Remy. Reported as data rather than taught as a URL shape, so the caller\n * never has to construct one.\n */\nexport interface ReleaseSummary {\n releaseId: string;\n commitSha: string;\n branch: string | null;\n status: V2ReleaseStatus;\n buildDurationMs: number | null;\n publishedAt: string | null;\n previewUrl?: string;\n /** Why it failed; only present when status is `failed`. */\n error?: string;\n /**\n * Only present when status is `failed`. 'interrupted' means a platform\n * restart killed the build and a retry is already running — not a code\n * problem. See ReleaseFailureFields.\n */\n failureKind?: 'build' | 'interrupted' | 'unbuildable';\n /** Build stage that was running when it failed; only when `failed`. */\n failurePhase?: string;\n /**\n * Each data source whose reader this live release brought live, with the\n * documents it hasn't read: what `datasources reread --unread` reads, priced\n * first. Absent when the release declares no reader.\n */\n readers?: { slug: string; unread: number }[];\n}\n\nfunction summarizeRelease(release: ReleasesByCommitResult): ReleaseSummary {\n const summary: ReleaseSummary = {\n releaseId: release.id,\n commitSha: release.commitSha,\n branch: release.branch ?? null,\n status: release.status,\n buildDurationMs: release.buildDurationMs ?? null,\n publishedAt: release.publishedAt ?? null,\n ...(release.previewUrl ? { previewUrl: release.previewUrl } : {}),\n };\n const readers = (release.dataSources ?? []).filter((d) => d.reader);\n if (readers.length > 0 && release.status === 'live') {\n summary.readers = readers.map((d) => ({\n slug: d.slug,\n unread: d.readerUnread ?? 0,\n }));\n }\n if (release.status !== 'failed') {\n return summary;\n }\n return {\n ...summary,\n error:\n release.failureReason ?? 'Build failed (no error entry in the build log)',\n ...(release.failureKind ? { failureKind: release.failureKind } : {}),\n ...(release.failurePhase ? { failurePhase: release.failurePhase } : {}),\n };\n}\n\n/**\n * Terminal outcome of a `waitForCommit` call.\n *\n * `live` — deployed to the default branch; the app is live.\n * `preview` — feature-branch build finished; `summary.previewUrl` is set.\n * `failed` — build error; `summary.error` carries the reason.\n * `superseded` — a newer commit for this app finished first.\n * `timeout` — timed out before a terminal status; `summary` has the last-known state.\n * `not_found` — no release registered within the 30s resolve grace.\n */\nexport type WaitOutcome =\n 'live' | 'preview' | 'failed' | 'superseded' | 'timeout' | 'not_found';\n\nexport interface WaitForCommitResult {\n /** Terminal outcome; determines which other fields are populated. */\n outcome: WaitOutcome;\n /** Raw release row at the time of resolution; absent for `not_found`. */\n release?: ReleasesByCommitResult;\n /** The summarizeRelease projection; absent for `not_found`. */\n summary?: ReleaseSummary;\n /**\n * Error message string for `not_found` and `timeout` outcomes. The CLI skin\n * incorporates this into the printable output object. For `failed`, the error\n * is already baked into `summary.error` by summarizeRelease.\n */\n error?: string;\n}\n\nexport interface WaitForCommitParams {\n /** Full or abbreviated (7–40 hex char) git commit SHA; the API matches by prefix. */\n commitSha: string;\n /** Defaults to 300 000 ms (5 min), matching the CLI's --timeout 300 default. */\n timeoutMs?: number;\n /**\n * Called with the exact progress strings the CLI prints via progress():\n * `waiting for release to be created for ${shortSha}…`\n * `${status}… (Ns)`\n */\n onProgress?: (message: string) => void;\n}\n\nconst POLL_MS = 3_000;\nconst RESOLVE_GRACE_MS = 30_000;\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\n/**\n * Wait for the release built from a git commit to reach a terminal state.\n *\n * The \"publish and wait until live\" primitive. Phase 1 resolves the release\n * row by commit SHA, tolerating 404s for up to 30s — a SHA polled immediately\n * after `git push` will briefly 404 while the receive-pack hook registers it,\n * and that is expected. Phase 2 polls every 3s until the release reaches a\n * terminal status or the timeout expires.\n *\n * Possible outcomes:\n * `live` — default-branch deploy succeeded; the app is live.\n * `preview` — feature-branch build finished; `summary.previewUrl` is the gated URL.\n * `failed` — build failed; `summary.error` carries the last build-log error entry.\n * `superseded` — a newer commit finished first and this build was skipped.\n * `timeout` — `timeoutMs` elapsed before a terminal status; `summary` has the last-known state.\n * `not_found` — no release created within the 30s resolve grace; the push may not have\n * registered yet, or this SHA never produced a build.\n *\n * `onProgress` is called with a human-readable string on each poll cycle —\n * the exact strings the CLI skin passes to `progress()`, so callers can echo\n * them without reformatting.\n *\n * Throws a plain `Error` (not AdminApiError) only when Phase 1 encounters an\n * unexpected non-404 HTTP error (e.g. a 500 from the API).\n *\n * @example\n * const result = await admin.releases.waitForCommit({\n * commitSha: '91ca67a',\n * timeoutMs: 600_000,\n * onProgress: (msg) => console.error(msg),\n * });\n * if (result.outcome !== 'live' && result.outcome !== 'preview') {\n * throw new Error(result.error ?? result.outcome);\n * }\n */\nexport async function waitForCommit(\n ctx: AdminContext,\n params: WaitForCommitParams,\n): Promise<WaitForCommitResult> {\n const { commitSha, onProgress } = params;\n const timeoutMs = params.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const shortSha = commitSha.slice(0, 8);\n const start = Date.now();\n\n // Phase 1 — resolve the release for this commit.\n let release: ReleasesByCommitResult;\n while (true) {\n const r = await byCommit(ctx, commitSha);\n if (r.ok) {\n release = r.body;\n break;\n }\n if (r.status !== 404) {\n throw new Error(\n `Failed to resolve release for ${shortSha}: HTTP ${r.status} ${JSON.stringify(r.body)}`,\n );\n }\n if (Date.now() - start > RESOLVE_GRACE_MS) {\n return {\n outcome: 'not_found',\n error: `No release created for commit ${commitSha} within ${RESOLVE_GRACE_MS / 1000}s — either the push hasn't registered yet or this SHA never produced a build`,\n };\n }\n onProgress?.(`waiting for release to be created for ${shortSha}…`);\n await sleep(POLL_MS);\n }\n\n // Phase 2 — poll status until terminal.\n const SUCCESS = new Set<string>(['live', 'preview']);\n while (true) {\n if (SUCCESS.has(release.status)) {\n return {\n outcome: release.status as 'live' | 'preview',\n release,\n summary: summarizeRelease(release),\n };\n }\n if (release.status === 'failed') {\n return { outcome: 'failed', release, summary: summarizeRelease(release) };\n }\n if (release.status === 'superseded') {\n return {\n outcome: 'superseded',\n release,\n summary: summarizeRelease(release),\n };\n }\n if (Date.now() - start > timeoutMs) {\n return {\n outcome: 'timeout',\n release,\n summary: summarizeRelease(release),\n error: `Timed out after ${timeoutMs / 1000}s (last status: ${release.status})`,\n };\n }\n onProgress?.(\n `${release.status}… (${Math.round((Date.now() - start) / 1000)}s)`,\n );\n await sleep(POLL_MS);\n const r = await byCommit(ctx, commitSha);\n if (r.ok) {\n release = r.body;\n }\n // A transient non-ok keeps the last known release; the timeout guard above\n // still applies, so we don't loop forever on a persistent error.\n }\n}\n","/**\n * App domain operations: platform subdomain + custom hostnames.\n *\n * `findHostname` resolves a user-supplied hostname to its row id and full\n * entry (list → match → id). It throws a plain Error with the exact\n * \"not found\" message the CLI historically surfaced — the entry-point catch\n * prints `.message` identically whether it came from `fatal()` or here.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, seg } from '../http.js';\nimport type {\n DomainsCustomHostnameView,\n DomainsCustomListResult,\n DomainsCustomAddResult,\n DomainsCustomCheckResult,\n DomainsCustomRemoveResult,\n DomainsCustomRetryResult,\n DomainsGetResult,\n DomainsSetResult,\n DomainsCheckResult,\n} from '../types/domains.js';\n\n/**\n * Get the app's current platform subdomain (e.g. `my-app.madewithremy.com`).\n *\n * Returns `{ subdomain: null }` when none is set.\n *\n * @example\n * const { subdomain } = await admin.domains.get();\n */\nexport function get(ctx: AdminContext) {\n return call<DomainsGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-subdomain`,\n );\n}\n\n/**\n * Set the app's platform subdomain.\n *\n * @param subdomain The desired subdomain (hyphenated, no suffix).\n * @example\n * await admin.domains.set('my-app');\n */\nexport function set(ctx: AdminContext, subdomain: string) {\n return call<DomainsSetResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-subdomain`,\n { subdomain },\n );\n}\n\n/**\n * Check whether a platform subdomain is available before calling `set`.\n *\n * @example\n * const { isAvailable } = await admin.domains.check('my-app');\n */\nexport function check(ctx: AdminContext, subdomain: string) {\n return call<DomainsCheckResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-subdomain/check-availability`,\n { subdomain },\n );\n}\n\n/**\n * List all custom hostnames registered on the app.\n *\n * Results come from a Cloudflare-synced cache that can be up to ~5 minutes\n * stale. Use `customRetry` to force a synchronous re-check after the customer\n * adds DNS records. `uiStatus` values: `waiting_for_dns | issuing_ssl | live |\n * action_needed | reconnecting`.\n *\n * @example\n * const { hostnames } = await admin.domains.customList();\n * const live = hostnames.filter((h) => h.uiStatus === 'live');\n */\nexport function customList(ctx: AdminContext) {\n return call<DomainsCustomListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-domains`,\n );\n}\n\n/**\n * Register a custom hostname on the app.\n *\n * Apex input (e.g. `acme.com`) auto-creates the `www.acme.com` pair and\n * returns both entries. `dnsInstructions` on each returned entry contains\n * the DNS records the customer must add to their provider.\n *\n * @throws AdminApiError `invalid_hostname` (400) — the hostname failed format\n * validation; `hostname_in_use` (400) — the hostname (or its auto-paired\n * www) is already registered on any app.\n * @example\n * const { hostnames } = await admin.domains.customAdd('acme.com');\n * // hostnames[0] = apex row, hostnames[1] = www pair\n */\nexport function customAdd(ctx: AdminContext, hostname: string) {\n return call<DomainsCustomAddResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-domains`,\n { hostname },\n );\n}\n\n/**\n * Preflight a hostname before registering: validates format, checks\n * availability, and signals whether an apex would auto-pair www.\n *\n * Never throws — invalid input returns `{ valid: false, errorMessage }`.\n *\n * @example\n * const { valid, willAutoPairWww } = await admin.domains.customCheck('acme.com');\n */\nexport function customCheck(ctx: AdminContext, hostname: string) {\n return call<DomainsCustomCheckResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-domains/check-domain`,\n { hostname },\n );\n}\n\n/**\n * Resolve a hostname entry by name: lists all hostnames and matches on the\n * canonical lowercase hostname, returning the row id and full entry.\n *\n * @throws Error `No custom domain \"${hostname}\" found on this app` when the\n * hostname is not registered.\n * @example\n * const { id, entry } = await admin.domains.findHostname('app.acme.com');\n */\nexport async function findHostname(\n ctx: AdminContext,\n hostname: string,\n): Promise<{ id: string; entry: DomainsCustomHostnameView }> {\n const wanted = hostname.toLowerCase();\n const res = await customList(ctx);\n const entry = (res.hostnames ?? []).find(\n (h) => typeof h.hostname === 'string' && h.hostname === wanted,\n );\n if (!entry) {\n throw new Error(`No custom domain \"${hostname}\" found on this app`);\n }\n return { id: entry.id, entry };\n}\n\n/**\n * Remove a custom hostname from the app.\n *\n * Apex hostnames also remove their paired `www.` entry. The hostname is\n * resolved internally via `findHostname` before the delete call.\n *\n * @throws Error `No custom domain \"${hostname}\" found on this app` when not\n * registered; AdminApiError `not_found` (404) if the resolved id has gone\n * stale.\n * @example\n * await admin.domains.customRemove('acme.com');\n */\nexport async function customRemove(ctx: AdminContext, hostname: string) {\n const { id } = await findHostname(ctx, hostname);\n return call<DomainsCustomRemoveResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-domains/${seg(id)}/delete`,\n );\n}\n\n/**\n * Re-trigger Cloudflare validation for a hostname, typically after the\n * customer has updated their DNS records.\n *\n * @throws Error `No custom domain \"${hostname}\" found on this app` when not\n * registered; AdminApiError `not_found` (404) if the resolved id has gone\n * stale; `no_cf_id` (400) — the hostname was never registered with\n * Cloudflare and cannot be retried.\n * @example\n * const { hostname: updated } = await admin.domains.customRetry('app.acme.com');\n */\nexport async function customRetry(ctx: AdminContext, hostname: string) {\n const { id } = await findHostname(ctx, hostname);\n return call<DomainsCustomRetryResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/custom-domains/${seg(id)}/retry`,\n );\n}\n","/**\n * Email operations: outbound delivery log, blast stats, suppression list,\n * inbound inbox, and custom domain management (both directions).\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/email.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n EmailBatchResult,\n EmailBatchesResult,\n EmailDomainBase,\n EmailInboxResult,\n EmailListResult,\n EmailMessageResult,\n EmailSendingStatusResult,\n EmailStatsResult,\n EmailSuppressResult,\n EmailSuppressionsResult,\n EmailUnsuppressResult,\n InboundEmailDomainAddResult,\n InboundEmailDomainCheckResult,\n InboundEmailDomainDeleteResult,\n InboundEmailDomainVerifyResult,\n InboundEmailDomainsListResult,\n OutboundEmailDomainAddResult,\n OutboundEmailDomainCheckResult,\n OutboundEmailDomainDeleteResult,\n OutboundEmailDomainVerifyResult,\n OutboundEmailDomainsListResult,\n} from '../types/email.js';\n\n// ---------------------------------------------------------------------------\n// Param interfaces\n// ---------------------------------------------------------------------------\n\nexport interface EmailListParams {\n /**\n * Comma-separated statuses to include. Values: `suppressed`, `failed`,\n * `sent`, `delivered`, `blocked`, `bounced`, `complained`, `delayed`,\n * `rejected`. Default: all statuses. `blocked` means an SES suppression list\n * dropped the message before delivery — usually this app's OWN tenant list\n * (a prior hard bounce or spam report from that address), occasionally the\n * shared account-wide list. `unsuppress` reports which.\n */\n status?: string;\n /** Origin to filter by: `method` (app-sent) or `auth` (sign-in codes). Default: all. */\n kind?: string;\n /**\n * Exact-match recipient address (index-backed, fast). Use `search` for\n * partial or substring matches instead.\n */\n recipient?: string;\n /** Show only messages belonging to this blast / campaign batch id. */\n batchId?: string;\n /**\n * Substring search across subject and recipient address. Bounded; results\n * are not cursor-paginated.\n */\n search?: string;\n /** ISO date range start (inclusive). */\n start?: string;\n /** ISO date range end (inclusive). */\n end?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface EmailWindowParams {\n /** ISO date range start (inclusive). */\n start?: string;\n /** ISO date range end (inclusive). */\n end?: string;\n}\n\nexport interface EmailBatchesParams {\n /** ISO date range start (inclusive). */\n start?: string;\n /** ISO date range end (inclusive). */\n end?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface EmailSuppressionsParams {\n limit?: number;\n offset?: number;\n}\n\nexport interface EmailInboxParams {\n /** Filter by processing status: `success` or `error`. Default: all. */\n status?: string;\n /** Substring search across sender address and subject. */\n search?: string;\n /** ISO date range start (inclusive). */\n start?: string;\n /** ISO date range end (inclusive). */\n end?: string;\n /** Cursor from a previous response for pagination. */\n cursor?: string;\n limit?: number;\n}\n\n/** Direction of mail flow: `sending` = outbound (a domain at the email provider); `inbound` = receiving (MX). */\nexport type DomainDirection = 'sending' | 'inbound';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst DOMAIN_BASES: Record<DomainDirection, string> = {\n sending: 'outbound-email-domains',\n inbound: 'email-domains',\n};\n\nfunction domainsPath(ctx: AdminContext, direction: DomainDirection): string {\n return `/_internal/v2/apps/${ctx.appId}/settings/${DOMAIN_BASES[direction]}`;\n}\n\nasync function resolveDomainId(\n ctx: AdminContext,\n direction: DomainDirection,\n domain: string,\n): Promise<string> {\n const { domains } = await call<{ domains: EmailDomainBase[] }>(\n ctx,\n 'GET',\n domainsPath(ctx, direction),\n );\n const wanted = domain.trim().toLowerCase();\n const match = (domains ?? []).find(\n (d: { domain: string }) => d.domain.toLowerCase() === wanted,\n );\n if (!match) {\n const known = (domains ?? []).map((d: { domain: string }) => d.domain);\n throw new Error(\n `No ${direction} domain \"${domain}\" on this app.` +\n (known.length ? ` Registered: ${known.join(', ')}` : ''),\n );\n }\n return match.id;\n}\n\n// ---------------------------------------------------------------------------\n// Outbound message ops\n// ---------------------------------------------------------------------------\n\n/**\n * Sent messages for this app, including messages that never reached SES.\n *\n * The log covers every send attempt — suppressed, over-cap,\n * sender-not-allowed — because most real failures never touch the provider.\n * Status values: `suppressed` (app-level unsubscribe), `failed`, `sent`,\n * `delivered`, `blocked` (dropped by an SES suppression list — usually this\n * app's own tenant list after an earlier bounce or spam report from that\n * address), `bounced`, `complained`, `delayed`, `rejected`. Paginated via\n * cursor in the result or by offset.\n *\n * @example\n * const { messages } = await admin.email.list({ status: 'bounced,blocked', limit: 50 });\n */\nexport function list(ctx: AdminContext, params: EmailListParams = {}) {\n return call<EmailListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/messages${qs(params)}`,\n );\n}\n\n/**\n * Full detail for one outbound message, including bounce diagnostics.\n *\n * @throws AdminApiError `not_found` (404) — no message with that id on this app.\n * @example\n * const msg = await admin.email.get('msg_abc123');\n * console.log(msg.status, msg.diagnostic);\n */\nexport function get(ctx: AdminContext, messageId: string) {\n return call<EmailMessageResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/messages/${seg(messageId)}`,\n );\n}\n\n/**\n * Aggregate counts and delivery rates over a time window.\n *\n * `accepted` is the denominator for all rates (messages SES received);\n * `counts` includes pre-SES failures. `series` is a per-bucket time-series\n * for charting.\n *\n * @example\n * const { counts, rates } = await admin.email.stats({ start: '2026-01-01T00:00:00Z' });\n */\nexport function stats(ctx: AdminContext, params: EmailWindowParams = {}) {\n return call<EmailStatsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/summary${qs(params)}`,\n );\n}\n\n/**\n * Whether this app can send email right now, and up to what — the first thing\n * to check when \"it's not sending emails\".\n *\n * Reports four independent things: `sending` (the gate the send path itself\n * uses, so this and a `409 sending_paused` can never disagree), `enforcement`\n * (the platform's own throttle/pause and WHO applied it), `ses` (Amazon's view\n * of the app's tenant), and `quota` (the daily recipient limit, usage, and\n * where the limit came from).\n *\n * How to read a pause: `sending.source === 'ses'` means Amazon paused the\n * tenant on its own findings — nothing the app owner does lifts it directly;\n * it clears when the finding clears. `source === 'platform'` with\n * `enforcement.origin === 'platform'` is the automatic bounce/complaint sweep\n * and steps down on its own as rates recover; `origin === 'operator'` is a\n * human hold and will not. A throttle shows up as `enforcement.level:\n * 'throttled'` with the reduced `quota.limit` and its `expiresAt`.\n *\n * @example\n * const s = await admin.email.status();\n * if (!s.sending.allowed) console.log(s.sending.source, s.sending.reason);\n * console.log(`${s.quota.used}/${s.quota.limit ?? '∞'} recipients today`);\n */\nexport function status(ctx: AdminContext) {\n return call<EmailSendingStatusResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/status`,\n );\n}\n\n/**\n * One row per blast/campaign with per-status counts and, for queued sends,\n * the in-flight lifecycle.\n *\n * A marketing send delivers one message per recipient; many rows share a\n * `batchId` (set by the caller via `sendEmail`). `recipients` is the total\n * fan-out count including pre-SES failures; `accepted` is the SES-received\n * denominator used for rate calculations.\n *\n * Large or marketing sends are accepted immediately and delivered in chunks —\n * `status` (`accepted`/`sending`/`completed`/`partial`/`failed`), `chunksDone`/\n * `chunksTotal` and `pending` report the progress. `status: null` is a normal,\n * finished send delivered inline (or predating the queue), not an error.\n *\n * @example\n * const { batches } = await admin.email.batches({ limit: 20 });\n * const inFlight = batches.filter((b) => b.status === 'sending');\n */\nexport function batches(ctx: AdminContext, params: EmailBatchesParams = {}) {\n return call<EmailBatchesResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/batches${qs(params)}`,\n );\n}\n\n/**\n * Stats for a single blast identified by its batch id, including the queued\n * lifecycle (`status`, chunk progress, `pending`) when the send was queued.\n * A reused batch id reports its NEWEST run's lifecycle.\n *\n * @throws AdminApiError `not_found` (404) — no batch with that id on this app.\n * @example\n * const blast = await admin.email.batch('batch_xyz');\n * console.log(blast.status, blast.pending, blast.counts);\n */\nexport function batch(ctx: AdminContext, batchId: string) {\n return call<EmailBatchResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/batches/${seg(batchId)}`,\n );\n}\n\n/**\n * App-level suppression list (addresses that have opted out of this app's mail).\n *\n * @example\n * const { suppressions } = await admin.email.suppressions({ limit: 100 });\n */\nexport function suppressions(\n ctx: AdminContext,\n params: EmailSuppressionsParams = {},\n) {\n return call<EmailSuppressionsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/suppressions${qs(params)}`,\n );\n}\n\n/**\n * Add an address to this app's suppression list.\n *\n * @throws AdminApiError `invalid_email` (400) — the address is not a valid email.\n * @example\n * await admin.email.suppress('user@example.com');\n */\nexport function suppress(ctx: AdminContext, email: string) {\n return call<EmailSuppressResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/suppressions/add`,\n { email },\n );\n}\n\n/**\n * Remove an address from this app's suppression lists — the app-level\n * unsubscribe row AND the app's SES tenant suppression entry (a prior hard\n * bounce or spam report against this app), which is the one that actually\n * unblocks delivery.\n *\n * No `confirm` parameter here — the op is the deliberate act. The CLI skin\n * keeps the `--confirm` gate before calling this.\n *\n * Read the result, not just `ok`: `tenantEntryRemoved` true means a\n * provider-side bounce record was cleared and mail will be attempted again\n * (another bounce re-suppresses automatically); `platformSuppression` non-null\n * means the address is on SES's ACCOUNT-wide list — never cleared, shared by\n * every app — and this removal changed nothing about deliverability. The CLI\n * skin surfaces both advisories on stderr.\n *\n * @throws AdminApiError `invalid_email` (400) — the address is not a valid email.\n * @example\n * const result = await admin.email.unsuppress('user@example.com');\n * if (result.platformSuppression) console.warn('Still blocked account-wide.');\n */\nexport function unsuppress(ctx: AdminContext, email: string) {\n return call<EmailUnsuppressResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/outbound-email/suppressions/remove`,\n { email },\n );\n}\n\n/**\n * Inbound messages received by this app (sender/subject previews).\n *\n * An inbox row's `id` is its request-log id — open the full detail (parsed\n * message, method run, errors) with `requests.get(id)`. Cursor-paginated;\n * the next page token is in `EmailInboxResult.nextCursor`.\n *\n * @example\n * const { emails } = await admin.email.inbox({ status: 'error', limit: 20 });\n */\nexport function inbox(ctx: AdminContext, params: EmailInboxParams = {}) {\n return call<EmailInboxResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/inbox${qs(params)}`,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Domain ops (both directions via DomainDirection)\n//\n// Generic over the direction so a literal 'sending' / 'inbound' argument gets\n// the direction's concrete result type (the sending list carries\n// effectiveSender; the inbound one doesn't), while a runtime variable — the\n// CLI's spec-key factory passes one — still resolves to the union. The\n// implementation casts once: `call` can't know the conditional, but the path\n// selection and the conditional select on the same DomainDirection value.\n// ---------------------------------------------------------------------------\n\n/**\n * Direction-conditional result selector: maps a literal `DomainDirection` to\n * its concrete result type, or the union when the direction is a runtime variable.\n */\nexport type ForDirection<D extends DomainDirection, Sending, Inbound> = [\n D,\n] extends ['sending']\n ? Sending\n : [D] extends ['inbound']\n ? Inbound\n : Sending | Inbound;\n\n/**\n * All registered custom domains for a direction.\n *\n * Sending domains (`'sending'`) include `effectiveSender` — the address the\n * app currently sends from and its fallback tier (`app_domain` > `org_domain`\n * > `subdomain` > `default`). Inbound domains (`'inbound'`) list custom\n * receiving domains; apps already receive at `*@<slug>.madewithremy.com` with\n * no setup.\n *\n * @example\n * const { domains, effectiveSender } = await admin.email.listDomains('sending');\n */\nexport function listDomains<D extends DomainDirection>(\n ctx: AdminContext,\n direction: D,\n): Promise<\n ForDirection<D, OutboundEmailDomainsListResult, InboundEmailDomainsListResult>\n> {\n return call(ctx, 'GET', domainsPath(ctx, direction)) as Promise<\n ForDirection<\n D,\n OutboundEmailDomainsListResult,\n InboundEmailDomainsListResult\n >\n >;\n}\n\n/**\n * Pre-flight check: validate a domain name and confirm it is not already registered.\n *\n * For inbound domains, also returns `dnsInstructions` (the MX record) when\n * `valid` is true — the record is known before registration and can be given\n * to the user up front. Sending domain DKIM CNAMEs are only available after\n * `addDomain`. Returns `{ valid: false, errorMessage }` inline rather than\n * throwing for validation failures.\n *\n * @example\n * const { valid, dnsInstructions } = await admin.email.checkDomain('inbound', 'acme.com');\n */\nexport function checkDomain<D extends DomainDirection>(\n ctx: AdminContext,\n direction: D,\n domain: string,\n): Promise<\n ForDirection<D, OutboundEmailDomainCheckResult, InboundEmailDomainCheckResult>\n> {\n return call(ctx, 'POST', `${domainsPath(ctx, direction)}/check-domain`, {\n domain,\n }) as Promise<\n ForDirection<\n D,\n OutboundEmailDomainCheckResult,\n InboundEmailDomainCheckResult\n >\n >;\n}\n\n/**\n * Register a new custom domain in the given direction.\n *\n * **Sending (`'sending'`):** creates the domain at the email provider and\n * returns `dnsInstructions.records`, the DNS records to publish, each marked\n * required or not (on the cloud, three DKIM CNAMEs and a recommended SPF TXT).\n * Hand these to the user to create at their DNS host, then call `verifyDomain`\n * to re-check. Verification can take minutes after the records resolve;\n * `uiStatus` will be `pending` until then.\n *\n * **Inbound (`'inbound'`):** creates the domain row and returns\n * `dnsInstructions` with the MX record to add, plus an `ownershipTxt` record\n * when the domain was already aimed at the platform or held by another app\n * (it verifies only once both are published). Apps already receive at\n * `*@<slug>.madewithremy.com`; a custom inbound domain is optional.\n *\n * @throws AdminApiError `invalid_domain` (400) — not a valid registrable domain\n * name; `domain_in_use` (400) — already registered on any app;\n * `sending_domain_create_failed` (502, sending only) — the provider\n * couldn't create the domain; `sending_domains_unavailable` (400, sending\n * only) — the deployment sends from one address and takes no domains.\n * @example\n * const { domain } = await admin.email.addDomain('sending', 'mail.acme.com');\n * console.log(domain.dnsInstructions.records);\n */\nexport function addDomain<D extends DomainDirection>(\n ctx: AdminContext,\n direction: D,\n domain: string,\n): Promise<\n ForDirection<D, OutboundEmailDomainAddResult, InboundEmailDomainAddResult>\n> {\n return call(ctx, 'POST', domainsPath(ctx, direction), {\n domain,\n }) as Promise<\n ForDirection<D, OutboundEmailDomainAddResult, InboundEmailDomainAddResult>\n >;\n}\n\n/**\n * Force an immediate DNS check on a registered domain.\n *\n * Resolves the domain name to its row id via an extra GET, then calls the\n * `retry` endpoint. Use after adding DNS records to check earlier than the\n * background poller. `uiStatus` transitions from `pending` → `verified`, or\n * stays `action_needed` (check `verificationErrors`). Sending verification\n * that was never started expires after ~72h; fix the records and call\n * `verifyDomain` again.\n *\n * @throws Error if no domain matching `domain` is registered on this app\n * (thrown before the API call, not an AdminApiError).\n * @throws AdminApiError `not_found` (404) — the row was deleted between list and verify.\n * @example\n * const { domain } = await admin.email.verifyDomain('sending', 'mail.acme.com');\n * console.log(domain.uiStatus, domain.verificationErrors);\n */\nexport async function verifyDomain<D extends DomainDirection>(\n ctx: AdminContext,\n direction: D,\n domain: string,\n): Promise<\n ForDirection<\n D,\n OutboundEmailDomainVerifyResult,\n InboundEmailDomainVerifyResult\n >\n> {\n const id = await resolveDomainId(ctx, direction, domain);\n return call(\n ctx,\n 'POST',\n `${domainsPath(ctx, direction)}/${seg(id)}/retry`,\n ) as Promise<\n ForDirection<\n D,\n OutboundEmailDomainVerifyResult,\n InboundEmailDomainVerifyResult\n >\n >;\n}\n\n/**\n * Remove a registered domain.\n *\n * For sending domains, also removes the domain at the email provider\n * (best-effort; a failure there still removes the row). Resolves the domain name to its row\n * id via an extra GET before deletion.\n *\n * @throws Error if no domain matching `domain` is registered on this app\n * (thrown before the API call, not an AdminApiError).\n * @throws AdminApiError `not_found` (404) — the row was deleted between list and delete.\n * @example\n * await admin.email.removeDomain('sending', 'mail.acme.com');\n */\nexport async function removeDomain<D extends DomainDirection>(\n ctx: AdminContext,\n direction: D,\n domain: string,\n): Promise<\n ForDirection<\n D,\n OutboundEmailDomainDeleteResult,\n InboundEmailDomainDeleteResult\n >\n> {\n const id = await resolveDomainId(ctx, direction, domain);\n return call(\n ctx,\n 'POST',\n `${domainsPath(ctx, direction)}/${seg(id)}/delete`,\n ) as Promise<\n ForDirection<\n D,\n OutboundEmailDomainDeleteResult,\n InboundEmailDomainDeleteResult\n >\n >;\n}\n","/**\n * File-store operations: presigned uploads, read links, metadata, listing,\n * deletion. Pure (ctx, params) → typed result; the CLI skin owns everything\n * filesystem-shaped (path resolution, reading/writing disk).\n */\n\nimport path from 'node:path';\nimport { createHash } from 'node:crypto';\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\nimport { uploadDirect } from '../upload.js';\nimport type {\n FilesDeleteResult,\n FilesListResult,\n FilesLsResult,\n FilesStatResult,\n FilesUploadUrlResult,\n FilesUrlResult,\n} from '../types/files.js';\n\nexport type FileAccess = 'public' | 'private';\n\nexport interface FileRef {\n /** Store name (e.g. 'assets'). */\n store: string;\n /** 'public' or 'private'. */\n access: FileAccess;\n /** Store-relative object key. */\n key: string;\n}\n\nexport interface FilesPutParams {\n content: Buffer;\n store: string;\n access: FileAccess;\n /**\n * Omitted → content-addressed: `<sha256(content)><ext-of-filename>`.\n * Idempotent and immutable, so the returned URL is safe to bake into source.\n */\n key?: string;\n /** Used for the upload form part name and the default key's extension. */\n filename?: string;\n contentType?: string;\n /**\n * Omitted → content-addressed public objects default to\n * `public, max-age=31536000, immutable` (their keys are never reused);\n * everything else falls through to the server default.\n */\n cacheControl?: string;\n /** Called just before the byte upload starts. */\n onProgress?: (message: string) => void;\n}\n\n/**\n * Upload a file via presigned POST (up to 5 GiB).\n *\n * The API mints a presigned S3 POST; bytes go straight to storage, bypassing\n * the API's JSON body limit. The key defaults to sha256(content) plus the\n * filename extension (see `FilesPutParams.key`), making re-uploads of the same\n * bytes idempotent and their URL safe to bake into source. Pass `key` for a\n * stable, overwritable name (e.g. a config JSON the frontend fetches).\n *\n * @throws AdminApiError `invalid_store` (400); `invalid_access` (400);\n * `invalid_key` (400).\n * @example\n * const { key, url } = await admin.files.put({\n * content: imageBuffer,\n * store: 'assets',\n * access: 'public',\n * filename: 'hero.jpg',\n * });\n */\nexport async function put(\n ctx: AdminContext,\n params: FilesPutParams,\n): Promise<{ key: string; url: string }> {\n const { content, store, access, filename } = params;\n const key =\n params.key ||\n `${createHash('sha256').update(content).digest('hex')}${\n filename ? path.extname(filename) : ''\n }`;\n const cacheControl =\n params.cacheControl ||\n (!params.key && access === 'public'\n ? 'public, max-age=31536000, immutable'\n : undefined);\n\n const presign = await call<FilesUploadUrlResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/file-storage/upload-url`,\n {\n store,\n access,\n key,\n maxSize: content.length,\n ...(params.contentType ? { contentType: params.contentType } : {}),\n ...(cacheControl ? { cacheControl } : {}),\n },\n );\n\n params.onProgress?.(\n `uploading ${(content.length / 1024 / 1024).toFixed(1)}MB…`,\n );\n await uploadDirect(\n { uploadUrl: presign.uploadUrl, uploadFields: presign.uploadFields },\n content,\n filename ?? key,\n );\n\n return { key: presign.key, url: presign.url };\n}\n\n/**\n * Mint a read link for one object.\n *\n * Private objects return a signed, expiring URL with `expiresAt` (ttl clamped\n * server-side to [60s, 7d], default 300s). Public objects return a permanent\n * on-domain URL with no expiry. Use a private store plus `sign` as the\n * sensitive-file handoff channel — links are unguessable and the object stays\n * deletable.\n *\n * @param ttlSeconds Requested TTL in seconds (clamped to [60, 604800]; default\n * 300). Ignored for public objects.\n * @throws AdminApiError `invalid_store` (400); `invalid_access` (400);\n * `invalid_key` (400); `file_flagged` (403) — the object was flagged by AV\n * scanning and cannot be linked.\n * @example\n * const { url, expiresAt } = await admin.files.sign(\n * { store: 'handoff', access: 'private', key },\n * 86400,\n * );\n */\nexport function sign(ctx: AdminContext, ref: FileRef, ttlSeconds?: number) {\n return call<FilesUrlResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/file-storage/url${qs({ ...ref, ttl: ttlSeconds })}`,\n );\n}\n\n/**\n * Download an object's bytes in-process.\n *\n * Mints a 60s presigned link via `sign`, then plain-fetches it — the link is\n * self-authorizing, so no auth headers are needed for the byte transfer. No\n * timeout on the byte stream; large objects are the whole point.\n *\n * @throws AdminApiError `file_flagged` (403) — the object was flagged by AV\n * scanning; also propagates `sign` errors.\n * @example\n * const { bytes, contentType } = await admin.files.fetchBytes({\n * store: 'handoff',\n * access: 'private',\n * key,\n * });\n */\nexport async function fetchBytes(\n ctx: AdminContext,\n ref: FileRef,\n): Promise<{ bytes: Buffer; contentType: string | null }> {\n const { url } = await sign(\n ctx,\n ref,\n ref.access === 'private' ? 60 : undefined,\n );\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Download failed: ${res.status} ${res.statusText}`);\n }\n return {\n bytes: Buffer.from(await res.arrayBuffer()),\n contentType: res.headers.get('content-type'),\n };\n}\n\n/**\n * Object metadata (size, contentType, updatedAt, scan status) — no download.\n *\n * A missing key throws AdminApiError 404, so this doubles as an existence\n * check without transferring any bytes.\n *\n * @throws AdminApiError `invalid_store` (400); `invalid_access` (400);\n * `invalid_key` (400); 404 if the key does not exist.\n * @example\n * const meta = await admin.files.stat({\n * store: 'assets',\n * access: 'public',\n * key: 'hero.jpg',\n * });\n */\nexport function stat(ctx: AdminContext, ref: FileRef) {\n return call<FilesStatResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/file-storage/metadata${qs(ref)}`,\n );\n}\n\nexport interface FilesLsParams {\n /** Store name (e.g. 'assets'). */\n store: string;\n /** 'public' or 'private'. */\n access: FileAccess;\n /** Return only keys that start with this string. */\n prefix?: string;\n /** Server-side substring search (switches the listing mode). */\n q?: string;\n /** Pagination cursor from the previous page's `cursor` field. */\n cursor?: string;\n /** Maximum objects to return per page. */\n limit?: number;\n}\n\n/**\n * List objects in one store with optional prefix filtering or substring search.\n *\n * Flat list by default. Pass `q` for substring search across the whole store\n * (overrides `prefix`, delimiter ignored). Results are paginated — follow the\n * returned `cursor` to fetch the next page.\n *\n * @throws AdminApiError `invalid_store` (400); `invalid_access` (400).\n * @example\n * const { files, cursor } = await admin.files.ls({\n * store: 'assets',\n * access: 'public',\n * prefix: 'images/',\n * });\n */\nexport function ls(ctx: AdminContext, params: FilesLsParams) {\n return call<FilesLsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/file-storage${qs(params)}`,\n );\n}\n\n/**\n * Store-level summary: every store with object counts, total bytes, and\n * AV/PII scan status histograms.\n *\n * @example\n * const { stores, totalObjects } = await admin.files.summary();\n */\nexport function summary(ctx: AdminContext) {\n return call<FilesListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/file-storage/summary`,\n );\n}\n\n/**\n * Delete one object from a store.\n *\n * @throws AdminApiError `invalid_store` (400); `invalid_access` (400);\n * `invalid_key` (400).\n * @example\n * await admin.files.remove({ store: 'handoff', access: 'private', key });\n */\nexport function remove(ctx: AdminContext, ref: FileRef) {\n return call<FilesDeleteResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/file-storage/delete`,\n { store: ref.store, access: ref.access, keys: [ref.key] },\n );\n}\n","/**\n * Provisioned-infrastructure operations: lease, park, resume and delete\n * dedicated resources (first kind: retrieval capacity for data sources).\n *\n * Ops are pure (ctx, params) → typed result. The CLI skin in\n * commands/infra.ts owns flag parsing, progress printing and exit codes.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call } from '../http.js';\nimport { renderProgress } from '../output.js';\nimport { elapsedSeconds, pollUntil, timedOut } from '../poll.js';\nimport type {\n InfraGetResult,\n InfraListResult,\n InfraLogsResult,\n InfraPhase,\n InfraResource,\n InfraResourceResult,\n} from '../types/infra.js';\n\n/** @internal Consumed by the CLI skin; waitForPhase documents the default. */\nexport const DEFAULT_WAIT_TIMEOUT_MS = 10 * 60 * 1000;\nconst POLL_MS = 3000;\n\nfunction base(appId: string): string {\n return `/_internal/v2/apps/${appId}/infra`;\n}\n\n// ─── list ────────────────────────────────────────────────────────────────────\n\nexport interface ListParams {\n /** Include resources that have been deleted; off by default. */\n includeDestroyed?: boolean;\n}\n\n/**\n * The app's dedicated resources plus the offerings it can provision, with\n * their hourly and monthly prices.\n *\n * @example\n * const { resources, offerings } = await admin.infra.list();\n */\nexport function list(ctx: AdminContext, params?: ListParams) {\n return call<InfraListResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}${params?.includeDestroyed ? '?includeDestroyed=true' : ''}`,\n );\n}\n\n// ─── get ─────────────────────────────────────────────────────────────────────\n\nexport interface GetParams {\n /** Resource id. */\n id: string;\n}\n\n/**\n * One resource with its state timeline and the data sources placed on it.\n *\n * @throws AdminApiError `resource_not_found` (404).\n */\nexport function get(ctx: AdminContext, params: GetParams) {\n return call<InfraGetResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}`,\n );\n}\n\n// ─── logs ────────────────────────────────────────────────────────────────────\n\nexport interface LogsParams {\n /** Resource id. */\n id: string;\n /** Continue after this line id (the last line of a previous page). */\n after?: string;\n /** Lines per page; without `after`, the newest this many. Max 500. */\n limit?: number;\n}\n\n/**\n * The platform's narration of a resource, oldest first: the steps a\n * transition went through, failed attempts, and failures with the pod's\n * events and a warnings-and-errors tail of the instance log. Not the\n * instance's own stdout.\n *\n * @throws AdminApiError `resource_not_found` (404).\n */\nexport function logs(ctx: AdminContext, params: LogsParams) {\n const query = new URLSearchParams();\n if (params.after) {\n query.set('after', params.after);\n }\n if (params.limit) {\n query.set('limit', String(params.limit));\n }\n const search = query.toString();\n return call<InfraLogsResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/logs${search ? `?${search}` : ''}`,\n );\n}\n\n// ─── provision ───────────────────────────────────────────────────────────────\n\nexport interface ProvisionParams {\n /** Offering id from `list().offerings`, e.g. `retrieval.small`. */\n offeringId: string;\n /** Display name; defaults to the offering label. */\n name?: string;\n}\n\n/**\n * Lease a new resource. Spends credits: the workspace must have a month's\n * worth available before the request is accepted; nothing is charged until\n * activation, and from then the resource bills by the hour.\n *\n * The response is the row in `requested`; the platform brings it to `active`\n * within a minute or so. Use `waitForPhase` to block on that.\n *\n * @throws AdminApiError `offering_not_found` (400), `offering_retired` (422),\n * `provisioning_unavailable` (422), `insufficient_credits/*` (402).\n * @example\n * const { resource } = await admin.infra.provision({ offeringId: 'retrieval.small' });\n */\nexport function provision(ctx: AdminContext, params: ProvisionParams) {\n return call<InfraResourceResult>(ctx, 'POST', base(ctx.appId), {\n offeringId: params.offeringId,\n ...(params.name ? { name: params.name } : {}),\n });\n}\n\n// ─── hibernate / resume / destroy / rename ───────────────────────────────────\n\nexport interface ResourceIdParams {\n /** Resource id. */\n id: string;\n}\n\n/**\n * Park an active resource. Data is kept; searches on its data sources return\n * `capacity_hibernating` while it parks and `capacity_hibernated` once parked,\n * until it resumes; billing drops to the retained-storage rate.\n *\n * @throws AdminApiError `resource_not_found` (404), `invalid_transition` (422).\n */\nexport function hibernate(ctx: AdminContext, params: ResourceIdParams) {\n return call<InfraResourceResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/hibernate`,\n );\n}\n\n/**\n * Bring a hibernated (or failed) resource back to active.\n *\n * @throws AdminApiError `resource_not_found` (404), `invalid_transition` (422).\n */\nexport function resume(ctx: AdminContext, params: ResourceIdParams) {\n return call<InfraResourceResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/resume`,\n );\n}\n\n/**\n * Delete a resource. Refused while any data source is placed on it — move\n * those to shared capacity (`admin.dataSources.move({ placement: 'shared' })`,\n * data intact) or delete them first. Billing stops when the phase reaches\n * `destroyed`.\n *\n * @throws AdminApiError `resource_not_found` (404),\n * `resource_has_attachments` (422), `invalid_transition` (422).\n */\nexport function destroy(ctx: AdminContext, params: ResourceIdParams) {\n return call<InfraResourceResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/destroy`,\n );\n}\n\nexport interface ResizeParams {\n id: string;\n /** Offering id from `list().offerings`, e.g. `retrieval.medium`. */\n offeringId: string;\n}\n\n/**\n * Change a resource's size, keeping its documents.\n *\n * The platform parks the resource, swaps its spec, and brings it back up with\n * its sources' indexes rebuilt from durable storage in the background, so a\n * resize passes through `hibernated` and searches on those sources answer\n * `index_warming` with the rebuild's progress until it lands. A resource that\n * is already hibernated swaps in place and stays parked. Growing is gated on a\n * month of credits at the new rate like a provision; shrinking is refused\n * below what the resource holds. The response carries `resizingTo` until the\n * swap has happened; `waitForPhase` with `until: (r) => r.resizingTo === null`\n * blocks on the whole thing.\n *\n * @throws AdminApiError `resource_not_found` (404), `offering_not_found`\n * (400), `offering_retired` (422), `same_offering` (400),\n * `offering_kind_mismatch` (400), `resize_pending` (422), `resize_too_small`\n * (422), `insufficient_credits/*` (402), `invalid_transition` (422).\n * @example\n * await admin.infra.resize({ id, offeringId: 'retrieval.medium' });\n */\nexport function resize(ctx: AdminContext, params: ResizeParams) {\n return call<InfraResourceResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/resize`,\n { offeringId: params.offeringId },\n );\n}\n\nexport interface RenameParams {\n id: string;\n name: string;\n}\n\n/** @throws AdminApiError `resource_not_found` (404), `invalid_name` (400). */\nexport function rename(ctx: AdminContext, params: RenameParams) {\n return call<InfraResourceResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/${encodeURIComponent(params.id)}/rename`,\n { name: params.name },\n );\n}\n\n// ─── waitForPhase ────────────────────────────────────────────────────────────\n\nexport interface WaitForPhaseParams {\n id: string;\n /** The phase(s) that count as done. */\n phases: InfraPhase[];\n /**\n * An extra condition on top of the phase — a resize, for one, ends in the\n * phase it started from and is done only once `resizingTo` has cleared.\n */\n until?: (resource: InfraResource) => boolean;\n /** How long without movement before giving up. Default 10 minutes. */\n timeoutMs?: number;\n onProgress?: (message: string) => void;\n}\n\nexport type WaitForPhaseResult =\n | { status: 'done'; resource: InfraResource }\n | { status: 'failed'; resource: InfraResource; error: string }\n | { status: 'timeout'; resource: InfraResource; error: string };\n\n/**\n * Poll a resource until it reaches one of `phases`, fails, or the timeout\n * elapses. A `failed` phase returns immediately with the platform's error.\n *\n * @example\n * const result = await admin.infra.waitForPhase({ id, phases: ['active'] });\n */\nexport async function waitForPhase(\n ctx: AdminContext,\n params: WaitForPhaseParams,\n): Promise<WaitForPhaseResult> {\n const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;\n const wanted = new Set<InfraPhase>(params.phases);\n const arrived = (resource: InfraResource) =>\n wanted.has(resource.phase) && (params.until?.(resource) ?? true);\n\n const outcome = await pollUntil(\n async () => (await get(ctx, { id: params.id })).resource,\n (resource) => arrived(resource) || resource.phase === 'failed',\n {\n timeoutMs,\n pollMs: POLL_MS,\n describe: (resource, start) =>\n resource.progress\n ? renderProgress(\n resource.progress,\n start,\n resource.resizingTo\n ? `resizing to ${resource.resizingTo.label}`\n : null,\n )\n : `${resource.phase}${resource.detail ? ` · ${resource.detail}` : ''}${\n resource.resizingTo\n ? ` · resizing to ${resource.resizingTo.label}`\n : ''\n }… (${elapsedSeconds(start)}s)`,\n // A rebuild after a resume runs as long as it must; the timeout bounds\n // silence, and a phase or step change counts as movement.\n progressKey: (resource) =>\n `${resource.phase}:${resource.progress?.done ?? ''}:${resource.detail ?? ''}`,\n onProgress: params.onProgress,\n },\n );\n const resource = outcome.value;\n if (!outcome.settled) {\n return {\n status: 'timeout',\n resource,\n error: timedOut(timeoutMs, `; resource is still ${resource.phase}`),\n };\n }\n if (arrived(resource)) {\n return { status: 'done', resource };\n }\n return {\n status: 'failed',\n resource,\n error: resource.lastError ?? 'The platform could not complete the change.',\n };\n}\n","/**\n * App issues operations: CRUD for bugs, ideas, and tasks.\n *\n * Ops take resolved strings for body content — the stdin read\n * (`fs.readFileSync(0, ...)`) stays in the CLI skin (commands/issues.ts).\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n IssuesListResult,\n IssuesGetResult,\n IssuesCreateResult,\n IssuesCommentResult,\n IssuesUpdateResult,\n IssuesDeleteResult,\n} from '../types/issues.js';\n\n// The origin the API should credit for an entry this client writes, as a\n// spreadable fragment. Empty when the client is acting as the app it is pointed\n// at, which is the ordinary case and the one the API reads as \"my own agent\".\nfunction authorship(ctx: AdminContext): { originAppId?: string } {\n return ctx.originAppId ? { originAppId: ctx.originAppId } : {};\n}\n\nexport interface IssuesListParams {\n /** Filter by status: `open` or `closed`. Omit for any state. */\n status?: string;\n /** Match issues carrying ANY of these labels. */\n labels?: string[];\n /** Only issues another app filed here, by that app's id. */\n originAppId?: string;\n /** Max issues to return (default 50). */\n limit?: number;\n /** Keyset cursor from a previous response's `nextCursor`. */\n cursor?: string;\n}\n\n// The wire names the list routes read. `labels` is sent as a repeated `label`\n// param, so the mapping is explicit rather than a field rename away from\n// silently dropping the filter.\nfunction listQuery(params: IssuesListParams): string {\n return qs({\n status: params.status,\n label: params.labels,\n originAppId: params.originAppId,\n limit: params.limit,\n cursor: params.cursor,\n });\n}\n\n/**\n * List the issues filed IN an app, newest-first.\n *\n * @throws AdminApiError `invalid_status` (400) — status is not `open` or\n * `closed`.\n * @example\n * const { issues } = await admin.issues.list({ status: 'open', labels: ['bug'] });\n */\nexport function list(ctx: AdminContext, params: IssuesListParams = {}) {\n return call<IssuesListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/issues${listQuery(params)}`,\n );\n}\n\n/**\n * List the issues this app filed INTO other apps, newest-first.\n *\n * The sender's half of a cross-app thread: one call returns every issue the\n * app sent out, so a fan-out across forty apps is read once rather than forty\n * times. Scoped to apps in the same workspace.\n *\n * @throws AdminApiError `invalid_status` (400) — status is not `open` or\n * `closed`.\n * @example\n * const { issues } = await admin.issues.filed({ status: 'open' });\n */\nexport function filed(\n ctx: AdminContext,\n params: Omit<IssuesListParams, 'originAppId'> = {},\n) {\n return call<IssuesListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/issues/filed${listQuery(params)}`,\n );\n}\n\n/**\n * Get one issue with its full comment thread.\n *\n * @param number The friendly per-app issue number (e.g. `\"42\"`), as shown\n * in `list` results under `issue.number`.\n * @throws AdminApiError `issue_not_found` (404) — no issue with this number\n * in this app.\n * @example\n * const { issue, comments } = await admin.issues.get('42');\n */\nexport function get(ctx: AdminContext, number: string) {\n return call<IssuesGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}`,\n );\n}\n\nexport interface IssuesCreateParams {\n /** Issue title (required, non-empty). */\n title: string;\n /** Issue body in markdown. */\n body?: string;\n /** Labels to file it under. Open set, at most 20, 64 chars each. */\n labels?: string[];\n /**\n * The app filing this, when it isn't the app the issue lands in. Defaults to\n * `ctx.originAppId` — set whenever the caller retargeted at another app — so\n * cross-app authorship is recorded without anyone opting in. Pass it\n * explicitly only to override that.\n */\n originAppId?: string;\n}\n\n/**\n * File a new issue authored as the agent (`authorKind: \"agent\"`).\n *\n * Returns the created issue row. When the server is supplied a `source`\n * blob and an open issue for the same source already existed, it returns\n * that issue with `deduped: true` (no new row created); the ops layer does\n * not accept `source`, so `deduped` is always absent from op-layer responses.\n *\n * @throws AdminApiError `missing_title` (400) — title is required or empty;\n * `invalid_labels` (400) — labels are not strings, or exceed the count /\n * length caps; `invalid_origin_app_id` (400) — originAppId is not an app id.\n * @example\n * const { issue } = await admin.issues.create({ title: 'Checkout 500s on empty cart', labels: ['bug'] });\n */\nexport function create(ctx: AdminContext, params: IssuesCreateParams) {\n const requestBody: Record<string, unknown> = {\n title: params.title,\n authorKind: 'agent',\n };\n if (params.body !== undefined) {\n requestBody.body = params.body;\n }\n if (params.labels !== undefined) {\n requestBody.labels = params.labels;\n }\n const originAppId = params.originAppId ?? ctx.originAppId;\n if (originAppId !== undefined) {\n requestBody.originAppId = originAppId;\n }\n return call<IssuesCreateResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/issues`,\n requestBody,\n );\n}\n\n/**\n * Post a comment on an issue's thread authored as the agent.\n *\n * @param number The issue number.\n * @param body The comment body (non-empty).\n * @throws AdminApiError `missing_body` (400) — body is empty;\n * `issue_not_found` (404) — no issue with this number in this app.\n * @example\n * await admin.issues.comment('42', 'Fixed in the latest release.');\n */\nexport function comment(ctx: AdminContext, number: string, body: string) {\n return call<IssuesCommentResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}/comments`,\n { body, authorKind: 'agent', ...authorship(ctx) },\n );\n}\n\n/**\n * Close an issue, optionally with a closing comment.\n *\n * Records a `closed` timeline event on the thread, preceded by the comment\n * when one is given — so answering and resolving is one call, which is what\n * replying to an issue another app filed usually amounts to.\n *\n * @param number The issue number.\n * @param comment Optional prose posted before the close event.\n * @throws AdminApiError `issue_not_found` (404) — no issue with this number\n * in this app.\n * @example\n * await admin.issues.close('42', 'Already fixed in v3 — no change needed.');\n */\nexport function close(ctx: AdminContext, number: string, comment?: string) {\n const requestBody: Record<string, unknown> = {\n status: 'closed',\n authorKind: 'agent',\n ...authorship(ctx),\n };\n if (comment !== undefined) {\n requestBody.comment = comment;\n }\n return call<IssuesUpdateResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}/update`,\n requestBody,\n );\n}\n\n/**\n * Reopen a closed issue.\n *\n * Records a `reopened` timeline event on the thread.\n *\n * @param number The issue number.\n * @throws AdminApiError `issue_not_found` (404) — no issue with this number\n * in this app.\n * @example\n * await admin.issues.reopen('42');\n */\nexport function reopen(ctx: AdminContext, number: string) {\n return call<IssuesUpdateResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}/update`,\n { status: 'open', authorKind: 'agent', ...authorship(ctx) },\n );\n}\n\nexport interface IssuesEditParams {\n /** Replace the issue's title (non-empty). */\n title?: string;\n /** Replace the issue's body. */\n body?: string;\n /** Replace the issue's labels wholesale (not a merge). */\n labels?: string[];\n /** Change the status to `open` or `closed`. */\n status?: string;\n}\n\n/**\n * Edit an issue's title, body, labels, or status.\n *\n * Status transitions record a `closed` or `reopened` timeline event\n * automatically. At least one field must be provided.\n *\n * @param number The issue number.\n * @throws AdminApiError `missing_title` (400) — title was supplied but empty;\n * `invalid_labels` (400) — labels are not strings, or exceed the count /\n * length caps; `invalid_status` (400) — status is not `open` or `closed`;\n * `no_fields` (400) — no editable field was provided; `issue_not_found`\n * (404) — no issue with this number in this app.\n * @example\n * await admin.issues.edit('42', { status: 'closed' });\n */\nexport function edit(\n ctx: AdminContext,\n number: string,\n params: IssuesEditParams,\n) {\n const requestBody: Record<string, unknown> = {\n authorKind: 'agent',\n ...authorship(ctx),\n };\n if (params.title !== undefined) {\n requestBody.title = params.title;\n }\n if (params.body !== undefined) {\n requestBody.body = params.body;\n }\n if (params.labels !== undefined) {\n requestBody.labels = params.labels;\n }\n if (params.status !== undefined) {\n requestBody.status = params.status;\n }\n return call<IssuesUpdateResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}/update`,\n requestBody,\n );\n}\n\n/**\n * Delete an issue. The number is permanently retired (never reissued).\n *\n * @param number The issue number.\n * @throws AdminApiError `issue_not_found` (404) — no issue with this number\n * in this app.\n * @example\n * await admin.issues.del('42');\n */\nexport function del(ctx: AdminContext, number: string) {\n return call<IssuesDeleteResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}/delete`,\n );\n}\n","/**\n * Jewels operations: shadowing overview, pair ledger, approval queue, training.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/jewels.ts and the importable client both call these.\n *\n * Long-running ops (resolve --approve, dryrun, train, grade) hold the request\n * for a full agent/model run; they pass their own timeout bound to `call`.\n * The constant is exported so the CLI skin can pass the same value to\n * cliStream.rawToStdout for the `jewels export --file` passthrough.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\n\nimport type {\n JewelsDryrunResult,\n JewelsExportResult,\n JewelsGradeResult,\n JewelsOverviewResult,\n JewelsPairResult,\n JewelsPairsResult,\n JewelsQueueResult,\n JewelsResolveResult,\n JewelsRunResult,\n JewelsRunsResult,\n JewelsTimeseriesResult,\n JewelsTrainResult,\n} from '../types/jewels.js';\n\n/**\n * Jewel runs are full agent loops: resolve --approve applies the method as\n * the reviewer, and dryrun executes the live jewel end to end — both can\n * legitimately take minutes, so they get their own request bound.\n * @internal Consumed by the CLI skin; not part of the documented surface.\n */\nexport const JEWEL_RUN_TIMEOUT_MS = 600_000;\n\nexport interface WindowParams {\n /** ISO date string for the start of the query window (default: 30 days before `end`). */\n start?: string;\n /** ISO date string for the end of the query window (default: now). */\n end?: string;\n}\n\nexport interface JewelsPairsParams extends WindowParams {\n /** Filter to a specific method id. */\n methodId?: string;\n /** Filter by verdict: `agree`, `disagree`, `skip`, or `expired`. */\n verdict?: string;\n /** Filter by shadow mode: `shadow`, `arrival`, `auto`, or `approve`. */\n mode?: string;\n /** Page size (default 50). */\n limit?: number;\n /** Keyset cursor from a previous response's `nextCursor`. */\n cursor?: string;\n}\n\nexport interface JewelsQueueParams {\n /** Filter to a specific method id. */\n methodId?: string;\n /** Max items to return (default 50). */\n limit?: number;\n}\n\nexport interface JewelsTimeseriesParams extends WindowParams {\n /** Filter to a specific method id. */\n methodId?: string;\n /** Number of time buckets (default 24). */\n buckets?: number;\n}\n\nexport interface JewelsResolveParams {\n /** The queue item's id (from `queue` results). */\n itemId: string;\n /**\n * `approve` runs the method for real as the calling user (the reviewer),\n * grades the proposed-vs-final pair, and closes the item. `dismiss` closes\n * the item without acting — no method run, no pair recorded.\n */\n action: 'approve' | 'dismiss';\n /**\n * Override the proposed input before applying (approve only). When set the\n * resolution is recorded as `edited`; omit to apply the proposal as-is.\n */\n input?: Record<string, unknown>;\n}\n\nexport interface JewelsDryrunParams {\n /** The method id whose jewel should run against `subject`. */\n methodId: string;\n /** The triggering subject object to pass to the jewel. */\n subject: Record<string, unknown>;\n}\n\nexport interface JewelsExportParams extends WindowParams {\n /** The method id to export pairs for. */\n methodId: string;\n}\n\nexport interface JewelsTrainParams {\n /** The method id to train a fine-tuning run for. */\n methodId: string;\n}\n\nexport interface JewelsRunsParams {\n /** Filter to a specific method id. */\n methodId?: string;\n /** Max runs to return (default 20). */\n limit?: number;\n}\n\n/**\n * Per-method shadowing overview: autonomy, sample rate, pair counts by verdict,\n * agreement rate, human-invocation coverage, and queue depth.\n *\n * Time window defaults to the last 30 days when `start`/`end` are omitted.\n * Training summary (active run, last run, latest model) is always all-time\n * regardless of the window — it reflects current model state, not the pair\n * stats window.\n *\n * @example\n * const { methods, totals } = await admin.jewels.overview();\n * const shadowed = methods.filter((m) => m.hasJewel);\n */\nexport function overview(ctx: AdminContext, params: WindowParams = {}) {\n return call<JewelsOverviewResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/overview${qs(params)}`,\n );\n}\n\n/**\n * Verdict counts (agree / disagree / skip / expired) over time, bucketed.\n *\n * One bucket array per method; use `methodId` to narrow to a single series.\n * Time window defaults to the last 30 days.\n *\n * @example\n * const { methods } = await admin.jewels.timeseries({ methodId: 'triage-issue', buckets: 48 });\n */\nexport function timeseries(\n ctx: AdminContext,\n params: JewelsTimeseriesParams = {},\n) {\n return call<JewelsTimeseriesResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/timeseries${qs(params)}`,\n );\n}\n\n/**\n * Paginated list of slim pair rows (excludes the full JSONB pair payload).\n *\n * Use `pair(pairId)` to fetch the full record with hydrated traces.\n * Time window defaults to the last 30 days.\n *\n * @example\n * const { pairs, nextCursor } = await admin.jewels.pairs({ verdict: 'disagree' });\n */\nexport function pairs(ctx: AdminContext, params: JewelsPairsParams = {}) {\n return call<JewelsPairsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/pairs${qs(params)}`,\n );\n}\n\n/**\n * Full pair record: proposed vs actual output, reasoning, grade notes, and\n * hydrated model transcripts (propose + grade phases) when the jewel attached\n * traces. Objects that could not be fetched degrade to `{ id, phase, missing: true }`\n * rather than a 500.\n *\n * @param pairId The pair id (from `pairs` results or the overview).\n * @throws AdminApiError `pair_not_found` (404) — no pair with this id in this app.\n * @example\n * const { pair, traces } = await admin.jewels.pair('6f1e...');\n */\nexport function pair(ctx: AdminContext, pairId: string) {\n return call<JewelsPairResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/pairs/${seg(pairId)}`,\n );\n}\n\n/**\n * Pending approve-mode proposals awaiting review.\n *\n * Only items for methods with `autonomy: 'approve'` appear here. Use\n * `resolve` to approve or dismiss an item.\n *\n * @example\n * const { items } = await admin.jewels.queue({ methodId: 'triage-issue' });\n */\nexport function queue(ctx: AdminContext, params: JewelsQueueParams = {}) {\n return call<JewelsQueueResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/queue${qs(params)}`,\n );\n}\n\n/**\n * Approve or dismiss one approval-queue item.\n *\n * **Approve** applies the method as the calling user (the reviewer): the\n * proposal's input runs for real, the platform grades proposed-vs-final, and\n * the item closes. Pass `input` to apply an edited version (resolution\n * recorded as `edited`). **Dismiss** closes the item without acting — no\n * method run, no pair recorded.\n *\n * The request holds for a full jewel/method run — allow minutes (up to\n * `JEWEL_RUN_TIMEOUT_MS`).\n *\n * @example\n * const { resolution, output } = await admin.jewels.resolve({ itemId: '6f1e...', action: 'approve' });\n */\nexport function resolve(ctx: AdminContext, params: JewelsResolveParams) {\n const body: Record<string, unknown> = {\n itemId: params.itemId,\n action: params.action,\n };\n if (params.input !== undefined) {\n body.input = params.input;\n }\n return call<JewelsResolveResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/jewels/queue/resolve`,\n body,\n JEWEL_RUN_TIMEOUT_MS,\n );\n}\n\n/**\n * Run the live jewel against a subject without recording or committing\n * anything.\n *\n * Executes inside a disposable database mirror — guaranteed side-effect-free\n * on the app database. The prod twin of the dev `testJewel` tool (which runs\n * draft code against the dev DB); this one answers for the deployed release\n * against the real world. Allow minutes for the full jewel run.\n *\n * @throws AdminApiError `invalid_subject` (400) — `subject` is not an object;\n * `invalid_app_method` (400) — unknown method id; `no_jewel` (400) — the\n * method has no compiled jewel in the live release.\n * @example\n * const { record } = await admin.jewels.dryrun({ methodId: 'triage-issue', subject: { issueId: 'abc' } });\n */\nexport function dryrun(ctx: AdminContext, params: JewelsDryrunParams) {\n return call<JewelsDryrunResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/jewels/${seg(params.methodId)}/dryrun`,\n { subject: params.subject },\n JEWEL_RUN_TIMEOUT_MS,\n );\n}\n\n/**\n * Dataset report (no `--file`): per-file row counts, every exclusion bucket\n * named (skip, expired, ungraded, auto, traceless, traceMissing,\n * preferenceUnrenderable), and trace coverage.\n *\n * The streaming JSONL variant (`--file`) is handled entirely by the CLI skin\n * via `cliStream.rawToStdout` — it is not an op.\n *\n * @throws AdminApiError `missing_method_id` (400) — `methodId` is required;\n * `invalid_file` (400) — `file` is not one of the allowed dataset file types.\n * @example\n * const { summary } = await admin.jewels.exportSummary({ methodId: 'triage-issue' });\n */\nexport function exportSummary(ctx: AdminContext, params: JewelsExportParams) {\n return call<JewelsExportResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/export${qs(params)}`,\n undefined,\n JEWEL_RUN_TIMEOUT_MS,\n );\n}\n\n/**\n * Kick off a LoRA fine-tuning run on the method's graded pairs.\n *\n * Returns **immediately** with a run id and dataset report (per-file row\n * counts, exclusion buckets); the GPU trainer runs asynchronously. Poll\n * with `getRun(run.id)` for live progress — the run's `log` carries a\n * narrated status timeline and loss-curve points. One run per method at\n * a time.\n *\n * The tuning dial comes from the method's manifest in the live release.\n * The report's agreement is scored against the held-out ledger split —\n * real decisions the model never saw.\n *\n * @throws AdminApiError `missing_method_id` (400) — `methodId` is required;\n * `invalid_app_method` (400) — unknown method id; `no_jewel` (400) — the\n * method has no compiled jewel in the live release.\n * @example\n * const { run, summary } = await admin.jewels.train({ methodId: 'triage-issue' });\n * // poll for completion:\n * const { run: status } = await admin.jewels.getRun(run.id);\n */\nexport function train(ctx: AdminContext, params: JewelsTrainParams) {\n return call<JewelsTrainResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/jewels/train`,\n { methodId: params.methodId },\n JEWEL_RUN_TIMEOUT_MS,\n );\n}\n\n/**\n * List training runs newest-first.\n *\n * The `log` field is serialized as `[]` in list responses; fetch a single\n * run with `getRun` to read the full event log.\n *\n * @example\n * const { runs } = await admin.jewels.runs({ methodId: 'triage-issue' });\n */\nexport function runs(ctx: AdminContext, params: JewelsRunsParams = {}) {\n return call<JewelsRunsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/training-runs${qs(params)}`,\n );\n}\n\n/**\n * Get one training run with its full event log and report.\n *\n * The run's `log` is an append-only array of `status` (narration) and `loss`\n * (training curve) entries — the primary polling target for `train --wait`.\n * Status `complete` or `failed` is the terminal signal.\n *\n * @param runId The run id returned by `train` or `runs`.\n * @throws AdminApiError `run_not_found` (404) — no run with this id in this app.\n * @example\n * const { run } = await admin.jewels.getRun(runId);\n * if (run.status === 'complete') console.log(run.report?.grading);\n */\nexport function getRun(ctx: AdminContext, runId: string) {\n return call<JewelsRunResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/jewels/training-runs/${seg(runId)}`,\n );\n}\n\n/**\n * Re-grade a completed run's held-out predictions with the jewel's own grade\n * function (the same grader as the pairs dashboard).\n *\n * Writes `report.grading`. Runs automatically on completion — use this as\n * the manual retry or backfill for runs that predate the grading feature or\n * whose fire-and-forget trigger was lost. Idempotent.\n *\n * @param runId The run id to grade.\n * @throws AdminApiError `run_not_found` (404) — no run with this id in this app.\n * @example\n * const { grading } = await admin.jewels.grade(runId);\n * console.log(`agreement: ${grading.agreement}`);\n */\nexport function grade(ctx: AdminContext, runId: string) {\n return call<JewelsGradeResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/jewels/training-runs/${seg(runId)}/grade`,\n undefined,\n JEWEL_RUN_TIMEOUT_MS,\n );\n}\n","/**\n * Methods operations: list (via dashboard) and invoke.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/methods.ts owns streaming (--stream → cliStream.streamToStdout)\n * and user-facing error messages.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, seg } from '../http.js';\nimport type {\n DashboardResult,\n DashboardReleaseMethod,\n} from '../types/releases.js';\nimport type { MethodsInvokeResult } from '../types/methods.js';\n\n/**\n * How long an invoke waits for the method's answer: as long as the API's load\n * balancer holds an idle connection (600 s), since a method can run for many\n * minutes and a request can't outwait that. A method still running past it\n * carries on; `requests list --method <id>` shows how it ended.\n * @internal Consumed by the CLI skin; not part of the documented surface.\n */\nexport const METHOD_RUN_TIMEOUT_MS = 600_000;\n\nexport interface MethodsInvokeParams {\n /** The method's compiled id (e.g. `mth_abc123`), as shown by `methods.list`. */\n methodId: string;\n /** Input payload forwarded to the method as its first argument. */\n input: Record<string, unknown>;\n /** Present when --roles or --user-id is set; routes through /invoke-as. */\n impersonate?: { roles?: string[]; userId?: string };\n}\n\n/**\n * List methods available on the live release.\n *\n * Fetches the dashboard endpoint and unwraps `liveRelease.methods`. Throws a\n * plain `Error` (not AdminApiError) when the app has no live release —\n * message: `\"No live release — publish first.\"`.\n *\n * @example\n * const methods = await admin.methods.list();\n * const target = methods.find((m) => m.id === 'mth_abc123');\n */\nexport async function list(\n ctx: AdminContext,\n): Promise<DashboardReleaseMethod[]> {\n const dashboard = await call<DashboardResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/dashboard`,\n );\n const release = dashboard.liveRelease;\n if (!release) {\n throw new Error('No live release — publish first.');\n }\n return release.methods ?? [];\n}\n\n/**\n * Invoke a method and return its output (non-streaming).\n *\n * Routes to `/invoke-as` when `impersonate` is set (either `roles` or\n * `userId` provided), allowing role-gated methods to be tested without\n * spec edits. The streaming path in the CLI skin calls\n * `cliStream.streamToStdout` with the same path/body construction.\n *\n * @throws AdminApiError `missing_impersonation` (400) — `impersonate` object\n * is malformed; `invalid_impersonation` (400) — `impersonate.userId` or\n * `impersonate.roles` has a bad type, or neither field is populated.\n * @example\n * const { output } = await admin.methods.invoke({\n * methodId: 'mth_abc123',\n * input: { query: 'hello' },\n * });\n */\nexport function invoke(ctx: AdminContext, params: MethodsInvokeParams) {\n const { methodId, input, impersonate } = params;\n const useImpersonate =\n impersonate !== undefined &&\n (impersonate.roles !== undefined || impersonate.userId !== undefined);\n const apiPath = useImpersonate\n ? `/_internal/v2/apps/${ctx.appId}/methods/${seg(methodId)}/invoke-as`\n : `/_internal/v2/apps/${ctx.appId}/methods/${seg(methodId)}/invoke`;\n const body: Record<string, unknown> = useImpersonate\n ? { input, impersonate }\n : { input };\n return call<MethodsInvokeResult>(\n ctx,\n 'POST',\n apiPath,\n body,\n METHOD_RUN_TIMEOUT_MS,\n );\n}\n","/**\n * Prerender operations: snapshot listing, stored-HTML view, cache invalidation.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/prerender.ts owns the `prerender get` crawler fetch (a public-URL\n * bot-UA fetch that is NOT an authed API call).\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs } from '../http.js';\n\nimport type {\n PrerenderInvalidateResult,\n PrerenderPagesResult,\n PrerenderViewResult,\n} from '../types/prerender.js';\n\nexport interface PrerenderPagesParams {\n /** Opaque cursor from a previous `pages` response; omit to start from the first page. */\n cursor?: string;\n}\n\nexport interface PrerenderViewParams {\n /** App path to look up (e.g. `/u/abc123`). Must be non-empty. */\n path: string;\n}\n\nexport interface PrerenderInvalidateParams {\n /**\n * Paths to purge. Omit (or pass undefined) to purge every snapshot\n * (the `--all` flag). An explicit empty array is the same as --all.\n */\n paths?: string[];\n}\n\n/**\n * List stored prerendered snapshots for the live release.\n *\n * Paginated — pass `nextCursor` from the previous response as `cursor` on\n * the next call. Returns `{ releaseId: null, pages: [] }` (not an error)\n * when the app has no live release.\n *\n * @example\n * const { pages } = await admin.prerender.pages();\n * console.log(`${pages.length} snapshots cached`);\n */\nexport function pages(ctx: AdminContext, params: PrerenderPagesParams = {}) {\n return call<PrerenderPagesResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/prerender/pages${qs(params)}`,\n );\n}\n\n/**\n * Retrieve the stored snapshot HTML for a single path.\n *\n * Returns JSON (not text/html) so the snapshot cannot execute in the API\n * origin; render the `html` field in a sandboxed iframe if displaying it.\n *\n * @throws AdminApiError `snapshot_not_found` (404) — no snapshot exists for\n * that path (the path is cold; trigger a render via `prerender get`);\n * `missing_path` (400) — `path` is empty.\n * @example\n * const { html } = await admin.prerender.view({ path: '/u/abc123' });\n */\nexport function view(ctx: AdminContext, params: PrerenderViewParams) {\n return call<PrerenderViewResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/prerender/pages/view${qs({ path: params.path })}`,\n );\n}\n\n/**\n * Purge one or more prerendered snapshots for the live release.\n *\n * Omit `paths` (or pass `undefined`) to purge every snapshot for the app.\n * An empty array behaves the same as omitting. The next crawler visit to any\n * invalidated path will trigger a fresh render.\n *\n * @example\n * // Purge a specific path:\n * await admin.prerender.invalidate({ paths: ['/u/abc123'] });\n * // Purge all snapshots:\n * await admin.prerender.invalidate();\n */\nexport function invalidate(\n ctx: AdminContext,\n params: PrerenderInvalidateParams = {},\n) {\n const body: Record<string, unknown> = {};\n if (params.paths !== undefined && params.paths.length > 0) {\n body.paths = params.paths;\n }\n return call<PrerenderInvalidateResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/prerender/invalidate`,\n body,\n );\n}\n","/**\n * Browser-QA replay recordings: list what the QA agent recorded, and render a\n * replay to an mp4.\n *\n * `ls` is a grouped view over `files.ls` — a replay chunk is an ordinary\n * private file in the app's `qa-recordings` store and needs no endpoint of its\n * own.\n *\n * `export` is the one operation in this SDK that does NOT go through the\n * management API. Rendering a replay means playing it in a real browser and\n * encoding the frames, and the only machine set up to do that is the dev box\n * the recording was made on: it already has the headless Chrome, the rrweb\n * replayer and ffmpeg. So this talks to the sandbox's local sidecar, and says\n * so plainly when there isn't one. (CLI-only paths are established here —\n * `methods invoke --stream`, `jewels export --file` — but this is the first\n * that needs local compute rather than local disk.)\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { SIDECAR_URL } from '../config.js';\nimport * as files from './files.js';\nimport type {\n QaRecordingRun,\n QaRecordingSession,\n QaRecordingsExportResult,\n QaRecordingsLsResult,\n} from '../types/qaRecordings.js';\n\n/** The app store QA replay chunks are written to (private). */\nexport const RECORDING_STORE = 'qa-recordings';\n\nexport interface QaRecordingsLsParams {\n /** Only this session. Omitted → every session in the store. */\n sessionId?: string;\n cursor?: string;\n /** Chunk objects to scan, not sessions returned. */\n limit?: number;\n}\n\n/**\n * Recording sessions in this app, grouped from the chunk keys.\n *\n * @example\n * const { sessions } = await admin.qaRecordings.ls({});\n * // → [{ sessionId, chunks, bytes, runs: [{ runId, keys }] }]\n */\nexport async function ls(\n ctx: AdminContext,\n params: QaRecordingsLsParams = {},\n): Promise<QaRecordingsLsResult> {\n const page = await files.ls(ctx, {\n store: RECORDING_STORE,\n access: 'private',\n ...(params.sessionId ? { prefix: `${params.sessionId}/` } : {}),\n ...(params.cursor ? { cursor: params.cursor } : {}),\n ...(params.limit ? { limit: params.limit } : {}),\n });\n\n const sessions = new Map<string, QaRecordingSession>();\n for (const entry of page.files) {\n // `{sessionId}/{runId}/{seq}.json`. Anything else is not a chunk — skip it\n // rather than inventing a session for it.\n const parts = entry.key.split('/');\n if (parts.length !== 3) {\n continue;\n }\n const [sessionId, runId] = parts;\n let session = sessions.get(sessionId);\n if (!session) {\n session = { sessionId, chunks: 0, bytes: 0, runs: [] };\n sessions.set(sessionId, session);\n }\n let run = session.runs.find((r: QaRecordingRun) => r.runId === runId);\n if (!run) {\n run = { runId, chunks: 0, bytes: 0, keys: [] };\n session.runs.push(run);\n }\n const size = entry.size ?? 0;\n session.chunks += 1;\n session.bytes += size;\n run.chunks += 1;\n run.bytes += size;\n run.keys.push(entry.key);\n if (entry.updatedAt) {\n if (!session.startedAt || entry.updatedAt < session.startedAt) {\n session.startedAt = entry.updatedAt;\n }\n if (!session.endedAt || entry.updatedAt > session.endedAt) {\n session.endedAt = entry.updatedAt;\n }\n }\n }\n\n // Keys within a run sort by seq, and sessions by recency — the run somebody\n // just did is the one they are almost always asking about.\n for (const session of sessions.values()) {\n for (const run of session.runs) {\n run.keys.sort((a, b) => seqOf(a) - seqOf(b));\n }\n }\n return {\n store: RECORDING_STORE,\n sessions: [...sessions.values()].sort((a, b) =>\n (b.endedAt ?? '').localeCompare(a.endedAt ?? ''),\n ),\n ...(page.cursor ? { cursor: page.cursor } : {}),\n };\n}\n\nfunction seqOf(key: string): number {\n const n = Number(\n key\n .split('/')\n .pop()\n ?.replace(/\\.json$/, ''),\n );\n return Number.isFinite(n) ? n : 0;\n}\n\nexport interface QaRecordingsExportParams {\n /** The recording session to render (32 hex characters). */\n sessionId: string;\n /** Window of the session, as epoch milliseconds. Both required: a replay is\n * a slice of a continuous recording, not a file. */\n from: number;\n to: number;\n /** Where the mp4 is written. Defaults to `assets`, public. */\n store?: string;\n access?: 'public' | 'private';\n /** Milliseconds to wait for the render. */\n timeoutMs?: number;\n}\n\n// Above the sidecar's own 600s rung so the box's error surfaces rather than a\n// severed request (see the ladder in mindstudio-sandbox/src/lsp/sidecar.ts).\nconst DEFAULT_EXPORT_TIMEOUT_MS = 660_000;\n\n/**\n * Render a window of a recording session to an mp4 on the dev box.\n *\n * Blocks for the whole render — the clip plays in real time, then encodes and\n * uploads — and answers with where the video landed. Runs only on a Remy dev\n * box, since that is where the browser and ffmpeg are.\n *\n * @example\n * const { url } = await admin.qaRecordings.exportVideo({\n * sessionId, from: 1758000000000, to: 1758000042000,\n * });\n */\nexport async function exportVideo(\n _ctx: AdminContext,\n params: QaRecordingsExportParams,\n): Promise<QaRecordingsExportResult> {\n const body = {\n recordingSessionId: params.sessionId,\n startTs: params.from,\n endTs: params.to,\n ...(params.store ? { store: params.store } : {}),\n ...(params.access ? { access: params.access } : {}),\n };\n\n let res: Response;\n try {\n res = await fetch(`${SIDECAR_URL}/export-recording`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(\n params.timeoutMs ?? DEFAULT_EXPORT_TIMEOUT_MS,\n ),\n });\n } catch (err) {\n // Nothing listening is the common case and has a specific cause worth\n // naming, rather than surfacing ECONNREFUSED at the user. Not an\n // AdminApiError: this never reached an API.\n throw new Error(\n `Could not reach the sandbox at ${SIDECAR_URL} ` +\n `(${err instanceof Error ? err.message : String(err)}). ` +\n 'Rendering a replay needs the dev box that recorded it — this ' +\n 'command only works inside a Remy sandbox.',\n );\n }\n\n const payload = (await res.json().catch(() => ({}))) as Record<\n string,\n unknown\n >;\n if (!res.ok) {\n throw new Error(\n typeof payload.error === 'string'\n ? payload.error\n : `The sandbox refused the export (HTTP ${res.status}).`,\n );\n }\n const status = payload.export as QaRecordingsExportResult | undefined;\n if (!status) {\n throw new Error(\n 'The sandbox accepted the export but reported no result. Check the ' +\n \"box's tunnel logs.\",\n );\n }\n // A render that ran and failed is a RESULT, not an exception — it carries a\n // reason and an error code the caller may want to branch on (FFMPEG_\n // UNAVAILABLE, CANCELLED). The CLI skin turns a non-completed status into a\n // non-zero exit; an importing caller inspects `status`.\n return status;\n}\n","/**\n * Request log + method metrics operations.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/requests.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n RequestsListResult,\n RequestsGetResult,\n RequestsStatsSummaryResult,\n RequestsStatsMethodResult,\n} from '../types/requests.js';\n\nexport interface RequestsListParams {\n /** Filter to a single method id (e.g. `mth_abc123`). */\n methodId?: string;\n /** `'success'` or `'error'` — omit to return all statuses. */\n status?: string;\n /** Maximum rows to return (default 50). */\n limit?: number;\n /** Row offset for pagination (default 0). */\n offset?: number;\n /** Keyset cursor from a previous page's `nextCursor`. */\n cursor?: string;\n}\n\nexport interface MetricsWindowParams {\n /** Window start as an ISO 8601 date string (inclusive). */\n start?: string;\n /** Window end as an ISO 8601 date string (inclusive). */\n end?: string;\n}\n\n/**\n * Recent request log entries, optionally filtered by method or status.\n *\n * Results are cursor-paginated — check `nextCursor` to page forward. Default\n * `limit` is 50 and `offset` is 0. A run's `id` is also its request-log id,\n * so `requests.get(id)` drills into the full payload for any interface\n * (cron, api, agent, …).\n *\n * @example\n * const { requests } = await admin.requests.list({ status: 'error', limit: 10 });\n */\nexport function list(ctx: AdminContext, params: RequestsListParams = {}) {\n return call<RequestsListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/requests${qs(params)}`,\n );\n}\n\n/**\n * Full request log entry — input, output, stdout, error, and interface context.\n *\n * @param requestId The request id (e.g. from `list`, or the `requestId`\n * returned by `cron.run`).\n * @throws AdminApiError `not_found` (404) — the request id does not exist or\n * belongs to a different app.\n * @example\n * const entry = await admin.requests.get('req_abc123');\n */\nexport function get(ctx: AdminContext, requestId: string) {\n return call<RequestsGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/requests/${seg(requestId)}`,\n );\n}\n\n/**\n * Aggregated metrics for the whole app over a time window.\n *\n * Returns per-bucket totals, per-method breakdowns with sparklines,\n * per-error-type counts, and interface distribution. When `start`/`end` are\n * omitted the server applies its own default window.\n *\n * @example\n * const { totals, byMethod } = await admin.requests.statsSummary();\n */\nexport function statsSummary(\n ctx: AdminContext,\n params: MetricsWindowParams = {},\n) {\n return call<RequestsStatsSummaryResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/metrics/summary${qs(params)}`,\n );\n}\n\n/**\n * Per-method time-series metrics over a time window.\n *\n * Returns per-bucket counts (including `successCount`, which is absent from\n * the app-summary buckets), overall totals, and an error-type breakdown.\n * When `start`/`end` are omitted the server applies its own default window.\n *\n * @param methodId The method id to scope the query (e.g. `mth_abc123`).\n * @example\n * const { buckets, totals } = await admin.requests.statsForMethod('mth_abc123');\n */\nexport function statsForMethod(\n ctx: AdminContext,\n methodId: string,\n params: MetricsWindowParams = {},\n) {\n return call<RequestsStatsMethodResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/metrics/methods/${seg(methodId)}${qs(params)}`,\n );\n}\n","/**\n * App secrets operations: list, read, write, and delete encrypted key/value pairs.\n *\n * `SecretsSetParams` allows `null` values to explicitly clear an environment's\n * stored value (mapped from the CLI's `--dev-clear` / `--prod-clear` flags).\n * The key presence check (at least one of devValue/prodValue) stays in the skin.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, seg } from '../http.js';\nimport type {\n SecretsListResult,\n SecretsGetResult,\n SecretsSetResult,\n SecretsDeleteResult,\n} from '../types/secrets.js';\n\n/**\n * List all secret keys for the app (values are not returned — use `get` to\n * retrieve decrypted values for a specific key).\n *\n * @example\n * const { secrets } = await admin.secrets.list();\n * const withProd = secrets.filter((s) => s.hasProdValue);\n */\nexport function list(ctx: AdminContext) {\n return call<SecretsListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/secrets`,\n );\n}\n\n/**\n * Get the decrypted dev and prod values for a secret key.\n *\n * This call is audited as a `secret.reveal` event on the workspace.\n *\n * @throws AdminApiError `secret_not_found` (404).\n * @example\n * const { devValue, prodValue } = await admin.secrets.get('STRIPE_SECRET_KEY');\n */\nexport function get(ctx: AdminContext, key: string) {\n return call<SecretsGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/secrets/${seg(key)}`,\n );\n}\n\nexport interface SecretsSetParams {\n /**\n * Value for the dev environment; `null` clears the stored dev value;\n * omitting the field leaves the dev value unchanged.\n */\n devValue?: string | null;\n /**\n * Value for the prod environment; `null` clears the stored prod value;\n * omitting the field leaves the prod value unchanged.\n */\n prodValue?: string | null;\n}\n\n/**\n * Create or update a secret's value for dev and/or prod (merge semantics —\n * environments you omit are not changed).\n *\n * Active sandboxes are invalidated so they reprovision with the updated values.\n * Key must match `[A-Z][A-Z0-9_]{0,99}` (validated server-side).\n *\n * @throws AdminApiError `invalid_key` (400) — the key does not match\n * `[A-Z][A-Z0-9_]{0,99}`; `missing_value` (400) — neither devValue nor\n * prodValue was provided.\n * @example\n * await admin.secrets.set('STRIPE_SECRET_KEY', { devValue: 'sk_test_…', prodValue: 'sk_live_…' });\n * // Clear just the dev value:\n * await admin.secrets.set('STRIPE_SECRET_KEY', { devValue: null });\n */\nexport function set(ctx: AdminContext, key: string, params: SecretsSetParams) {\n const body: Record<string, unknown> = {};\n if ('devValue' in params) {\n body.devValue = params.devValue;\n }\n if ('prodValue' in params) {\n body.prodValue = params.prodValue;\n }\n return call<SecretsSetResult>(\n ctx,\n 'PUT',\n `/_internal/v2/apps/${ctx.appId}/secrets/${seg(key)}`,\n body,\n );\n}\n\n/**\n * Delete a secret entirely (removes both dev and prod values).\n *\n * Active sandboxes are invalidated. Silently succeeds if the key does not\n * exist.\n *\n * @example\n * await admin.secrets.del('OLD_KEY');\n */\nexport function del(ctx: AdminContext, key: string) {\n return call<SecretsDeleteResult>(\n ctx,\n 'DELETE',\n `/_internal/v2/apps/${ctx.appId}/secrets/${seg(key)}`,\n );\n}\n","/**\n * App settings operations: get and update the app's v2_settings jsonb.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/settings.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call } from '../http.js';\nimport type { SettingsResult, V2AppSettings } from '../types/settings.js';\n\n/**\n * Get all V2AppSettings for this app.\n *\n * Returns the current state of every dashboard-controlled toggle: signup\n * allowlist, test accounts, frame-ancestors, disposable-email blocking,\n * telemetry capture, and more. See `V2AppSettings` in `types/settings.ts`\n * for the full field set and per-field semantics.\n *\n * @example\n * const settings = await admin.settings.getSettings();\n * console.log(settings.blockDisposableEmails);\n */\nexport function getSettings(ctx: AdminContext): Promise<V2AppSettings> {\n return call<SettingsResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/settings/v2`,\n ).then((res) => res.settings ?? {});\n}\n\n// `partial` stays loose on purpose: `settings set` forwards an arbitrary\n// user-supplied key for the route to validate, so a V2AppSettings-typed body\n// would reject exactly the escape hatch the command exists to provide.\n/**\n * Apply a partial update to the app's V2AppSettings.\n *\n * The server validates and normalizes security-shaped values before writing:\n * signup-allowlist entries must be `*@domain.com` or `user@domain.com`; test\n * accounts require a valid email or E.164 identifier and a 6-digit code (max\n * 5 entries); frame-ancestor entries must be exact `https://` origins (max\n * 25). Unknown keys in `partial` are silently dropped. Returns the full\n * settings after the update.\n *\n * `partial` is deliberately untyped: the CLI escape-hatch `settings set`\n * forwards arbitrary keys for the route to validate; a strict `V2AppSettings`\n * body would reject that use.\n *\n * @throws AdminApiError `invalid_signup_allowlist` (400) — malformed entry or\n * non-array value; `invalid_test_accounts` (400) — invalid identifier/code,\n * duplicate identifier, or over the 5-entry cap;\n * `invalid_frame_ancestors` (400) — not a valid https origin or over the\n * 25-entry cap.\n * @example\n * const updated = await admin.settings.updateSettings({ blockDisposableEmails: false });\n */\nexport function updateSettings(\n ctx: AdminContext,\n partial: Record<string, unknown>,\n): Promise<V2AppSettings> {\n return call<SettingsResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/v2`,\n partial,\n ).then((res) => res.settings ?? {});\n}\n","/**\n * App users operations: list, role management, API key lifecycle.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling — the CLI skin in\n * commands/users.ts and the importable client both call these.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n UsersListResult,\n UsersSetRoleResult,\n UsersCreateApiKeyResult,\n UsersRevokeApiKeyResult,\n} from '../types/users.js';\n\nexport interface UsersListParams {\n /** Max users to return per page (server default 50, clamped to 200). */\n limit?: number;\n /** Zero-based page offset. */\n offset?: number;\n}\n\n/**\n * All app-managed users with their roles and masked API-key status.\n *\n * @example\n * const { users } = await admin.users.list({ limit: 20 });\n * const admins = users.filter((u) => u.roles.includes('admin'));\n */\nexport function list(ctx: AdminContext, params: UsersListParams = {}) {\n return call<UsersListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/users${qs(params)}`,\n );\n}\n\n/**\n * Replace a user's role set with a single role.\n *\n * Sends `roles: [role]` — the array replaces the user's entire prior role\n * list. The updated user record is returned.\n *\n * @throws AdminApiError `user_not_found` (404) — the user does not belong to\n * this app; `invalid_roles` (400) — the roles field was malformed.\n * @example\n * const { user } = await admin.users.setRole('usr_abc123', 'admin');\n */\nexport function setRole(ctx: AdminContext, userId: string, role: string) {\n return call<UsersSetRoleResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/users/${seg(userId)}/roles`,\n { roles: [role] },\n );\n}\n\n/**\n * Generate an API key for a user; the full plaintext `key` is returned exactly\n * once — only the masked form is stored after this call.\n *\n * Requires the app's live release to have the `api-key` auth method enabled.\n *\n * @throws AdminApiError `user_not_found` (404) — the user does not belong to\n * this app; `auth_method_not_enabled` (400) — the `api-key` auth method is\n * not enabled on the app's live release.\n * @example\n * const { key } = await admin.users.createApiKey('usr_abc123');\n * // Store `key` immediately — it cannot be retrieved again.\n */\nexport function createApiKey(ctx: AdminContext, userId: string) {\n return call<UsersCreateApiKeyResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/users/${seg(userId)}/api-key`,\n );\n}\n\n/**\n * Revoke a user's API key; takes effect immediately — in-flight requests using\n * the key will fail.\n *\n * @throws AdminApiError `user_not_found` (404) — the user does not belong to\n * this app.\n * @example\n * await admin.users.revokeApiKey('usr_abc123');\n */\nexport function revokeApiKey(ctx: AdminContext, userId: string) {\n return call<UsersRevokeApiKeyResult>(\n ctx,\n 'DELETE',\n `/_internal/v2/apps/${ctx.appId}/users/${seg(userId)}/api-key`,\n );\n}\n","/**\n * Voice operations: phone numbers, sessions, and policy settings.\n *\n * `findNumberId` resolves a user-supplied E.164 string to a row id (list →\n * normalize → match). It throws a plain Error with the exact historical\n * message if not found — entry-point catch prints it identically to `fatal()`.\n *\n * Ops are pure: (ctx, params) → typed result, throwing AdminApiError /\n * AdminTimeoutError. No printing, no process coupling.\n */\n\nimport type { AdminContext } from '../ctx.js';\nimport { call, qs, seg } from '../http.js';\nimport type {\n VoiceNumbersListResult,\n VoiceNumbersSearchResult,\n VoiceNumbersBuyResult,\n VoiceNumbersReleaseResult,\n VoiceNumbersSetNameResult,\n VoiceSessionsListResult,\n VoiceSessionGetResult,\n VoiceSettingsGetResult,\n VoiceSettingsSetResult,\n} from '../types/voice.js';\n\n// ---------------------------------------------------------------------------\n// Phone numbers\n// ---------------------------------------------------------------------------\n\n/**\n * Canonicalize a user-typed phone number to E.164 before matching: strip\n * formatting, accept bare 10/11-digit US numbers.\n */\nfunction normalizeE164(input: string): string {\n const stripped = input.replace(/[\\s().-]/g, '');\n if (/^\\d{10}$/.test(stripped)) {\n return `+1${stripped}`;\n }\n if (/^1\\d{10}$/.test(stripped)) {\n return `+${stripped}`;\n }\n return stripped;\n}\n\n/**\n * All dedicated phone numbers attached to the app.\n *\n * Lazily reconciles any pending orders so callers can poll this until a\n * `pending` number converges to `active` or `failed`.\n *\n * @example\n * const { numbers } = await admin.voice.numbersList();\n * const active = numbers.filter((n) => n.status === 'active');\n */\nexport function numbersList(ctx: AdminContext) {\n return call<VoiceNumbersListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/settings/voice-phone-numbers`,\n );\n}\n\nexport interface NumbersSearchParams {\n /** US 3-digit area code to filter by. */\n areaCode?: string;\n /** City name to filter by. */\n locality?: string;\n /** State or region code (e.g. `CA`). */\n administrativeArea?: string;\n /** Max results to return (server clamps to 50). */\n limit?: number;\n}\n\n/**\n * Search available US numbers by area code or locality.\n *\n * Results are Telnyx availability snapshots — they are not reservations and\n * may be gone by the time `numbersBuy` is called.\n *\n * @throws AdminApiError `missing_search_filter` (400) — neither areaCode nor\n * locality provided; `invalid_area_code` (400) — area code is not 3 digits;\n * `telnyx_not_configured` (422) — phone numbers are not available on this\n * platform host.\n * @example\n * const { results } = await admin.voice.numbersSearch({ areaCode: '310', limit: 5 });\n */\nexport function numbersSearch(ctx: AdminContext, params: NumbersSearchParams) {\n return call<VoiceNumbersSearchResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/voice-phone-numbers/search`,\n {\n areaCode: params.areaCode,\n locality: params.locality,\n administrativeArea: params.administrativeArea,\n limit: params.limit,\n },\n );\n}\n\nexport interface NumbersBuyParams {\n /** E.164 US number to purchase, from a prior `numbersSearch` result. */\n phoneNumber: string;\n /** City name label — display metadata only, echoed from the search result. */\n locality?: string;\n /** State/region label — display metadata only, echoed from the search result. */\n administrativeArea?: string;\n /** Carrier monthly cost string (e.g. `\"1.00000\"`) — display metadata only. */\n monthlyCost?: string;\n}\n\n/**\n * Buy and attach a dedicated phone number to the app ($1/month billed to the\n * workspace starting immediately — always confirm with the user before calling).\n *\n * The number is both the outbound caller-ID for `voice.call()` and the app's\n * inbound line. A `pending` status usually activates within seconds; poll\n * `numbersList` to confirm. One number per app in v1 — release before switching.\n *\n * @throws AdminApiError `invalid_phone_number` (400) — not a valid +1 E.164\n * US number; `number_already_assigned` (422) — this app already has a live\n * number; `number_unavailable` (422) — the number is no longer available;\n * `insufficient_credits/*` (402) — the workspace can't cover it;\n * `telnyx_not_configured` (422) — phone numbers unavailable on this host.\n * @example\n * const { number } = await admin.voice.numbersBuy({\n * phoneNumber: '+13105551234',\n * locality: 'Los Angeles',\n * administrativeArea: 'CA',\n * monthlyCost: '1.00000',\n * });\n */\nexport function numbersBuy(ctx: AdminContext, params: NumbersBuyParams) {\n return call<VoiceNumbersBuyResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/voice-phone-numbers`,\n {\n phoneNumber: params.phoneNumber,\n locality: params.locality,\n administrativeArea: params.administrativeArea,\n monthlyCost: params.monthlyCost,\n },\n );\n}\n\n/**\n * Resolve a phone-number row id from its E.164 value by listing and matching.\n * Throws with the exact historical message if not found.\n */\nasync function findNumberId(ctx: AdminContext, e164: string): Promise<string> {\n const normalized = normalizeE164(e164);\n const res = await numbersList(ctx);\n const entry = (res.numbers ?? []).find((n) => n.e164 === normalized);\n if (!entry) {\n throw new Error(`No phone number \"${e164}\" on this app`);\n }\n return entry.id;\n}\n\n/**\n * Release a dedicated phone number from the app (permanent).\n *\n * The monthly rental stops immediately (no refund for the current month),\n * the carrier quarantines the number for ~15 days, and both inbound calls\n * and outbound `voice.call()` stop working until a new number is attached.\n *\n * @param e164 The phone number in E.164 or bare 10-digit US format.\n * @throws Error `No phone number \"${e164}\" on this app` when not found;\n * AdminApiError `number_not_found` (404) if the resolved id has gone stale;\n * `order_in_progress` (422) — the purchase is still settling, try again in\n * a minute.\n * @example\n * await admin.voice.numbersRelease('+13105551234');\n */\nexport async function numbersRelease(ctx: AdminContext, e164: string) {\n const id = await findNumberId(ctx, e164);\n return call<VoiceNumbersReleaseResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/voice-phone-numbers/${seg(id)}/release`,\n );\n}\n\n/**\n * Set or clear the outbound caller-ID display name (CNAM) for a phone number.\n *\n * CNAM must be 1–15 letters, numbers, or spaces; carrier propagation takes\n * 12–72 hours and display is ultimately the receiving carrier's call. Pass an\n * empty string to remove the listing.\n *\n * @param e164 The phone number in E.164 or bare 10-digit US format.\n * @param displayName 1–15 character CNAM string, or `\"\"` to remove the listing.\n * @throws Error `No phone number \"${e164}\" on this app` when not found;\n * AdminApiError `number_not_found` (404) if the resolved id has gone stale;\n * `number_not_active` (422) — the number must be active before setting a\n * display name; `invalid_display_name` (400) — value is not 1–15 letters,\n * numbers, or spaces.\n * @example\n * await admin.voice.numbersSetName('+13105551234', 'Acme Corp');\n * // Clear the listing:\n * await admin.voice.numbersSetName('+13105551234', '');\n */\nexport async function numbersSetName(\n ctx: AdminContext,\n e164: string,\n displayName: string,\n) {\n const id = await findNumberId(ctx, e164);\n return call<VoiceNumbersSetNameResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/settings/voice-phone-numbers/${seg(id)}/display-name`,\n { displayName },\n );\n}\n\n// ---------------------------------------------------------------------------\n// Sessions\n// ---------------------------------------------------------------------------\n\nexport interface SessionsListParams {\n /** Max sessions per page (default 20, server clamps to 100). */\n limit?: number;\n /** Pagination cursor from a prior page's `nextCursor`. */\n cursor?: string;\n}\n\n/**\n * Call log for the app (web, phone-out, phone-in sessions), newest first.\n *\n * Returns cursored pages; pass `nextCursor` from one page as `cursor` for the\n * next. Transcripts are not included — fetch a session with `sessionsGet` for\n * the full transcript.\n *\n * @example\n * const { sessions, nextCursor } = await admin.voice.sessionsList({ limit: 20 });\n */\nexport function sessionsList(\n ctx: AdminContext,\n params: SessionsListParams = {},\n) {\n return call<VoiceSessionsListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/voice-sessions${qs(params)}`,\n );\n}\n\n/**\n * One voice session with full transcript and cost breakdown.\n *\n * `transcript` is the primary tool for debugging and iterating on a voice\n * persona. `cost` is `null` while the session is still active.\n *\n * @throws AdminApiError `session_not_found` (404).\n * @example\n * const session = await admin.voice.sessionsGet('4f6c…');\n * console.log(session.transcript);\n */\nexport function sessionsGet(ctx: AdminContext, sessionId: string) {\n return call<VoiceSessionGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/voice-sessions/${seg(sessionId)}`,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Settings\n// ---------------------------------------------------------------------------\n\n/**\n * Voice policy for the app: owner-set overrides, the effective (default-filled\n * and ceiling-clamped) values that apply at session mint, and the platform\n * ceilings.\n *\n * @example\n * const { settings, effective, ceilings } = await admin.voice.settingsGet();\n */\nexport function settingsGet(ctx: AdminContext) {\n return call<VoiceSettingsGetResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/voice-settings`,\n );\n}\n\nexport interface VoiceSettingsSetParams {\n /** Cap on simultaneous sessions across all visitors (platform ceiling applies). */\n maxConcurrentSessions?: number;\n /** Cap on simultaneous sessions per visitor. */\n maxConcurrentSessionsPerVisitor?: number;\n /** Max session duration in seconds before the session is terminated. */\n maxSessionDurationSecs?: number;\n}\n\n/**\n * Override one or more voice-policy settings for the app (merge semantics —\n * fields you omit keep their current values).\n *\n * @throws AdminApiError `invalid_voice_settings` (400) — a field value is not\n * a positive number.\n * @example\n * await admin.voice.settingsSet({ maxConcurrentSessions: 5, maxSessionDurationSecs: 600 });\n */\nexport function settingsSet(ctx: AdminContext, params: VoiceSettingsSetParams) {\n return call<VoiceSettingsSetResult>(\n ctx,\n 'PUT',\n `/_internal/v2/apps/${ctx.appId}/voice-settings`,\n {\n maxConcurrentSessions: params.maxConcurrentSessions,\n maxConcurrentSessionsPerVisitor: params.maxConcurrentSessionsPerVisitor,\n maxSessionDurationSecs: params.maxSessionDurationSecs,\n },\n );\n}\n","/**\n * The importable admin client: every CLI command as a typed method, bound to\n * one app. Namespaces mirror the CLI groups 1:1 — `remy-admin requests list`\n * is `admin.requests.list(...)` — so there is exactly one mental model.\n *\n * The client is a thin binding layer: each namespace is its ops module with\n * the AdminContext pre-applied. Ops throw AdminApiError / AdminTimeoutError;\n * nothing here prints, exits, or streams (the CLI-only streaming passthroughs\n * live in cliStream.ts and are deliberately not exposed).\n */\n\nimport {\n DEFAULT_BASE_URL,\n loadWorkspaceAppId,\n type AdminContext,\n} from './ctx.js';\n\nimport * as agent from './ops/agent.js';\nimport * as tasks from './ops/tasks.js';\nimport * as analytics from './ops/analytics.js';\nimport * as appEvents from './ops/events.js';\nimport * as crashes from './ops/crashes.js';\nimport * as cron from './ops/cron.js';\nimport * as data from './ops/data.js';\nimport * as dataSources from './ops/dataSources.js';\nimport * as dataSourceJobs from './ops/dataSourceJobs.js';\nimport * as dataSourceConnectors from './ops/dataSourceConnectors.js';\nimport * as dataSourceEvals from './ops/dataSourceEvals.js';\nimport * as dataSourceMappers from './ops/dataSourceMappers.js';\nimport * as db from './ops/db.js';\nimport * as diagnostics from './ops/diagnostics.js';\nimport * as domains from './ops/domains.js';\nimport * as email from './ops/email.js';\nimport * as files from './ops/files.js';\nimport * as infra from './ops/infra.js';\nimport * as issues from './ops/issues.js';\nimport * as jewels from './ops/jewels.js';\nimport * as methods from './ops/methods.js';\nimport * as prerender from './ops/prerender.js';\nimport * as qaRecordings from './ops/qaRecordings.js';\nimport * as releases from './ops/releases.js';\nimport * as requests from './ops/requests.js';\nimport * as secrets from './ops/secrets.js';\nimport * as settings from './ops/settings.js';\nimport * as users from './ops/users.js';\nimport * as voice from './ops/voice.js';\n\nexport interface AdminClientOptions {\n /** Org-scoped `sk_` API key. Falls back to MINDSTUDIO_API_KEY. */\n apiKey?: string;\n /**\n * The app to manage. Falls back to the workspace's mindstudio.json —\n * pass explicitly anywhere that file doesn't exist.\n */\n appId?: string;\n /** API origin. Falls back to MINDSTUDIO_BASE_URL, then the production default. */\n baseUrl?: string;\n}\n\n/** An ops module with the AdminContext pre-applied to every function. */\ntype BoundOps<T> = {\n [\n K in keyof T as T[K] extends (\n ctx: AdminContext,\n ...args: never[]\n ) => unknown\n ? K\n : never\n ]: T[K] extends (ctx: AdminContext, ...args: infer A) => infer R\n ? (...args: A) => R\n : never;\n};\n\nfunction bindOps<T extends object>(ops: T, ctx: AdminContext): BoundOps<T> {\n const bound: Record<string, unknown> = {};\n for (const [name, value] of Object.entries(ops)) {\n if (typeof value === 'function') {\n bound[name] = (...args: unknown[]) => value(ctx, ...args);\n }\n }\n return bound as BoundOps<T>;\n}\n\nfunction resolveOptions(options: AdminClientOptions): AdminContext {\n const apiKey = options.apiKey ?? process.env['MINDSTUDIO_API_KEY'] ?? '';\n if (!apiKey) {\n throw new Error(\n 'No API key: pass { apiKey } to createAdminClient or set MINDSTUDIO_API_KEY',\n );\n }\n return {\n apiKey,\n // loadWorkspaceAppId throws its own precise message if there's no\n // mindstudio.json to fall back to.\n appId: options.appId ?? loadWorkspaceAppId(),\n baseUrl:\n options.baseUrl ?? process.env['MINDSTUDIO_BASE_URL'] ?? DEFAULT_BASE_URL,\n };\n}\n\nfunction buildClient(ctx: AdminContext) {\n return {\n /** The resolved context this client is bound to. */\n context: ctx as Readonly<AdminContext>,\n /**\n * A sibling client for another app, sharing credentials.\n *\n * The app we came from becomes the origin, so a write through the returned\n * client records which app acted — the same rule the CLI's `--app` follows.\n * Chaining `forApp` twice keeps the FIRST app as the origin, since that is\n * the one whose workspace this code is running in.\n */\n forApp(appId: string) {\n return buildClient({\n ...ctx,\n appId,\n originAppId:\n appId === ctx.appId\n ? ctx.originAppId\n : (ctx.originAppId ?? ctx.appId),\n });\n },\n\n agent: bindOps(agent, ctx),\n tasks: bindOps(tasks, ctx),\n analytics: bindOps(analytics, ctx),\n events: bindOps(appEvents, ctx),\n crashes: bindOps(crashes, ctx),\n cron: bindOps(cron, ctx),\n data: bindOps(data, ctx),\n dataSources: bindOps(dataSources, ctx),\n dataSourceJobs: bindOps(dataSourceJobs, ctx),\n dataSourceConnectors: bindOps(dataSourceConnectors, ctx),\n dataSourceEvals: bindOps(dataSourceEvals, ctx),\n dataSourceMappers: bindOps(dataSourceMappers, ctx),\n db: bindOps(db, ctx),\n diagnostics: bindOps(diagnostics, ctx),\n domains: bindOps(domains, ctx),\n email: {\n ...bindOps(email, ctx),\n // Hand-bound: these are generic over the direction ('sending' |\n // 'inbound') and bindOps' mapped type would erase the generic,\n // collapsing every result to the cross-direction union.\n listDomains: <D extends email.DomainDirection>(direction: D) =>\n email.listDomains(ctx, direction),\n checkDomain: <D extends email.DomainDirection>(\n direction: D,\n domain: string,\n ) => email.checkDomain(ctx, direction, domain),\n addDomain: <D extends email.DomainDirection>(\n direction: D,\n domain: string,\n ) => email.addDomain(ctx, direction, domain),\n verifyDomain: <D extends email.DomainDirection>(\n direction: D,\n domain: string,\n ) => email.verifyDomain(ctx, direction, domain),\n removeDomain: <D extends email.DomainDirection>(\n direction: D,\n domain: string,\n ) => email.removeDomain(ctx, direction, domain),\n },\n files: bindOps(files, ctx),\n infra: bindOps(infra, ctx),\n issues: bindOps(issues, ctx),\n jewels: bindOps(jewels, ctx),\n methods: bindOps(methods, ctx),\n prerender: bindOps(prerender, ctx),\n qaRecordings: bindOps(qaRecordings, ctx),\n releases: bindOps(releases, ctx),\n requests: bindOps(requests, ctx),\n secrets: bindOps(secrets, ctx),\n settings: bindOps(settings, ctx),\n users: bindOps(users, ctx),\n voice: bindOps(voice, ctx),\n };\n}\n\nexport type AdminClient = ReturnType<typeof buildClient>;\n\n/**\n * Create a client bound to one app.\n *\n * ```ts\n * import { createAdminClient } from '@madewithremy/admin';\n * const admin = createAdminClient({ apiKey: 'sk_…', appId: 'app_…' });\n * const { releases } = await admin.releases.list({ limit: 5 });\n * ```\n */\nexport function createAdminClient(\n options: AdminClientOptions = {},\n): AdminClient {\n return buildClient(resolveOptions(options));\n}\n","/**\n * @madewithremy/admin — manage production Remy apps from code.\n *\n * Two ways in:\n * import admin from '@madewithremy/admin'; // lazy, env-configured\n * import { createAdminClient } from '@madewithremy/admin'; // explicit\n *\n * Every CLI command (`remy-admin <group> <sub>`) is a client method\n * (`admin.<group>.<sub>()`). Ops throw AdminApiError / AdminTimeoutError.\n */\n\nexport {\n createAdminClient,\n type AdminClient,\n type AdminClientOptions,\n} from './client.js';\nexport type { AdminContext } from './ctx.js';\nexport { AdminApiError, AdminTimeoutError } from './errors.js';\nexport * from './types/index.js';\n\nimport { createAdminClient, type AdminClient } from './client.js';\n\n// ---------------------------------------------------------------------------\n// Lazy default singleton\n// ---------------------------------------------------------------------------\n\n/**\n * Lazy default client — created on first property access from the environment\n * (MINDSTUDIO_API_KEY, MINDSTUDIO_BASE_URL, the workspace's mindstudio.json), so the\n * import itself is safe anywhere; resolution errors surface at first use.\n *\n * ```ts\n * import admin from '@madewithremy/admin';\n * const { jobs } = await admin.cron.list({});\n * ```\n */\nlet _default: AdminClient;\nexport const admin: AdminClient = new Proxy({} as AdminClient, {\n get(_, prop) {\n _default ??= createAdminClient();\n const value = Reflect.get(_default, prop, _default);\n return typeof value === 'function' ? value.bind(_default) : value;\n },\n});\n\nexport default admin;\n"],"mappings":"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","names":["path","status","search","get","list","list","get","list","list","list","start","start","count","view","entities","documents","tracked","start","list","query","source","pages","DEFAULT_WAIT_TIMEOUT_MS","get","list","DEFAULT_WAIT_TIMEOUT_MS","POLL_MS","base","approve","list","get","job","start","get","base","get","DEFAULT_WAIT_TIMEOUT_MS","run","DEFAULT_WAIT_TIMEOUT_MS","POLL_MS","base","list","source","start","run","set","base","query","query","get","list","list","get","summary","POLL_MS","start","live","get","get","batch","get","list","stats","list","get","stats","batch","path","createHash","createHash","path","DEFAULT_WAIT_TIMEOUT_MS","get","list","resume","DEFAULT_WAIT_TIMEOUT_MS","POLL_MS","base","list","get","query","search","resume","resource","start","create","get","list","list","get","create","comment","getRun","getRun","list","list","ls","ls","run","status","get","list","list","get","del","get","list","set","list","get","set","del","list","list"]}
|