@madewithremy/admin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -0
- package/dist/index.d.ts +5050 -0
- package/dist/index.js +1674 -0
- package/dist/index.js.map +1 -0
- package/dist/prod.js +5261 -0
- package/package.json +61 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ctx.ts","../src/config.ts","../src/parseJsonConfig.ts","../src/ops/analytics.ts","../src/errors.ts","../src/http.ts","../src/ops/crashes.ts","../src/ops/cron.ts","../src/ops/data.ts","../src/ops/dataSources.ts","../src/sleep.ts","../src/upload.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/issues.ts","../src/ops/jewels.ts","../src/ops/methods.ts","../src/ops/prerender.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 /** 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/**\n * Build a context from the environment — the CLI's configuration model, also\n * used by the lazy default client. `apiKey` presence is NOT checked here so\n * the CLI can keep its historical error ordering (routing and argument errors\n * report before \"MINDSTUDIO_API_KEY is not set\").\n */\nexport function resolveEnvContext(): AdminContext {\n return {\n apiKey: process.env['MINDSTUDIO_API_KEY'] ?? '',\n appId: loadWorkspaceAppId(),\n baseUrl: process.env['API_BASE_URL'] || DEFAULT_BASE_URL,\n };\n}\n","/**\n * Workspace location for CLI commands that touch local files (files put/get,\n * datasources add, releases wait's git HEAD sniff). API credentials and appId\n * resolution live in ctx.ts.\n */\n\nexport const WORKSPACE_DIR =\n process.env['WORKSPACE_DIR'] || '/home/vercel-sandbox/workspace';\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 * 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 * 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/** 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 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 * 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\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 * @example\n * const result = await admin.data.liftFromDev();\n * console.log(`Lifted ${result.databasesAffected.length} databases to live`);\n */\nexport function liftFromDev(ctx: AdminContext) {\n return call<DataLiftFromDevResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/manage/lift-dev-to-live`,\n { confirm: true },\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\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 * @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 { confirm: true, ...(params.truncate ? { mode: 'truncate' } : {}) },\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 { sleep } from '../sleep.js';\nimport { uploadDirect } from '../upload.js';\nimport type {\n DataSourcesConfigResult,\n DataSourcesConfigUpdateResult,\n DataSourcesDeleteResult,\n DataSourcesDocument,\n DataSourcesDocumentConfirmResult,\n DataSourcesDocumentDeleteResult,\n DataSourcesDocumentsResult,\n DataSourcesDocumentStatus,\n DataSourcesDropResult,\n DataSourcesIngestUpdate,\n DataSourcesListResult,\n DataSourcesPromoteResult,\n DataSourcesRetrievalUpdate,\n DataSourcesRevectorizeResult,\n DataSourcesSearchResult,\n DataSourcesUploadTokenResult,\n} from '../types/dataSources.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 * 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 document: DataSourcesDocument;\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, onProgress } = 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 },\n );\n\n if (token.alreadyCurrent) {\n onProgress?.(`${filename}: unchanged, skipped`);\n return { filename, skipped: true, document: token.document };\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 },\n );\n\n return {\n filename,\n skipped: false,\n queued: confirmed.queued,\n document: confirmed.document,\n };\n}\n\n// ─── waitForIngest ────────────────────────────────────────────────────────────\n\nexport interface WaitForIngestParams {\n slug: string;\n documentIds: string[];\n /** 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 start = Date.now();\n\n for (;;) {\n const { documents: docs } = await call<DataSourcesDocumentsResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/documents?slug=${encodeURIComponent(slug)}`,\n );\n const tracked = (docs ?? []).filter((d) => wanted.has(d.id));\n const pending = tracked.filter((d) => d.status === 'processing');\n const failed = tracked.filter((d) => d.status === 'error');\n\n if (pending.length === 0) {\n return {\n status: failed.length ? 'error' : 'done',\n documents: tracked.map(summarize),\n };\n }\n\n if (Date.now() - start > timeoutMs) {\n return {\n status: 'timeout',\n documents: tracked.map(summarize),\n error: `Timed out after ${Math.round(timeoutMs / 1000)}s with ${pending.length} document(s) still processing`,\n };\n }\n\n onProgress?.(\n `ingesting… ${tracked.length - pending.length}/${tracked.length} done (${Math.round(\n (Date.now() - start) / 1000,\n )}s)`,\n );\n await sleep(POLL_MS);\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}\n\n/**\n * Fetch per-document ingest state for one pipeline.\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.\n *\n * @example\n * const { documents } = await admin.dataSources.documents({ slug: 'policies' });\n */\nexport function documents(ctx: AdminContext, params: DocumentsParams) {\n return call<DataSourcesDocumentsResult>(\n ctx,\n 'GET',\n `${base(ctx.appId)}/documents${qs({ slug: params.slug, candidate: params.candidate || undefined })}`,\n );\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\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\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 * @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 } = params;\n return call<DataSourcesConfigUpdateResult>(\n ctx,\n 'POST',\n `${base(ctx.appId)}/config`,\n {\n slug,\n ...(ingest ? { ingest } : {}),\n ...(retrieval ? { retrieval } : {}),\n },\n );\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// ─── 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 * 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 * 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 * 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 * SQL errors (syntax, constraint violations, etc.) surface as HTTP 400\n * responses with a `code` field rather than throwing — check `error.code`\n * in the response when the call fails.\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 * `query_error` (400) — the SQL failed at the database layer;\n * `unique_constraint_violated` (400) — a UNIQUE constraint was violated.\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 V2BuildLogEntry,\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 * Why a failed build failed.\n *\n * There is no `error` column on a release — when the API marks one failed it\n * appends a build-log entry with phase 'error' carrying the message. The\n * by-commit endpoint returns the plain release row, buildLog included, so the\n * reason is already in hand here.\n */\nfunction buildFailureReason(release: ReleasesByCommitResult): string | null {\n const log: V2BuildLogEntry[] = Array.isArray(release.buildLog)\n ? release.buildLog\n : [];\n const errors = log.filter(\n (entry) => entry?.phase === 'error' && typeof entry.message === 'string',\n );\n return errors.length ? errors[errors.length - 1].message : null;\n}\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 /** Build failure reason from the last build-log `error` phase entry; only present when status is `failed`. */\n error?: string;\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 if (release.status !== 'failed') {\n return summary;\n }\n return {\n ...summary,\n error:\n buildFailureReason(release) ??\n 'Build failed (no error entry in the build log)',\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 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 the platform-wide SES\n * suppression list dropped the message — usually from another tenant's hard\n * bounce — not the app's own suppression list.\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 (SES identity/DKIM); `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` (platform-wide SES suppression, usually another\n * tenant's hard bounce — not this app's list), `bounced`, `complained`,\n * `delayed`, `rejected`. Paginated via 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 * One row per blast/campaign with per-status counts.\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 * @example\n * const { batches } = await admin.email.batches({ limit: 20 });\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.\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.recipients, 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 the app-level suppression list.\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 * The returned `platformSuppression` field (non-null) means the address is\n * also on the platform-wide SES list and will remain undeliverable even after\n * this removal. The CLI skin surfaces that advisory on stderr.\n *\n * @throws AdminApiError `invalid_email` (400) — the address is not a valid email.\n * @example\n * const { platformSuppression } = await admin.email.unsuppress('user@example.com');\n * if (platformSuppression) console.warn('Address is still on the platform SES list.');\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 SES identity and returns\n * `dnsInstructions` containing three DKIM CNAME records (all required) and a\n * recommended SPF TXT record. Hand these to the user to create at their DNS\n * host, then call `verifyDomain` to re-check. SES verification can take\n * minutes after the CNAMEs resolve; `uiStatus` will be `pending` until then.\n *\n * **Inbound (`'inbound'`):** creates the domain row and returns\n * `dnsInstructions` with the single MX record to add. 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 * `ses_create_failed` (502, sending only) — SES identity creation failed.\n * @example\n * const { domain } = await admin.email.addDomain('sending', 'mail.acme.com');\n * console.log(domain.dnsInstructions.cnameRecords);\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 tears down the SES identity (best-effort; a SES\n * cleanup failure 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 * 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\nexport interface IssuesListParams {\n /** Filter by status: `open` or `closed`. */\n status?: string;\n /** Filter by kind: `bug`, `idea`, or `task`. */\n kind?: 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/**\n * List issues newest-first.\n *\n * @throws AdminApiError `invalid_status` (400) — status is not `open` or\n * `closed`; `invalid_kind` (400) — kind is not `bug`, `idea`, or `task`.\n * @example\n * const { issues } = await admin.issues.list({ status: 'open', kind: 'bug' });\n */\nexport function list(ctx: AdminContext, params: IssuesListParams = {}) {\n return call<IssuesListResult>(\n ctx,\n 'GET',\n `/_internal/v2/apps/${ctx.appId}/issues${qs(params as Record<string, string | number | boolean | undefined | null>)}`,\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 /** Issue kind: `bug`, `idea`, or `task` (default `bug`). */\n kind?: 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_kind` (400) — kind is not `bug`, `idea`, or `task`.\n * @example\n * const { issue } = await admin.issues.create({ title: 'Checkout 500s on empty cart', kind: '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.kind !== undefined) {\n requestBody.kind = params.kind;\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' },\n );\n}\n\n/**\n * Close an issue.\n *\n * Records a `closed` 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.close('42');\n */\nexport function close(ctx: AdminContext, number: string) {\n return call<IssuesUpdateResult>(\n ctx,\n 'POST',\n `/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}/update`,\n { status: 'closed', authorKind: 'agent' },\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' },\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 /** Change the kind to `bug`, `idea`, or `task`. */\n kind?: string;\n /** Change the status to `open` or `closed`. */\n status?: string;\n}\n\n/**\n * Edit an issue's title, body, kind, 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_kind` (400) — kind is not `bug`, `idea`, or `task`;\n * `invalid_status` (400) — status is not `open` or `closed`; `no_fields`\n * (400) — no editable field was provided; `issue_not_found` (404) — no\n * 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> = { authorKind: 'agent' };\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.kind !== undefined) {\n requestBody.kind = params.kind;\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\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>(ctx, 'POST', apiPath, body);\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 * 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 as Record<string, string | number | boolean | undefined | null>)}`,\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 as Record<string, string | number | boolean | undefined | null>)}`,\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 analytics from './ops/analytics.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 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 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 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 API_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: options.baseUrl ?? process.env['API_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 /** A sibling client for another app, sharing credentials. */\n forApp(appId: string) {\n return buildClient({ ...ctx, appId });\n },\n\n analytics: bindOps(analytics, ctx),\n crashes: bindOps(crashes, ctx),\n cron: bindOps(cron, ctx),\n data: bindOps(data, ctx),\n dataSources: bindOps(dataSources, 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 issues: bindOps(issues, ctx),\n jewels: bindOps(jewels, ctx),\n methods: bindOps(methods, ctx),\n prerender: bindOps(prerender, 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, API_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, receiver) {\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","search","list","list","list","view","list","query","query","query","get","list","list","get","summary","POLL_MS","live","get","get","batch","get","list","stats","list","get","stats","batch","path","createHash","createHash","path","get","list","list","get","list","list","get","list","list","get","del","get","list","set","list","get","set","del","list","list"]}
|