@tangle-network/agent-app 0.43.43 → 0.43.45

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sandbox/index.ts","../src/sandbox/outcome.ts","../src/sandbox/binary-read.ts","../src/sandbox/terminal-proxy-token.ts","../src/sandbox/workspace-terminal.ts"],"sourcesContent":["import {\n Sandbox,\n type AgentProfile,\n type AgentProfileFileMount,\n type AgentProfileMcpServer,\n type ExecResult,\n type SandboxConnection,\n type SandboxInstance,\n type ScopedTokenScope,\n type StorageConfig,\n type TurnDriveResult,\n type ProvisionEvent,\n} from '@tangle-network/sandbox'\nimport { createHash } from 'node:crypto'\nimport {\n buildAppToolMcpServer,\n type AppToolName,\n type AppToolContext,\n type ToolHeaderNames,\n} from '../tools/index'\nimport { assertHarnessModelCompatible, type Harness } from '../harness/index'\nimport {\n resolveTangleExecutionEnvironment,\n trimOrNull,\n type TangleExecutionEnvironment,\n} from '../runtime/model'\nimport { ok, fail, type Outcome } from './outcome'\n\nexport type { Outcome } from './outcome'\nexport * from './binary-read'\n\nexport interface SandboxClientCredentials {\n apiKey: string\n baseUrl: string\n}\n\n/**\n * Sandbox credential policy reuses the canonical execution-environment union\n * (development/test/staging/production) so env classification stays in one place\n * (see resolveTangleExecutionEnvironment in runtime/model).\n */\nexport type SandboxCredentialEnvironment = TangleExecutionEnvironment\n\nexport interface ResolveSandboxClientCredentialsOptions {\n /**\n * Environment object to read from. Defaults to process.env when available.\n */\n env?: Record<string, string | undefined>\n /**\n * Explicit environment classification. Defaults to APP_ENV/NODE_ENV derived\n * behavior: local/development/test use direct env credentials; staging/prod\n * require the provision callback unless allowDirectEnvCredentials opts in.\n */\n environment?: SandboxCredentialEnvironment\n /**\n * Env names that may carry a sandbox-compatible bearer. The first non-empty\n * value wins when direct env credentials are allowed.\n */\n directKeyNames?: readonly string[]\n /**\n * Env names that may carry the sandbox gateway URL. The first non-empty value\n * wins, then defaultBaseUrl.\n */\n baseUrlNames?: readonly string[]\n /**\n * Base URL used when none of baseUrlNames are present.\n */\n defaultBaseUrl?: string\n /**\n * Whether direct env credentials are allowed for this environment. Defaults\n * to true in development/test and false in staging/production.\n */\n allowDirectEnvCredentials?: boolean | ((environment: SandboxCredentialEnvironment) => boolean)\n /**\n * Product-owned provision path, usually minting a per-user sandbox key from a\n * linked platform account. Called before direct env credentials in\n * staging/production and after direct env credentials in development/test.\n */\n provision?: (\n context: {\n environment: SandboxCredentialEnvironment\n env: Record<string, string | undefined>\n },\n ) => SandboxClientCredentials | null | undefined | Promise<SandboxClientCredentials | null | undefined>\n}\n\nconst DEFAULT_SANDBOX_DIRECT_KEY_NAMES = [\n 'TCLOUD_SANDBOX_API_KEY',\n 'SANDBOX_API_KEY',\n 'TANGLE_API_KEY',\n] as const\nconst DEFAULT_SANDBOX_BASE_URL_NAMES = ['SANDBOX_GATEWAY_URL', 'SANDBOX_API_URL'] as const\n\nfunction normalizeBaseUrl(value: string): string {\n return value.trim().replace(/\\/v1\\/?$/, '').replace(/\\/+$/, '')\n}\n\nfunction processEnv(): Record<string, string | undefined> {\n return typeof process === 'undefined' ? {} : process.env\n}\n\nfunction directEnvCredentialsAllowed(\n environment: SandboxCredentialEnvironment,\n allow: ResolveSandboxClientCredentialsOptions['allowDirectEnvCredentials'],\n): boolean {\n if (typeof allow === 'function') return allow(environment)\n if (typeof allow === 'boolean') return allow\n return environment === 'development' || environment === 'test'\n}\n\nfunction resolveSandboxBaseUrl(\n env: Record<string, string | undefined>,\n names: readonly string[],\n defaultBaseUrl: string | undefined,\n): string {\n for (const name of names) {\n const value = trimOrNull(env[name])\n if (value) return normalizeBaseUrl(value)\n }\n const value = trimOrNull(defaultBaseUrl)\n if (value) return normalizeBaseUrl(value)\n throw new Error(\n `Sandbox base URL is required (set one of ${names.join(', ')} or pass defaultBaseUrl).`,\n )\n}\n\nfunction resolveDirectSandboxCredentials(\n env: Record<string, string | undefined>,\n keyNames: readonly string[],\n baseUrlNames: readonly string[],\n defaultBaseUrl: string | undefined,\n): SandboxClientCredentials | null {\n for (const name of keyNames) {\n const apiKey = trimOrNull(env[name])\n if (!apiKey) continue\n return {\n apiKey,\n baseUrl: resolveSandboxBaseUrl(env, baseUrlNames, defaultBaseUrl),\n }\n }\n return null\n}\n\nexport async function resolveSandboxClientCredentials(\n options: ResolveSandboxClientCredentialsOptions = {},\n): Promise<SandboxClientCredentials> {\n const env = options.env ?? processEnv()\n const environment = options.environment ?? resolveTangleExecutionEnvironment(env)\n const keyNames = options.directKeyNames ?? DEFAULT_SANDBOX_DIRECT_KEY_NAMES\n const baseUrlNames = options.baseUrlNames ?? DEFAULT_SANDBOX_BASE_URL_NAMES\n const directAllowed = directEnvCredentialsAllowed(environment, options.allowDirectEnvCredentials)\n const direct = () =>\n directAllowed\n ? resolveDirectSandboxCredentials(env, keyNames, baseUrlNames, options.defaultBaseUrl)\n : null\n\n if (environment === 'development' || environment === 'test') {\n const credentials = direct()\n if (credentials) return credentials\n }\n\n const provisioned = await options.provision?.({ environment, env })\n if (provisioned) {\n return {\n apiKey: provisioned.apiKey,\n baseUrl: normalizeBaseUrl(provisioned.baseUrl),\n }\n }\n\n const credentials = direct()\n if (credentials) return credentials\n\n const directHint = directAllowed\n ? ` or set one of ${keyNames.join(', ')}`\n : ''\n throw new Error(\n `Sandbox credentials are required for ${environment} (provide a provision callback${directHint}).`,\n )\n}\n\nexport interface SandboxResourceConfig {\n image: string\n cpuCores: number\n memoryMB: number\n diskGB: number\n maxLifetimeSeconds: number\n idleTimeoutSeconds: number\n}\n\nexport interface ProviderResolutionConfig {\n routerBaseUrl?: string\n apiKey?: string\n providerName?: string\n modelName?: string\n defaultModel?: string\n openaiApiKey?: string\n // Opt-in: a resolvable provider+model WITHOUT an api key still yields model\n // metadata (model/provider/baseUrl, no apiKey) instead of undefined. Keyless\n // metadata makes the sandbox platform mint its OWN per-user router key at\n // create (its requiresRouterKey gate), so turns bill the box's billing owner\n // instead of a product-baked shared key. Requires an explicit providerName —\n // provider inference from key presence cannot fire keyless. Default false:\n // a keyless config resolves to undefined exactly as before.\n allowKeylessModel?: boolean\n}\n\nexport interface SandboxBuildContext {\n workspaceId: string\n connectedIntegrationIds: string[]\n userId?: string\n}\n\n// SDK-typed snapshot storage config (re-exported for product seam closures).\nexport type { StorageConfig }\n\n// Scope handed to per-identity seams. workspaceId is always present; userId is\n// present when the lifecycle op carries one. Workspace-keyed products ignore userId.\nexport interface SandboxScope {\n workspaceId: string\n userId?: string\n}\n\n// Snapshot RESTORE-on-create. Returned alongside storage; undefined => fresh box.\nexport interface SandboxRestoreSpec {\n fromSnapshot: string\n fromSandboxId: string\n}\n\nexport interface StoppedSandboxResumeFailure {\n box: SandboxInstance\n error: Error\n scope: SandboxScope\n boxKey: string\n}\n\nexport interface StoppedSandboxResumeRecovery {\n // Used for both the replacement sandbox name and idempotency key.\n replacementBoxKey: string\n // undefined preserves the configured restore seam; null creates without one.\n restore?: SandboxRestoreSpec | null\n}\n\n// Reuse health gate + sidecar liveness. The exec+timeout-race is generic; the\n// sidecarProcessPattern is harness-specific (which process is the live sidecar),\n// so it is a closure. Absent => no liveness probe (reuse on metadata.harness match).\nexport interface LivenessProbeConfig {\n sidecarProcessPattern: (harness: Harness) => string\n execTimeoutMs?: number\n psTimeoutMs?: number\n}\n\nexport interface ProfileComposeOptions {\n systemPrompt?: string\n extraFiles?: AgentProfileFileMount[]\n extraMcp?: Record<string, AgentProfileMcpServer>\n name?: string\n}\n\nexport interface SandboxRuntimeConfig {\n // Widened to accept an optional scope and be async so a per-user key can be\n // minted. The sync, no-arg form still satisfies the type (back-compat).\n credentials: (\n scope?: SandboxScope,\n ) => SandboxClientCredentials | null | Promise<SandboxClientCredentials | null>\n name: (workspaceId: string) => string\n metadata: (harness: Harness) => Record<string, unknown>\n connectedIntegrationIds: (workspaceId: string) => Promise<string[]>\n env: (ctx: SandboxBuildContext) => Promise<Record<string, string>>\n files: (ctx: SandboxBuildContext) => Promise<AgentProfileFileMount[]>\n secrets: (workspaceId: string) => Promise<string[]>\n profile: (options: ProfileComposeOptions) => AgentProfile\n permissionRole?: (workspaceRole: string) => SandboxPermissionLevel\n resources?: SandboxResourceConfig\n provider?: ProviderResolutionConfig\n\n // BYOS3/R2 snapshot storage. Returns undefined => key omitted entirely\n // (fail-closed when creds absent). Product owns bucket/endpoint/credentials/prefix.\n storage?: (ctx: SandboxBuildContext) => StorageConfig | undefined\n // Snapshot RESTORE-on-create. undefined => fresh box.\n restore?: (ctx: SandboxBuildContext) => SandboxRestoreSpec | undefined\n // Per-identity box NAME. Defaults to name(scope.workspaceId) when absent.\n boxKey?: (scope: SandboxScope) => string\n // Per-workspace child-key mint: overrides the resolved model apiKey before create.\n // Applied only when a model is resolved and its provider is openai-compat.\n childKeyMint?: (scope: SandboxScope) => Promise<Outcome<string>>\n // One-shot post-running bootstrap, on BOTH create and reuse paths (idempotency\n // is the closure's job — it owns the marker check).\n bootstrap?: (box: SandboxInstance, scope: SandboxScope) => Promise<Outcome<void>>\n // Reuse health gate + sidecar liveness probe.\n livenessProbe?: LivenessProbeConfig\n // Enable browser terminal endpoints on newly-created sandboxes.\n webTerminalEnabled?: boolean\n // default true: try stopped-resume before create.\n resumeStopped?: boolean\n // Product-owned retention/recovery policy after a stopped box fails to resume.\n // Return ok(null) to preserve the original resume error. A replacement key is\n // required before this shell creates a new box, so it cannot resolve the\n // failed stopped box through the original idempotency identity.\n recoverStoppedSandbox?: (\n failure: StoppedSandboxResumeFailure,\n ) => Promise<Outcome<StoppedSandboxResumeRecovery | null>>\n // default false: bake resolveModel() into backend.model at create.\n backendModelAtCreate?: boolean\n // default false: write the profile's `resources.files` INTO the box after it\n // reaches running (via `box.exec`), instead of inlining them in the create\n // payload. The orchestrator caps the provision body at 256 KiB; a large\n // file corpus (skills, tool scripts) blows that cap. Deferring it keeps the\n // provision body small and uncapped in corpus size, and lands real files on\n // disk — which is also the only path that works for harnesses whose backend\n // does not materialize the provider-neutral `resources.files` channel.\n //\n // Only `kind: 'inline'` files are deferred; non-inline refs (e.g. github)\n // stay in the create payload so the orchestrator resolves them. Runs on the\n // create AND resume/reuse paths (idempotent overwrite). Inline files are\n // STRIPPED from `resources.files` before create when this is set.\n deferProfileFiles?: boolean\n}\n\nexport const DEFAULT_SANDBOX_RESOURCES: SandboxResourceConfig = {\n image: 'universal',\n cpuCores: 2,\n memoryMB: 4096,\n diskGB: 10,\n maxLifetimeSeconds: 86400,\n idleTimeoutSeconds: 3600,\n}\n\ninterface ClientCacheEntry {\n client: Sandbox\n fingerprint: string\n}\n\nlet _cached: ClientCacheEntry | null = null\n\nfunction getClientFromCreds(creds: SandboxClientCredentials): Sandbox {\n const fingerprint = `${creds.apiKey} ${creds.baseUrl}`\n if (_cached && _cached.fingerprint === fingerprint) return _cached.client\n\n const client = new Sandbox({ apiKey: creds.apiKey, baseUrl: creds.baseUrl })\n _cached = { client, fingerprint }\n return client\n}\n\n// Sync client for non-scoped callers (secretStoreFromClient etc.). Resolves\n// credentials with no scope; throws if the seam returns a Promise — scoped\n// products must use the async ensureWorkspaceSandbox path.\nexport function getClient(shell: SandboxRuntimeConfig): Sandbox {\n const creds = shell.credentials()\n if (creds && typeof (creds as Promise<unknown>).then === 'function') {\n throw new Error('getClient: scoped (async) credentials require the async sandbox path')\n }\n if (!creds) throw new Error('sandbox credentials are required (apiKey/baseUrl)')\n return getClientFromCreds(creds as SandboxClientCredentials)\n}\n\nexport function resetClientCache(): void {\n _cached = null\n}\n\nexport interface AppToolDescriptor {\n tool: AppToolName\n key: string\n description: string\n}\n\nexport interface BuildAppToolMcpServersOptions {\n tools: AppToolDescriptor[]\n baseUrl: string\n token: string\n ctx: AppToolContext\n headerNames?: ToolHeaderNames\n}\n\nexport function buildAppToolMcpServers(\n options: BuildAppToolMcpServersOptions,\n): Record<string, AgentProfileMcpServer> {\n const entries: Record<string, AgentProfileMcpServer> = {}\n for (const { tool, key, description } of options.tools) {\n entries[key] = buildAppToolMcpServer({\n tool,\n baseUrl: options.baseUrl,\n token: options.token,\n ctx: options.ctx,\n description,\n headerNames: options.headerNames,\n }) as AgentProfileMcpServer\n }\n return entries\n}\n\nexport interface EnsureWorkspaceSandboxOptions {\n workspaceId: string\n userId?: string\n harness: Harness\n // When set, both the running-reuse and stopped-resume short-circuits are\n // skipped and any name-matched box is deleted before create.\n forceNew?: boolean\n // Real-time provisioning progress from the SDK's SSE stream, forwarded from\n // the `waitFor('running')` calls on the resume and cold-create paths. Callers\n // surface it as live \"warming up\" status. Only fires while a box is actually\n // being provisioned; a reused running box emits nothing.\n onProgress?: (event: ProvisionEvent) => void\n // Billing owner for the created box, forwarded VERBATIM on the create\n // payload. The sandbox platform honors it only when the create-auth\n // principal is a trusted first-party service; the box's usage then bills\n // this platform user's wallet (the platform's per-user router-key mint)\n // instead of the service account that authenticated the create. Omitted =>\n // platform default (billing owner = create-auth principal) — unchanged.\n billingOwnerId?: string\n}\n\n// Single-quote a string for safe interpolation into a shell command.\nfunction shellSingleQuote(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`\n}\n\nexport interface SandboxToolSpec {\n name: string\n content: string\n executable?: boolean\n}\n\nexport interface SandboxToolPathOptions {\n appName: string\n baseDir?: string\n binDir?: string\n}\n\nexport interface BuildSandboxToolFileMountsOptions extends SandboxToolPathOptions {\n tools: readonly SandboxToolSpec[]\n}\n\nconst DEFAULT_SANDBOX_TOOL_BASE_DIR = '/home/agent/tools'\nconst SAFE_TOOL_SEGMENT = /^[A-Za-z0-9._-]+$/\n\nfunction normalizeSandboxToolSegment(value: string, label: string): string {\n const segment = value.trim()\n if (!segment || segment === '.' || segment === '..' || !SAFE_TOOL_SEGMENT.test(segment)) {\n throw new Error(`${label} must contain only letters, numbers, dots, underscores, or hyphens.`)\n }\n return segment\n}\n\nfunction normalizeSandboxToolDir(value: string, label: string): string {\n const dir = value.trim().replace(/\\/+$/, '')\n if (!dir || !dir.startsWith('/') || dir.includes('\\0') || dir.includes('\\n')) {\n throw new Error(`${label} must be an absolute sandbox path.`)\n }\n return dir === '' ? '/' : dir\n}\n\nexport function sandboxToolRootDir(options: SandboxToolPathOptions): string {\n const appName = normalizeSandboxToolSegment(options.appName, 'sandbox tool appName')\n const baseDir = normalizeSandboxToolDir(\n options.baseDir ?? DEFAULT_SANDBOX_TOOL_BASE_DIR,\n 'sandbox tool baseDir',\n )\n return `${baseDir}/${appName}`\n}\n\nexport function sandboxToolBinDir(options: SandboxToolPathOptions): string {\n normalizeSandboxToolSegment(options.appName, 'sandbox tool appName')\n if (options.binDir) return normalizeSandboxToolDir(options.binDir, 'sandbox tool binDir')\n return `${sandboxToolRootDir(options)}/bin`\n}\n\nexport function sandboxToolPath(options: SandboxToolPathOptions & { toolName: string }): string {\n const toolName = normalizeSandboxToolSegment(options.toolName, 'sandbox tool name')\n return `${sandboxToolBinDir(options)}/${toolName}`\n}\n\nexport function buildSandboxToolFileMounts(\n options: BuildSandboxToolFileMountsOptions,\n): AgentProfileFileMount[] {\n return options.tools.map((tool) => {\n const name = normalizeSandboxToolSegment(tool.name, 'sandbox tool name')\n return {\n path: sandboxToolPath({ ...options, toolName: name }),\n resource: { kind: 'inline' as const, name, content: tool.content },\n executable: tool.executable ?? true,\n }\n })\n}\n\nexport function buildSandboxToolPathSetupScript(options: SandboxToolPathOptions): string {\n const binDir = sandboxToolBinDir(options)\n const exportLine = `export PATH=${binDir}:$PATH`\n return [\n 'set -eu',\n `mkdir -p ${shellSingleQuote(binDir)}`,\n `PATH=${shellSingleQuote(binDir)}:$PATH`,\n 'export PATH',\n 'for profile in \"${HOME:-/home/agent}/.profile\" \"${HOME:-/home/agent}/.bashrc\" \"${HOME:-/home/agent}/.zshrc\"; do',\n ' mkdir -p \"$(dirname \"$profile\")\"',\n ' touch \"$profile\"',\n ` grep -Fqx ${shellSingleQuote(exportLine)} \"$profile\" || printf '\\\\n%s\\\\n' ${shellSingleQuote(exportLine)} >> \"$profile\"`,\n 'done',\n ].join('\\n')\n}\n\nexport async function runSandboxToolPathSetup(\n box: SandboxInstance,\n options: SandboxToolPathOptions,\n): Promise<Outcome<void>> {\n try {\n const res = await box.exec(buildSandboxToolPathSetupScript(options))\n if (res.exitCode !== 0) {\n return fail(\n new Error(\n `runSandboxToolPathSetup: failed to configure PATH for ${sandboxToolBinDir(options)} ` +\n `(exit ${res.exitCode}): ${res.stderr.slice(0, 500)}`,\n ),\n )\n }\n return ok(undefined)\n } catch (err) {\n return fail(new Error('runSandboxToolPathSetup: exec failed', { cause: err }))\n }\n}\n\n// Build a shell-safe path token that preserves tilde-home semantics. A path\n// beginning `~/` (or a bare `~`) must resolve to the box user's real `$HOME`,\n// but single-quoting the whole path suppresses shell `~` expansion and lands\n// the file in a literal directory named `~`. Expand the leading `~` to an\n// UNQUOTED `\"$HOME\"` (so the shell expands it) and single-quote only the\n// remainder. Absolute and relative paths are single-quoted unchanged.\nfunction shellPath(path: string): string {\n if (path === '~') return '\"$HOME\"'\n if (path.startsWith('~/')) {\n const rest = path.slice(2)\n return rest ? `\"$HOME\"/${shellSingleQuote(rest)}` : '\"$HOME\"'\n }\n return shellSingleQuote(path)\n}\n\n// Split a profile's `resources.files` into the inline mounts that can be\n// written into a running box and the rest (non-inline refs that the\n// orchestrator must resolve, so they stay in the create payload). Returns the\n// inline set to defer and a profile copy with those inline files removed.\nexport function splitDeferredProfileFiles(\n profile: AgentProfile,\n): { leanProfile: AgentProfile; deferredFiles: AgentProfileFileMount[] } {\n const files = profile.resources?.files ?? []\n const deferredFiles: AgentProfileFileMount[] = []\n const keptFiles: AgentProfileFileMount[] = []\n for (const mount of files) {\n if (mount.resource.kind === 'inline') deferredFiles.push(mount)\n else keptFiles.push(mount)\n }\n if (deferredFiles.length === 0) return { leanProfile: profile, deferredFiles }\n const leanProfile: AgentProfile = {\n ...profile,\n resources: { ...(profile.resources ?? {}), files: keptFiles },\n }\n return { leanProfile, deferredFiles }\n}\n\n// The runtime exec proxy (`box.exec` → /terminals/commands) hangs (30s\n// timeout) on any request whose body crosses ~4096 bytes, and one oversized\n// exec wedges the channel so every later exec on the box hangs too. We slice\n// each file's base64 into appends whose full command string stays well under\n// that cap. 3000 chars of base64 leaves ~1000 bytes of headroom for the\n// surrounding `printf '%s' '<slice>' >> <path>.b64` command plus the proxy's\n// JSON request envelope — comfortably below 4096.\nconst PROFILE_WRITE_B64_CHUNK_CHARS = 3000\n\n// gtm's corpus is ~135 small execs; on a cold box the runtime exec proxy\n// hard-throttles (HTTP 429 after ~21 execs in ~34s) and, under sustained load,\n// SILENTLY HANGS instead of returning 429 — one parked exec wedges the channel\n// and `writeProfileFilesToBox` never returns, so `ensureWorkspaceSandbox`\n// parks the worker (~140s, no exception). These failures plus sidecar exec-plane\n// readiness/transport failures (5xx, reset, fetch/network errors) are transient:\n// retry the SAME exec with exponential backoff before failing loud. A non-zero\n// exit is a real command failure, never retried.\nconst PROFILE_WRITE_MAX_RETRIES = 4\nconst PROFILE_WRITE_RETRY_BASE_MS = 250\nconst PROFILE_WRITE_RETRY_MAX_MS = 2000\n\n// Client-side hard ceiling per exec. The proxy's own 30s timeout is unreliable\n// once the channel wedges (it can hang past it), so we race each exec against an\n// independent timer we control: a wedged exec is abandoned here and retried as a\n// transient transport error, never silently parked. We also pass timeoutMs to\n// the SDK as defense-in-depth, but the race is the guarantee.\nconst PROFILE_WRITE_EXEC_TIMEOUT_MS = 30_000\n\n// Pacing between execs to stay under the proxy throttle that triggers the hang.\n// The drill saw throttling at ~0.6 exec/s bursts; ~150ms between ~135 execs\n// adds well under a minute total and keeps the burst rate below the trip point.\n// On by default for the deferred path; overridable for tests/tuning.\nconst PROFILE_WRITE_PACE_MS = 150\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms))\n\n// A mount whose path sits in a bin directory is made executable. Shared so the\n// file-API eligibility check and the exec branch agree on \"executable by dir\".\nconst PROFILE_BIN_DIR_RE = /(^|\\/)(s?bin)\\//\n\n// Sentinel cause for a client-side per-exec timeout (a hung/wedged proxy exec).\n// Carried as the `.cause` of the fail-loud Outcome so callers see the wedged\n// command instead of an opaque infinite hang.\nclass ProfileWriteExecTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`exec exceeded ${timeoutMs}ms (proxy hang/wedge)`)\n this.name = 'ProfileWriteExecTimeoutError'\n }\n}\n\n// Run a box.exec, abandoning it if it does not settle within timeoutMs. The\n// returned promise rejects with ProfileWriteExecTimeoutError on timeout so the\n// retry loop treats a hang exactly like a transient transport error. We also\n// forward timeoutMs to the SDK so the underlying request is cancelled when the\n// SDK honors it; the race covers the case where it does not.\nfunction execWithTimeout(\n box: SandboxInstance,\n cmd: string,\n timeoutMs: number,\n): Promise<ExecResult> {\n return new Promise<ExecResult>((resolve, reject) => {\n let settled = false\n const timer = setTimeout(() => {\n if (settled) return\n settled = true\n reject(new ProfileWriteExecTimeoutError(timeoutMs))\n }, timeoutMs)\n box.exec(cmd, { timeoutMs }).then(\n (res) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n resolve(res)\n },\n (err) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n reject(err)\n },\n )\n })\n}\n\nconst TRANSIENT_EXEC_STATUS_CODES = new Set([408, 409, 425, 429, 500, 502, 503, 504])\nconst TRANSIENT_EXEC_CODE_RE = /^(ECONNRESET|ECONNREFUSED|ETIMEDOUT|EPIPE|ECONNABORTED)$/i\nconst TRANSIENT_EXEC_MESSAGE_RE =\n /\\b(408|409|425|429|500|502|503|504)\\b|rate.?limit|too many requests|\\bfetch failed\\b|network error|connection reset|socket hang up|timed? out|service unavailable|bad gateway|gateway timeout|internal server error|\\b(?:sidecar|runtime|exec(?:ution)?|terminal|sandbox|service|command(?:s)?|proxy)\\b.{0,80}\\bnot ready\\b|\\bnot ready\\b.{0,80}\\b(?:sidecar|runtime|exec(?:ution)?|terminal|sandbox|service|command(?:s)?|proxy)\\b/i\nconst RUNTIME_AUTH_REFRESH_SKEW_MS = 60_000\n\nfunction errorStatus(err: { status?: unknown; statusCode?: unknown; response?: unknown }): number | undefined {\n const rawStatus = err.status ?? err.statusCode ?? (\n err.response && typeof err.response === 'object'\n ? (err.response as { status?: unknown }).status\n : undefined\n )\n if (typeof rawStatus === 'number') return rawStatus\n if (typeof rawStatus === 'string' && /^\\d+$/.test(rawStatus)) return Number(rawStatus)\n return undefined\n}\n\nfunction retryAfterMs(err: unknown, seen = new Set<object>()): number | undefined {\n if (!err || typeof err !== 'object') return undefined\n if (seen.has(err)) return undefined\n seen.add(err)\n const e = err as { retryAfterMs?: unknown; cause?: unknown }\n if (typeof e.retryAfterMs === 'number') return e.retryAfterMs\n return retryAfterMs(e.cause, seen)\n}\n\nfunction isTransientExecError(err: unknown, seen = new Set<object>()): boolean {\n if (!err || typeof err !== 'object') return false\n if (seen.has(err)) return false\n seen.add(err)\n const e = err as {\n status?: unknown\n statusCode?: unknown\n response?: unknown\n code?: unknown\n message?: unknown\n cause?: unknown\n }\n const status = errorStatus(e)\n if (status !== undefined && TRANSIENT_EXEC_STATUS_CODES.has(status)) return true\n if (typeof e.code === 'string') {\n if (TRANSIENT_EXEC_CODE_RE.test(e.code)) return true\n if (/rate.?limit|too.?many.?requests|429|server.?error|service.?unavailable/i.test(e.code)) return true\n }\n if (typeof e.message === 'string' && TRANSIENT_EXEC_MESSAGE_RE.test(e.message)) return true\n return isTransientExecError(e.cause, seen)\n}\n\nfunction isRuntimeExecAuthError(err: unknown, seen = new Set<object>()): boolean {\n if (!err || typeof err !== 'object') return false\n if (seen.has(err)) return false\n seen.add(err)\n const e = err as {\n status?: unknown\n statusCode?: unknown\n response?: unknown\n code?: unknown\n name?: unknown\n message?: unknown\n cause?: unknown\n }\n if (errorStatus(e) === 401) return true\n if (\n typeof e.code === 'string' &&\n /^(AUTH_ERROR|AUTHENTICATION_ERROR|UNAUTHORIZED|UNAUTHENTICATED|ERR_UNAUTHORIZED|ERR_UNAUTHENTICATED|401)$/i.test(e.code)\n ) {\n return true\n }\n if (\n typeof e.name === 'string' &&\n /^(AuthError|AuthenticationError|UnauthorizedError|UnauthenticatedError|SandboxAuthError)$/i.test(e.name)\n ) {\n return true\n }\n return isRuntimeExecAuthError(e.cause, seen)\n}\n\nfunction isRuntimeAuthRefreshDenied(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false\n return (\n isRuntimeExecAuthError(err) ||\n errorStatus(err as { status?: unknown; statusCode?: unknown; response?: unknown }) === 403\n )\n}\n\n// Classify an exec failure as transient-retryable. Retryable shapes share the\n// same backoff path: rate-limit (HTTP 429 + retryAfterMs), client-side timeout,\n// and transient sidecar/transport/readiness failures surfaced as SandboxError-\n// shaped objects, fetch errors, network resets, or 5xx-ish messages. Everything\n// else fails loud. Non-zero shell exits never reach this classifier.\nfunction transientExecError(err: unknown): { retryable: boolean; retryAfterMs?: number } {\n if (err instanceof ProfileWriteExecTimeoutError) return { retryable: true }\n if (isTransientExecError(err)) return { retryable: true, retryAfterMs: retryAfterMs(err) }\n return { retryable: false }\n}\n\nfunction deferredProfileWriteFailed(stage: 'new' | 'reused' | 'resumed', name: string, cause: Error): Error {\n return new Error(`deferred file write failed on ${stage} box ${name}: ${cause.message}`, { cause })\n}\n\ntype ExistingBoxStage = 'reused' | 'resumed'\n\nexport class SandboxRuntimeAuthRefreshError extends Error {\n constructor(stage: ExistingBoxStage, name: string, detail: string, cause?: unknown) {\n super(`${stage} sandbox auth refresh failed for ${name}: ${detail}`, { cause })\n this.name = 'SandboxRuntimeAuthRefreshError'\n }\n}\n\n// Materialize inline profile files into a running box via `box.exec`. Uses a\n// base64 pipe so arbitrary content (scripts, unicode, special chars) lands\n// byte-exact, and writes to ANY absolute path (e.g. /usr/local/bin) or a\n// `~`-relative path — the exec runs as the sidecar, which is not bound by the\n// safe-prefix allow-list the /files/write API enforces. Sets the executable\n// bit when the mount declares it OR the target is a bin directory.\n//\n// Each file is written in several small execs (mkdir, one append per base64\n// chunk, then a decode+cleanup) so no single exec request body trips the\n// ~4 KiB proxy cap. Writes are sequential; a single bad mount stops the batch\n// and the first failure is returned (fail-loud), the rest are not attempted.\n//\n// Each exec is bounded by a client-side hard timeout and retried with backoff\n// on transient rate-limit/readiness/transport failures, so one wedged or early\n// exec-plane request can never park the caller (and thus never park provisioning).\n// A small pace between execs keeps the burst rate below the proxy throttle that\n// triggers the hang.\nexport interface WriteProfileFilesOptions {\n // Hard ceiling per exec (ms). A hung/wedged exec is abandoned and retried.\n execTimeoutMs?: number\n // Delay between execs (ms) to stay under the proxy throttle. 0 disables it.\n paceMs?: number\n // Max retries for a transient exec before failing loud.\n maxRetries?: number\n}\n\n// The workspace-relative target for a deferred inline mount when it can be\n// materialized through the sidecar file API (`box.fs.writeMany` — FILES rate\n// group, 300/min, whole-file, auto-mkdir) instead of the chunked terminal-exec\n// path (50/min); null when it must stay on exec. The file API resolves relative\n// paths from the workspace root, so eligibility is: inline and a path that\n// resolves under the workspace root with no `..`/`.sidecar` segment. `~/…` and\n// `/home/agent/…` are home-relative; agent sandboxes set $HOME to the workspace\n// root, so both map to the same relative target. Other absolute (`/…`) and bare\n// `~`/`~user` mounts stay on exec.\nfunction fileApiTarget(mount: AgentProfileFileMount): string | null {\n if (mount.resource.kind !== 'inline') return null\n let rel: string\n if (mount.path.startsWith('~/')) rel = mount.path.slice(2)\n else if (mount.path.startsWith('/home/agent/')) rel = mount.path.slice('/home/agent/'.length)\n else if (mount.path.startsWith('/') || mount.path.startsWith('~')) return null\n else rel = mount.path\n if (rel.length === 0 || rel.startsWith('/') || rel.split('/').some((seg) => seg === '..' || seg === '.sidecar')) {\n return null\n }\n return rel\n}\n\nfunction isExecutableProfileFile(mount: AgentProfileFileMount): boolean {\n return mount.executable ?? PROFILE_BIN_DIR_RE.test(mount.path)\n}\n\nfunction profileFileMode(mount: AgentProfileFileMount): number | undefined {\n return isExecutableProfileFile(mount) ? 0o755 : undefined\n}\n\nfunction fileApiSupportsMode(box: SandboxInstance): boolean {\n const fs = box.fs as (SandboxInstance['fs'] & { supportsWriteMode?: boolean }) | undefined\n return fs?.supportsWriteMode === true\n}\n\nexport async function writeProfileFilesToBox(\n box: SandboxInstance,\n files: AgentProfileFileMount[],\n options: WriteProfileFilesOptions = {},\n): Promise<Outcome<void>> {\n const execTimeoutMs = options.execTimeoutMs ?? PROFILE_WRITE_EXEC_TIMEOUT_MS\n const paceMs = options.paceMs ?? PROFILE_WRITE_PACE_MS\n const maxRetries = options.maxRetries ?? PROFILE_WRITE_MAX_RETRIES\n // The bulk of a profile corpus (skills, `~/.claude/skills/…`, config) is\n // inline and workspace-relative — write it in ONE paced,\n // retry-aware batch via the SDK's file API (`box.fs.writeMany`, FILES rate\n // group 300/min). The SDK owns the pacing + transient-retry this module used\n // to hand-roll. Absolute / bare-`~` paths can't use the file API\n // (prefix-restricted), so they stay on the chunked exec path.\n // Capability-guarded: SDKs without `writeMany` route everything through\n // exec; SDKs before @tangle-network/sandbox 0.9.4 keep executable files on\n // exec because they do not expose `supportsWriteMode` or forward file modes.\n const fileApiAvailable = typeof box.fs?.writeMany === 'function'\n const modeAwareFileApi = fileApiSupportsMode(box)\n const viaFileApi: { path: string; content: string; mode?: number }[] = []\n const viaExec: AgentProfileFileMount[] = []\n for (const mount of files) {\n if (mount.resource.kind !== 'inline') continue\n const fileApiPath = fileApiAvailable ? fileApiTarget(mount) : null\n const executable = isExecutableProfileFile(mount)\n if (fileApiPath !== null && (!executable || modeAwareFileApi)) {\n const mode = profileFileMode(mount)\n viaFileApi.push({\n path: fileApiPath,\n content: mount.resource.content ?? '',\n ...(mode !== undefined ? { mode } : {}),\n })\n }\n else viaExec.push(mount)\n }\n if (viaFileApi.length > 0) {\n // `writeMany` is fail-loud on the first file it can't write. Preserve the\n // cause so the runtime-auth-refresh wrapper still detects a 401 — it\n // recurses `.cause` for an AuthError/401 shape (see isRuntimeExecAuthError).\n try {\n await box.fs.writeMany(viaFileApi, { paceMs, maxRetries })\n } catch (err) {\n return fail(new Error('writeProfileFilesToBox: file-API batch write failed', { cause: err }))\n }\n }\n\n // Pace BETWEEN execs, not before the first or after the last. Shared across\n // the exec mounts so the (now smaller) executable/edge-case set stays paced.\n let execStarted = false\n\n // Pace + transient-retry ONE exec attempt: backoff/pace/fail-loud in one place.\n // `run` must be idempotent under unknown-outcome retries (exec writes\n // deterministic parts). A transient error retries with backoff up to\n // maxRetries (honoring a server Retry-After); anything else, or exhausting\n // retries, fails loud with the cause.\n const paceAndRetry = async <T>(run: () => Promise<T>, path: string): Promise<Outcome<T>> => {\n for (let attempt = 0; ; attempt++) {\n if (execStarted && paceMs > 0) await sleep(paceMs)\n execStarted = true\n try {\n return ok(await run())\n } catch (err) {\n const { retryable, retryAfterMs } = transientExecError(err)\n if (retryable && attempt < maxRetries) {\n const backoff = Math.min(PROFILE_WRITE_RETRY_BASE_MS * 2 ** attempt, PROFILE_WRITE_RETRY_MAX_MS)\n await sleep(retryAfterMs ?? backoff)\n continue\n }\n return fail(new Error(`writeProfileFilesToBox: exec failed for ${path}`, { cause: err }))\n }\n }\n }\n\n for (const mount of viaExec) {\n if (mount.resource.kind !== 'inline') continue // always true (viaExec is inline) — narrows for TS\n const content = mount.resource.content ?? ''\n const path = mount.path\n\n const b64 = Buffer.from(content, 'utf8').toString('base64')\n const b64Chunks: string[] = []\n for (let i = 0; i < b64.length; i += PROFILE_WRITE_B64_CHUNK_CHARS) {\n b64Chunks.push(b64.slice(i, i + PROFILE_WRITE_B64_CHUNK_CHARS))\n }\n const expectedSha256 = createHash('sha256').update(content, 'utf8').digest('hex')\n const dir = path.replace(/\\/[^/]*$/, '')\n const executable = isExecutableProfileFile(mount)\n const q = shellPath(path)\n const qb64 = shellPath(`${path}.b64`)\n const qtmp = shellPath(`${path}.tmp`)\n const qpartPrefix = shellPath(`${path}.b64.part.`)\n\n // Run one exec step. Transport errors (incl. a wedged-proxy timeout) are\n // paced + retried by paceAndRetry; a non-zero exit is a REAL command failure\n // — surfaced immediately, never retried.\n const step = async (cmd: string): Promise<Outcome<void>> => {\n const res = await paceAndRetry(() => execWithTimeout(box, cmd, execTimeoutMs), path)\n if (!res.succeeded) return res\n const exec = res.value\n if (exec.exitCode !== 0) {\n return fail(\n new Error(\n `writeProfileFilesToBox: failed to write ${path} (exit ${exec.exitCode}): ${exec.stderr.slice(0, 500)}`,\n ),\n )\n }\n return ok(undefined)\n }\n\n // Ensure the target directory exists. Chunk/final commands below are\n // idempotent under unknown-outcome transport retries; this no-op/mkdir is too.\n const mkdir = dir && dir !== path ? `mkdir -p ${shellPath(dir)}` : ':'\n let res = await step(mkdir)\n if (!res.succeeded) return res\n\n // Write each deterministic part with overwrite, not append. If the server\n // writes a part but the HTTP response is lost, retrying the same step lands\n // the same bytes instead of duplicating them.\n for (let i = 0; i < b64Chunks.length; i++) {\n const slice = b64Chunks[i]!\n res = await step(`printf '%s' '${slice}' > ${shellPath(`${path}.b64.part.${i}`)}`)\n if (!res.succeeded) return res\n }\n\n // Materialize from deterministic parts into a temp file, verify its content\n // hash, then atomically move into place. If the final exec succeeds but its\n // response is lost, a retry first accepts an already-correct target and only\n // re-runs idempotent chmod/cleanup. Parts are cleaned only after the target\n // hash is known-good, so a retried final step can always reconstruct.\n const chmod = executable ? `chmod +x ${q} || exit 1; ` : ''\n const checksumMismatch = shellSingleQuote(`writeProfileFilesToBox: checksum mismatch for ${path}`)\n const finalCmd =\n `expected='${expectedSha256}'; ` +\n `if [ -f ${q} ] && [ \"$(sha256sum ${q} | awk '{print $1}')\" = \"$expected\" ]; then ` +\n `${chmod}rm -f ${qb64} ${qtmp}; i=0; while [ \"$i\" -lt ${b64Chunks.length} ]; do rm -f ${qpartPrefix}$i; i=$((i+1)); done; exit 0; fi; ` +\n `: > ${qb64} && ` +\n `i=0; while [ \"$i\" -lt ${b64Chunks.length} ]; do cat ${qpartPrefix}$i >> ${qb64} || exit 1; i=$((i+1)); done && ` +\n `base64 -d ${qb64} > ${qtmp} && ` +\n `[ \"$(sha256sum ${qtmp} | awk '{print $1}')\" = \"$expected\" ] || { echo ${checksumMismatch} >&2; exit 1; }; ` +\n `mv ${qtmp} ${q} && ` +\n `${executable ? `chmod +x ${q} && ` : ''}` +\n `[ \"$(sha256sum ${q} | awk '{print $1}')\" = \"$expected\" ] || { echo ${checksumMismatch} >&2; exit 1; }; ` +\n `rm -f ${qb64} ${qtmp}; i=0; while [ \"$i\" -lt ${b64Chunks.length} ]; do rm -f ${qpartPrefix}$i; i=$((i+1)); done`\n res = await step(finalCmd)\n if (!res.succeeded) return res\n }\n return ok(undefined)\n}\n\n// Resolve the shell's deferred (inline) profile files and write them into a\n// box that already exists (reuse/resume paths). No-op unless the shell opts\n// into deferProfileFiles. Idempotent overwrite — a redeploy with new skills\n// refreshes the corpus on the next ensure call.\n// Box-metadata key holding the content hash of the deferred corpus that was\n// written to the box at CREATE. On reuse, an unchanged hash means the skills are\n// already on disk, so the (large, file-API) re-write can be skipped.\nconst DEFERRED_CORPUS_HASH_KEY = 'agentAppDeferredCorpusHash'\n\n/** Stable content hash of the deferred file corpus (path + inline content).\n * Unchanged corpus ⇒ same hash; a new/edited/removed skill ⇒ different hash.\n * Exported for the reuse-skip test. */\nexport function deferredCorpusHash(files: AgentProfileFileMount[]): string {\n const norm = files\n .map((f) => ({\n p: f.path,\n c: f.resource.kind === 'inline' ? ((f.resource as { content?: string }).content ?? '') : `ref:${f.resource.kind}`,\n }))\n .sort((a, b) => (a.p < b.p ? -1 : a.p > b.p ? 1 : 0))\n return createHash('sha256').update(JSON.stringify(norm), 'utf8').digest('hex')\n}\n\nasync function materializeDeferredFilesForExistingBox(\n shell: SandboxRuntimeConfig,\n client: Sandbox,\n box: SandboxInstance,\n stage: ExistingBoxStage,\n name: string,\n workspaceId: string,\n userId: string | undefined,\n): Promise<Outcome<SandboxInstance>> {\n if (!shell.deferProfileFiles) return ok(box)\n const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId)\n const buildCtx: SandboxBuildContext = {\n workspaceId,\n connectedIntegrationIds,\n ...(userId ? { userId } : {}),\n }\n const files = await shell.files(buildCtx)\n const fullProfile = shell.profile({ extraFiles: files })\n const { deferredFiles } = splitDeferredProfileFiles(fullProfile)\n if (deferredFiles.length === 0) return ok(box)\n // Skip the whole re-write when the corpus is UNCHANGED since the box was\n // created with it. The skill corpus is large and the bulk goes through the\n // file API (writeMany) UNCONDITIONALLY, so re-writing it on every reuse adds\n // seconds of latency to each turn. The create payload stamps the corpus hash\n // into box metadata; a matching hash means the skills are already on disk.\n // Fail-safe: a missing or mismatched hash (e.g. a redeploy with new skills, or\n // a box created before this optimization) WRITES — a stale skip is never\n // risked. Reads metadata only, so no extra exec/round-trip.\n const stampedHash = (box.metadata as Record<string, unknown> | undefined)?.[DEFERRED_CORPUS_HASH_KEY]\n if (typeof stampedHash === 'string' && stampedHash === deferredCorpusHash(deferredFiles)) return ok(box)\n return writeDeferredFilesWithRuntimeAuthRefresh(client, box, deferredFiles, stage, name)\n}\n\nasync function listRunning(\n client: Sandbox,\n name: string,\n): Promise<Outcome<SandboxInstance | null>> {\n try {\n const running = await client.list({ status: 'running' })\n return ok(running.find((s) => s.name === name) ?? null)\n } catch (err) {\n return fail(err)\n }\n}\n\nasync function listStopped(\n client: Sandbox,\n name: string,\n): Promise<Outcome<SandboxInstance | null>> {\n try {\n const stopped = await client.list({ status: 'stopped' })\n return ok(stopped.find((s) => s.name === name) ?? null)\n } catch (err) {\n return fail(err)\n }\n}\n\nasync function deleteBox(box: SandboxInstance): Promise<Outcome<void>> {\n try {\n await box.delete()\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\n// The SDK narrows `backend.type` to its own BackendType union and\n// `initialUsers[].role` to PermissionLevel — neither symbol is exported. The\n// create payload is assembled with the product's Harness/role strings, which\n// are a superset surface; the localized cast at the boundary is the only place\n// this widening is allowed, and the runtime contract (the sidecar boots the\n// named harness) is what enforces correctness.\ntype CreatePayload = Parameters<Sandbox['create']>[0]\n\n// ---------------------------------------------------------------------------\n// Provision-time S-cost gates. Both run immediately before `client.create` —\n// each catches an input class that can NEVER produce a working sandbox, so\n// failing at POST-time with actionable detail beats a platform 4xx (or a box\n// that boots and then E2BIGs on every exec).\n\n/** Gate on the provision body: the platform orchestrator caps the create\n * payload at 256 KiB; 240 KB leaves headroom for transport framing. An\n * over-cap payload fails provisioning 100% of the time (a 282 KB payload\n * shipped once and no sandbox could ever be created). */\nexport const PROVISION_PAYLOAD_MAX_BYTES = 240_000\n\n/** Per-variable env gate: the kernel rejects any single `NAME=value` env entry\n * over MAX_ARG_STRLEN (131072 bytes) with E2BIG, killing every exec inside\n * the box. 120 KB leaves headroom for the name and framing. */\nexport const ENV_VALUE_MAX_BYTES = 120_000\n\n/** Total env gate: the whole environment block shares the payload budget with\n * the profile; past 200 KB the provision body cannot stay under the cap. */\nexport const ENV_TOTAL_MAX_BYTES = 200_000\n\nfunction utf8ByteLength(value: unknown): number {\n return new TextEncoder().encode(typeof value === 'string' ? value : JSON.stringify(value ?? null))\n .byteLength\n}\n\n/** Structural slice of the profile the payload gate reads: it only measures\n * the profile's serialized size and names `resources.files` in the breakdown,\n * so callers composing a payload outside the SDK (products, tests) can pass a\n * plain object without casting through `AgentProfile`. */\nexport interface ProvisionProfileSection {\n resources?: { files?: readonly unknown[] }\n}\n\n/** The provision-payload sections the size gates need to see. Structural so\n * the gate is testable without the SDK's (unexported) create-payload type. */\nexport interface ProvisionPayloadSections {\n env?: Record<string, string>\n secrets?: readonly string[]\n /** `profile` may also be a named-profile string ref (the SDK's\n * `BackendConfig` union) — a string ref is tiny and has no files channel. */\n backend?: { profile?: string | ProvisionProfileSection }\n}\n\n/**\n * Throw when the serialized provision payload exceeds\n * {@link PROVISION_PAYLOAD_MAX_BYTES}. The error carries a per-section byte\n * breakdown (profile/files/env/secrets) so the offending channel is named, not\n * guessed.\n */\nexport function assertProvisionPayloadWithinCap(payload: ProvisionPayloadSections): void {\n const total = utf8ByteLength(payload)\n if (total <= PROVISION_PAYLOAD_MAX_BYTES) return\n const profile = payload.backend?.profile\n const files = (typeof profile === 'string' ? undefined : profile?.resources?.files) ?? []\n const breakdown =\n `profile=${utf8ByteLength(profile ?? null)}B ` +\n `(files=${utf8ByteLength(files)}B), ` +\n `env=${utf8ByteLength(payload.env ?? {})}B, ` +\n `secrets=${utf8ByteLength(payload.secrets ?? [])}B`\n throw new Error(\n `sandbox provision payload is ${total} bytes — over the ${PROVISION_PAYLOAD_MAX_BYTES}-byte gate ` +\n `(the platform caps the create body at 256 KiB; an over-cap payload can never create a sandbox). ` +\n `Breakdown: ${breakdown}. ` +\n `Hint: set deferProfileFiles: true or move content to resources.`,\n )\n}\n\n/**\n * Throw when any single env value exceeds {@link ENV_VALUE_MAX_BYTES} or the\n * whole env block exceeds {@link ENV_TOTAL_MAX_BYTES}, naming the offending\n * variable. This is the E2BIG incident class: the box may even provision, but\n * every exec inside it dies on the oversized entry.\n */\nexport function assertEnvWithinLimits(env: Record<string, string>): void {\n let total = 0\n let largest: { name: string; bytes: number } | null = null\n for (const [name, value] of Object.entries(env)) {\n const bytes = utf8ByteLength(`${name}=${value}`)\n total += bytes\n if (!largest || bytes > largest.bytes) largest = { name, bytes }\n if (bytes > ENV_VALUE_MAX_BYTES) {\n throw new Error(\n `sandbox env var ${name} is ${bytes} bytes — over the ${ENV_VALUE_MAX_BYTES}-byte gate ` +\n `(kernel MAX_ARG_STRLEN is 131072 bytes per env entry; anything larger E2BIGs every exec). ` +\n `Write large content to a file mount or resource instead of an env var.`,\n )\n }\n }\n if (total > ENV_TOTAL_MAX_BYTES) {\n const worst = largest ? ` Largest: ${largest.name} (${largest.bytes}B).` : ''\n throw new Error(\n `sandbox env block is ${total} bytes total — over the ${ENV_TOTAL_MAX_BYTES}-byte gate.${worst} ` +\n `Write large content to a file mount or resource instead of env vars.`,\n )\n }\n}\n\n// Generic exec+sidecar liveness probe. Absent probe => always alive (the prior\n// reuse-on-metadata-match behavior). With a probe: the container must answer an\n// `echo alive` exec within execTimeoutMs, and the sidecar process must be found\n// by pgrep within psTimeoutMs (an inconclusive pgrep is treated as reusable).\nasync function isBoxAlive(\n box: SandboxInstance,\n harness: Harness,\n probe: LivenessProbeConfig | undefined,\n): Promise<boolean> {\n if (!probe) return true\n const execTimeout = probe.execTimeoutMs ?? 5000\n const psTimeout = probe.psTimeoutMs ?? 3000\n const race = <T>(p: Promise<T>, ms: number, label: string): Promise<T> =>\n Promise.race([\n p,\n new Promise<T>((_, reject) => setTimeout(() => reject(new Error(label)), ms)),\n ])\n try {\n const alive = await race(box.exec('echo alive'), execTimeout, 'alive check timeout')\n if (!alive.stdout.includes('alive')) return false\n const pattern = probe.sidecarProcessPattern(harness)\n try {\n const ps = await race(\n box.exec(`pgrep -f ${shellSingleQuote(pattern)} || echo no-sidecar`),\n psTimeout,\n 'ps check timeout',\n )\n if (ps.stdout.includes('no-sidecar')) return false\n } catch {\n // sidecar probe inconclusive — container is alive, treat as reusable\n }\n return true\n } catch {\n return false\n }\n}\n\nconst RUNTIME_CONNECTION_WAIT_MS = 30_000\nconst RUNTIME_CONNECTION_POLL_MS = 1_000\n\n// `sidecarUrl` is a product/forward-compat field the orchestrator may set on\n// the connection ahead of the SDK declaring it — the v0.6 `SandboxConnection`\n// exposes only `runtimeUrl`. Read it through a typed augmentation rather than an\n// ad-hoc cast (a plain `SandboxConnection` satisfies the optional field), and\n// fall back to the SDK runtime URL. The product-facing `WorkspaceSandboxInstanceLike`\n// carries the same field for consumers driving their own box types.\ntype RuntimeConnectionFields = SandboxConnection & {\n sidecarUrl?: string\n authToken?: string\n sidecarToken?: string\n authTokenExpiresAt?: string | number | Date\n sidecarTokenExpiresAt?: string | number | Date\n}\n\nfunction sandboxRuntimeUrl(box: SandboxInstance): string | undefined {\n const connection: RuntimeConnectionFields | undefined = box.connection\n return connection?.sidecarUrl ?? connection?.runtimeUrl\n}\n\nfunction runtimeAuthExpiresAtMs(value: string | number | Date | undefined): number | undefined {\n if (value instanceof Date) return value.getTime()\n if (typeof value === 'number') return value\n if (typeof value !== 'string' || value.trim() === '') return undefined\n const parsed = Date.parse(value)\n return Number.isNaN(parsed) ? undefined : parsed\n}\n\nfunction hasFreshRuntimeExecAuth(box: SandboxInstance, now = Date.now()): boolean {\n const connection: RuntimeConnectionFields | undefined = box.connection\n const token = connection?.authToken ?? connection?.sidecarToken\n if (!sandboxRuntimeUrl(box) || !token) return false\n const expiresAt = runtimeAuthExpiresAtMs(\n connection?.authTokenExpiresAt ?? connection?.sidecarTokenExpiresAt,\n )\n return expiresAt === undefined || expiresAt > now + RUNTIME_AUTH_REFRESH_SKEW_MS\n}\n\nfunction sandboxEdgeFailed(box: SandboxInstance): boolean {\n // `edgeStatus`/`edgeError` are declared on the SDK's `SandboxConnection`, so no cast.\n const connection = box.connection\n return connection?.edgeStatus === 'failed' || Boolean(connection?.edgeError)\n}\n\nasync function refreshRuntimeConnection(\n client: Sandbox,\n box: SandboxInstance,\n): Promise<SandboxInstance> {\n let current = box\n if (sandboxRuntimeUrl(current)) return current\n\n const deadline = Date.now() + RUNTIME_CONNECTION_WAIT_MS\n while (Date.now() < deadline) {\n // Tolerate transient refresh/get failures (5xx, network blips) while the\n // orchestrator is still attaching the connection: swallow and retry. A box\n // that never surfaces a runtime URL is returned as-is so the caller's\n // readiness gate (isReusableBox) drops and recreates it — rather than this\n // poll throwing a hard provisioning failure on a recoverable hiccup.\n try {\n await current.refresh()\n if (sandboxRuntimeUrl(current)) return current\n\n const latest = await client.get(current.id)\n if (latest) current = latest\n if (sandboxRuntimeUrl(current)) return current\n } catch {\n // transient — fall through to the poll delay and retry\n }\n\n await new Promise((resolve) => setTimeout(resolve, RUNTIME_CONNECTION_POLL_MS))\n }\n\n return current\n}\n\nasync function bestEffortRefreshRuntimeExecAuth(\n client: Sandbox,\n box: SandboxInstance,\n stage: ExistingBoxStage,\n name: string,\n): Promise<Outcome<SandboxInstance>> {\n let current = box\n\n try {\n await current.refresh()\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n } catch (err) {\n if (isRuntimeAuthRefreshDenied(err)) {\n return fail(\n new SandboxRuntimeAuthRefreshError(\n stage,\n name,\n 'runtime exec auth refresh was unauthorized',\n err,\n ),\n )\n }\n }\n\n try {\n const latest = await client.get(current.id)\n if (latest) current = latest\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n } catch (err) {\n if (isRuntimeAuthRefreshDenied(err)) {\n return fail(\n new SandboxRuntimeAuthRefreshError(\n stage,\n name,\n 'runtime exec auth re-fetch was unauthorized',\n err,\n ),\n )\n }\n }\n\n return ok(current)\n}\n\nasync function refreshRuntimeExecAuth(\n client: Sandbox,\n box: SandboxInstance,\n stage: ExistingBoxStage,\n name: string,\n): Promise<Outcome<SandboxInstance>> {\n let current = box\n let lastError: unknown\n const deadline = Date.now() + RUNTIME_CONNECTION_WAIT_MS\n\n while (Date.now() < deadline) {\n try {\n await current.refresh()\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n\n const latest = await client.get(current.id)\n if (latest) current = latest\n if (hasFreshRuntimeExecAuth(current)) return ok(current)\n } catch (err) {\n lastError = err\n }\n\n await new Promise((resolve) => setTimeout(resolve, RUNTIME_CONNECTION_POLL_MS))\n }\n\n const detail = sandboxRuntimeUrl(current)\n ? 'runtime exec credentials are missing or expired after refresh'\n : 'runtime connection is missing after refresh'\n return fail(new SandboxRuntimeAuthRefreshError(stage, name, detail, lastError))\n}\n\nasync function writeDeferredFilesWithRuntimeAuthRefresh(\n client: Sandbox,\n box: SandboxInstance,\n files: AgentProfileFileMount[],\n stage: ExistingBoxStage,\n name: string,\n): Promise<Outcome<SandboxInstance>> {\n let writeBox = box\n\n if (!hasFreshRuntimeExecAuth(writeBox)) {\n const refreshed = await bestEffortRefreshRuntimeExecAuth(client, writeBox, stage, name)\n if (!refreshed.succeeded) return fail(refreshed.error)\n writeBox = refreshed.value\n }\n\n const first = await writeProfileFilesToBox(writeBox, files)\n if (first.succeeded) return ok(writeBox)\n if (!isRuntimeExecAuthError(first.error)) return fail(first.error)\n\n const refreshed = await refreshRuntimeExecAuth(client, writeBox, stage, name)\n if (!refreshed.succeeded) return fail(refreshed.error)\n\n const second = await writeProfileFilesToBox(refreshed.value, files)\n if (second.succeeded) return ok(refreshed.value)\n if (!isRuntimeExecAuthError(second.error)) return fail(second.error)\n\n return fail(\n new SandboxRuntimeAuthRefreshError(\n stage,\n name,\n 'runtime exec remained unauthorized after auth refresh',\n second.error,\n ),\n )\n}\n\n// Decide whether an existing (reused or resumed) box is safe to hand back.\n// `refreshRuntimeConnection` has already polled for the runtime URL, so a box\n// that still has none never became connectable and must be recreated rather\n// than silently reused — downstream exec/terminal traffic would fail against\n// it. A failed edge is likewise unusable. Only when the connection is present\n// do we spend an exec round-trip on the liveness probe.\nasync function isReusableBox(\n box: SandboxInstance,\n harness: Harness,\n probe: LivenessProbeConfig | undefined,\n): Promise<boolean> {\n if (sandboxEdgeFailed(box)) return false\n if (!sandboxRuntimeUrl(box)) return false\n return isBoxAlive(box, harness, probe)\n}\n\n// Resume a stopped box and wait for it to reach running.\nasync function resumeStoppedBox(\n box: SandboxInstance,\n timeoutMs: number,\n onProgress?: (event: ProvisionEvent) => void,\n): Promise<Outcome<SandboxInstance>> {\n try {\n await box.resume()\n await box.waitFor('running', { timeoutMs, ...(onProgress ? { onProgress } : {}) })\n return ok(box)\n } catch (err) {\n return fail(err)\n }\n}\n\n/** Scope + the client and box key every workspace-scoped sandbox call needs.\n * One place resolves credentials and derives the box name, so the ensure and\n * peek paths cannot drift on which key a workspace's box lives under. */\nasync function resolveWorkspaceSandboxClient(\n shell: SandboxRuntimeConfig,\n workspaceId: string,\n userId: string | undefined,\n): Promise<{ scope: SandboxScope; client: Sandbox; name: string }> {\n const scope: SandboxScope = { workspaceId, ...(userId ? { userId } : {}) }\n const creds = await shell.credentials(scope)\n if (!creds) throw new Error('sandbox credentials are required (apiKey/baseUrl)')\n return {\n scope,\n client: getClientFromCreds(creds),\n name: shell.boxKey ? shell.boxKey(scope) : shell.name(workspaceId),\n }\n}\n\n/** What a peek can find. `not-running` carries the platform's own state string\n * (`stopped`, `starting`, `failed`, …) — narrowing it to a union here would\n * drop states the platform adds later, and every caller wants it for a log. */\nexport type PeekWorkspaceSandboxOutcome =\n | { status: 'running'; box: SandboxInstance }\n | { status: 'not-running'; state: string; box: SandboxInstance }\n | { status: 'absent' }\n\n/**\n * Read-only twin of {@link ensureWorkspaceSandbox}: report whether a\n * workspace's box exists and is running, WITHOUT provisioning, resuming, or\n * bootstrapping anything.\n *\n * This is what a read-mostly path needs — a file-index route's `authorize`\n * seam, a stale-lock reconciliation, a status badge. Calling `ensure` from one\n * of those spins a box up as a side effect of a read (legal-agent #509), and\n * costs the caller a cold start it never asked for.\n *\n * Matching is on BOTH the box key and the display name, IN THAT ORDER.\n * `client.get(id)` keys on the platform's opaque sandbox id, not the\n * deterministic key a product derives from a workspace, and is itself a\n * `list().find` underneath — so a lookup by identity has to list and match.\n * Provisioning here always stamps `name` with the box key, so the key is the\n * authoritative match; the display-name pass exists only to adopt boxes on a\n * host that predates that convention. The order matters: a single unordered\n * `find` returns whichever the platform happens to list first, so a stopped\n * display-name box could shadow a running box-key one and report\n * `not-running` for a live workspace.\n *\n * Unlike `ensure`, this lists ALL statuses in one call: distinguishing \"no box\"\n * from \"box is stopped\" is the whole point, and a status-filtered list cannot.\n *\n * A `client.list()` rejection propagates RAW, unlike the `Outcome`-wrapping\n * helpers `ensure` uses internally. That is deliberate: there is no honest\n * outcome to map a listing failure onto — it is not `absent` and not\n * `not-running`, and inventing one would have callers act on a status the\n * platform never reported. Callers that must tolerate it say so explicitly\n * (the stale-turn-lock policy documents \"a throw is treated as unreachable\").\n */\nexport async function peekWorkspaceSandbox(\n shell: SandboxRuntimeConfig,\n options: { workspaceId: string; userId?: string },\n): Promise<PeekWorkspaceSandboxOutcome> {\n const { client, name } = await resolveWorkspaceSandboxClient(shell, options.workspaceId, options.userId)\n const displayName = shell.name(options.workspaceId)\n const boxes = await client.list()\n const match = boxes.find((box) => box.name === name) ?? boxes.find((box) => box.name === displayName)\n if (!match) return { status: 'absent' }\n if (match.status !== 'running') return { status: 'not-running', state: match.status, box: match }\n return { status: 'running', box: match }\n}\n\nexport async function ensureWorkspaceSandbox(\n shell: SandboxRuntimeConfig,\n options: EnsureWorkspaceSandboxOptions,\n): Promise<SandboxInstance> {\n const { workspaceId, userId, harness, forceNew, onProgress, billingOwnerId } = options\n const resolved = await resolveWorkspaceSandboxClient(shell, workspaceId, userId)\n const { scope, client } = resolved\n let name = resolved.name\n let recoveryRestore: SandboxRestoreSpec | null | undefined\n const resources = shell.resources ?? DEFAULT_SANDBOX_RESOURCES\n const resumeTimeout = 120_000\n\n // Stage 1 — running-box reuse (skipped on forceNew).\n const existing = await listRunning(client, name)\n if (existing.succeeded && existing.value) {\n const found = existing.value\n if (forceNew) {\n const dropped = await deleteBox(found)\n if (!dropped.succeeded) {\n throw new Error(`forceNew: sandbox ${name} could not be deleted`, { cause: dropped.error })\n }\n } else if (found.metadata?.harness === harness) {\n const ready = await refreshRuntimeConnection(client, found)\n if (await isReusableBox(ready, harness, shell.livenessProbe)) {\n const written = await materializeDeferredFilesForExistingBox(\n shell,\n client,\n ready,\n 'reused',\n name,\n workspaceId,\n userId,\n )\n if (!written.succeeded) {\n throw deferredProfileWriteFailed('reused', name, written.error)\n }\n const reusedBox = written.value\n if (shell.bootstrap) {\n const boot = await shell.bootstrap(reusedBox, scope)\n if (!boot.succeeded) {\n throw new Error(`bootstrap failed on reused box ${name}`, { cause: boot.error })\n }\n }\n return reusedBox\n }\n const dropped = await deleteBox(ready)\n if (!dropped.succeeded) {\n throw new Error(\n `sandbox ${name} ` +\n `(was ${String(found.metadata?.harness ?? 'unknown')}, want ${harness}, or unresponsive) ` +\n `could not be deleted`,\n { cause: dropped.error },\n )\n }\n } else {\n const dropped = await deleteBox(found)\n if (!dropped.succeeded) {\n throw new Error(\n `sandbox ${name} ` +\n `(was ${String(found.metadata?.harness ?? 'unknown')}, want ${harness}, or unresponsive) ` +\n `could not be deleted`,\n { cause: dropped.error },\n )\n }\n }\n }\n\n // Stage 2 — stopped-box resume (skipped on forceNew or resumeStopped===false).\n if (!forceNew && shell.resumeStopped !== false) {\n const stopped = await listStopped(client, name)\n if (!stopped.succeeded) throw stopped.error\n if (stopped.value) {\n const resumed = await resumeStoppedBox(stopped.value, resumeTimeout, onProgress)\n if (!resumed.succeeded) {\n if (!shell.recoverStoppedSandbox) throw resumed.error\n const recovery = await shell.recoverStoppedSandbox({\n box: stopped.value,\n error: resumed.error,\n scope,\n boxKey: name,\n })\n if (!recovery.succeeded) throw recovery.error\n if (!recovery.value) throw resumed.error\n const replacementBoxKey = recovery.value.replacementBoxKey.trim()\n if (!replacementBoxKey || replacementBoxKey === name) {\n throw new Error(\n `stopped sandbox recovery must return a fresh replacement box key for ${name}`,\n { cause: resumed.error },\n )\n }\n name = replacementBoxKey\n recoveryRestore = recovery.value.restore\n } else {\n const box = await refreshRuntimeConnection(client, resumed.value)\n if (await isReusableBox(box, harness, shell.livenessProbe)) {\n const written = await materializeDeferredFilesForExistingBox(\n shell,\n client,\n box,\n 'resumed',\n name,\n workspaceId,\n userId,\n )\n if (!written.succeeded) {\n throw deferredProfileWriteFailed('resumed', name, written.error)\n }\n const resumedBox = written.value\n if (shell.bootstrap) {\n const boot = await shell.bootstrap(resumedBox, scope)\n if (!boot.succeeded) {\n throw new Error(`bootstrap failed on resumed box ${name}`, { cause: boot.error })\n }\n }\n return resumedBox\n }\n const dropped = await deleteBox(box)\n if (!dropped.succeeded) {\n throw new Error(\n `resumed sandbox ${name} ` +\n `(was ${String(box.metadata?.harness ?? 'unknown')}, want ${harness}, or unresponsive) ` +\n `could not be deleted`,\n { cause: dropped.error },\n )\n }\n }\n }\n }\n\n // Stage 3 — create fresh.\n const connectedIntegrationIds = await shell.connectedIntegrationIds(workspaceId)\n const buildCtx: SandboxBuildContext = {\n workspaceId,\n connectedIntegrationIds,\n ...(userId ? { userId } : {}),\n }\n const [secrets, env, files] = await Promise.all([\n shell.secrets(workspaceId),\n shell.env(buildCtx),\n shell.files(buildCtx),\n ])\n const fullProfile = shell.profile({ extraFiles: files })\n // When deferring, strip inline files from the create payload and write them\n // into the box after it reaches running. Keeps the provision body under the\n // orchestrator's 256 KiB cap and lands real files on disk.\n const { leanProfile, deferredFiles } = shell.deferProfileFiles\n ? splitDeferredProfileFiles(fullProfile)\n : { leanProfile: fullProfile, deferredFiles: [] as AgentProfileFileMount[] }\n const profile = leanProfile\n\n const role = userId && shell.permissionRole ? shell.permissionRole('developer') : undefined\n\n // Bake the model at create when opted in. childKeyMint overrides the apiKey\n // per-workspace; a typed mint failure falls through to the parent key (logged).\n let model = shell.backendModelAtCreate ? resolveModel(shell.provider) : undefined\n if (model && shell.childKeyMint && model.provider === 'openai-compat') {\n const minted = await shell.childKeyMint(scope)\n if (minted.succeeded) model = { ...model, apiKey: minted.value }\n else {\n console.error(\n `[sandbox] childKeyMint failed for ${workspaceId}; using parent key:`,\n minted.error.message,\n )\n }\n }\n\n const storage = shell.storage?.(buildCtx)\n const restore = recoveryRestore === undefined ? shell.restore?.(buildCtx) : recoveryRestore\n\n const payload = {\n name,\n image: resources.image,\n // Stamp the deferred-corpus hash so a later REUSE can skip re-writing an\n // unchanged skill corpus (materializeDeferredFilesForExistingBox reads it).\n metadata: {\n ...shell.metadata(harness),\n ...(deferredFiles.length > 0 ? { [DEFERRED_CORPUS_HASH_KEY]: deferredCorpusHash(deferredFiles) } : {}),\n },\n idempotencyKey: name,\n // Passed through untyped (the SDK payload type predates it); the platform\n // authz-gates it server-side and ignores it when unsupported.\n ...(billingOwnerId ? { billingOwnerId } : {}),\n ...(userId ? { permissions: { initialUsers: [{ userId, role }] } } : {}),\n env,\n secrets,\n backend: { type: harness, profile, ...(model ? { model } : {}) },\n ...(storage ? { storage } : {}),\n ...(restore ? restore : {}),\n ...(shell.webTerminalEnabled ? { webTerminalEnabled: true } : {}),\n maxLifetimeSeconds: resources.maxLifetimeSeconds,\n idleTimeoutSeconds: resources.idleTimeoutSeconds,\n resources: {\n cpuCores: resources.cpuCores,\n memoryMB: resources.memoryMB,\n diskGB: resources.diskGB,\n },\n } as CreatePayload\n\n // S-cost gates: an oversized env entry (E2BIG class) or an over-cap\n // provision body can never produce a working sandbox — fail loud here,\n // before the POST, with the offending section named.\n assertEnvWithinLimits(env)\n // `?? {}` only narrows the SDK parameter's `| undefined`; the literal above\n // is always defined. The structural sections type needs no cast.\n assertProvisionPayloadWithinCap(payload ?? {})\n\n let box = await client.create(payload)\n\n await box.waitFor('running', { timeoutMs: 120_000, ...(onProgress ? { onProgress } : {}) })\n box = await refreshRuntimeConnection(client, box)\n\n if (deferredFiles.length > 0) {\n const written = await writeProfileFilesToBox(box, deferredFiles)\n if (!written.succeeded) {\n throw deferredProfileWriteFailed('new', name, written.error)\n }\n }\n\n if (shell.bootstrap) {\n const boot = await shell.bootstrap(box, scope)\n if (!boot.succeeded) {\n throw new Error(`bootstrap failed on new box ${name}`, { cause: boot.error })\n }\n }\n return box\n}\n\nexport interface ResolvedModel {\n model: string\n provider: string\n // Omitted only under `allowKeylessModel` — keyless metadata tells the\n // sandbox platform to mint its own per-user router key for the box.\n apiKey?: string\n baseUrl?: string\n}\n\nexport function resolveModel(\n config: ProviderResolutionConfig | undefined,\n override?: { model?: string; modelApiKey?: string },\n): ResolvedModel | undefined {\n const c = config ?? {}\n const explicitBaseUrl = c.routerBaseUrl\n const explicitApiKey = override?.modelApiKey ?? c.apiKey\n const provider =\n c.providerName ?? (explicitApiKey ? 'openai-compat' : c.openaiApiKey ? 'openai' : undefined)\n const modelName =\n override?.model ??\n c.modelName ??\n (provider === 'openai' || provider === 'openai-compat' ? c.defaultModel : undefined)\n const apiKey = explicitApiKey ?? (provider === 'openai' ? c.openaiApiKey : undefined)\n if (!provider || !modelName) return undefined\n if (!apiKey && !c.allowKeylessModel) return undefined\n return {\n model: modelName,\n provider,\n ...(apiKey ? { apiKey } : {}),\n ...(explicitBaseUrl ? { baseUrl: explicitBaseUrl } : {}),\n }\n}\n\n// The SDK's SandboxInstance.streamPrompt/.prompt accept `string | PromptInputPart[]`\n// but the published package does not re-export the PromptInputPart type by name from\n// any of its entry points, so it's derived structurally off the method signature\n// itself — this stays in lockstep with the SDK's actual accepted shape.\nexport type PromptInputPart = Extract<\n Parameters<SandboxInstance['streamPrompt']>[0],\n readonly unknown[]\n>[number]\n\nfunction historyTranscript(\n history: Array<{ role: 'user' | 'assistant'; content: string }>,\n): string {\n return history\n .map((entry) => `${entry.role === 'assistant' ? 'Assistant' : 'User'}: ${entry.content}`)\n .join('\\n\\n')\n}\n\nexport function flattenHistory(\n message: string,\n history?: Array<{ role: 'user' | 'assistant'; content: string }>,\n): string {\n if (!history?.length) return message\n return `${historyTranscript(history)}\\n\\nUser: ${message}`\n}\n\n/**\n * History-aware equivalent of flattenHistory for multimodal prompt parts: the\n * transcript is folded into the first text part (image/file parts carry no\n * text to prepend to) rather than replacing the message wholesale.\n */\nexport function mergeHistoryIntoParts(\n parts: PromptInputPart[],\n history?: Array<{ role: 'user' | 'assistant'; content: string }>,\n): PromptInputPart[] {\n if (!history?.length) return parts\n const textIndex = parts.findIndex((part) => part.type === 'text')\n if (textIndex === -1) {\n throw new Error('mergeHistoryIntoParts requires at least one text part to carry the history')\n }\n const textPart = parts[textIndex] as Extract<PromptInputPart, { type: 'text' }>\n const merged = [...parts]\n merged[textIndex] = { ...textPart, text: `${historyTranscript(history)}\\n\\nUser: ${textPart.text}` }\n return merged\n}\n\nexport function mergeExtraMcp(\n appToolMcp: Record<string, AgentProfileMcpServer>,\n baseProfileMcp: Record<string, AgentProfileMcpServer>,\n extra: Record<string, AgentProfileMcpServer> | undefined,\n): Record<string, AgentProfileMcpServer> {\n for (const key of Object.keys(extra ?? {})) {\n if (key in appToolMcp || key in baseProfileMcp) {\n throw new Error(`extraMcp key '${key}' collides with an existing profile MCP server`)\n }\n }\n return { ...appToolMcp, ...(extra ?? {}) }\n}\n\nexport function attachReasoningEffort(\n profile: AgentProfile,\n harness: Harness,\n effort: 'auto' | 'low' | 'medium' | 'high' | undefined,\n): AgentProfile {\n if (!effort || effort === 'auto') return profile\n return {\n ...profile,\n extensions: {\n ...(profile.extensions ?? {}),\n [harness]: {\n ...(profile.extensions?.[harness] ?? {}),\n reasoningEffort: effort,\n },\n },\n }\n}\n\nexport interface StreamSandboxPromptOptions {\n sessionId?: string\n executionId?: string\n lastEventId?: string\n systemPrompt?: string\n model?: string\n modelApiKey?: string\n history?: Array<{ role: 'user' | 'assistant'; content: string }>\n harness?: Harness\n effort?: 'auto' | 'low' | 'medium' | 'high'\n appToolMcp?: Record<string, AgentProfileMcpServer>\n baseProfileMcp?: Record<string, AgentProfileMcpServer>\n extraMcp?: Record<string, AgentProfileMcpServer>\n signal?: AbortSignal\n timeoutMs?: number\n requireVisibleAssistantOutput?: boolean\n // When true, an interactive question event throws instead of yielding —\n // detached (cron/mission-step) runs have no consumer to answer it.\n disallowQuestions?: boolean\n // Per-turn question/permission/plan channel toggles, forwarded VERBATIM into the\n // backend config. agent-app does not validate kinds per harness — the sidecar fails\n // session init loudly for unsupported ones; a local matrix would drift. Only honored\n // on the streaming path; the detached driveTurn path (driveSandboxTurn) never sets it.\n interactions?: { question?: boolean; permission?: boolean; plan?: boolean }\n // Detach the run from THIS stream's lifetime. When true, dropping the stream —\n // a Worker/isolate restart, a browser refresh, a network blip — does NOT cancel\n // the run: the platform keeps executing it server-side and buffers its events,\n // so a later reconnect (same `sessionId` + `lastEventId`) replays the tail and\n // the run's result survives. This is what makes a WATCHED interactive turn\n // durable — the run no longer dies with the Worker that opened it — while still\n // streaming live (unlike the fire-and-forget `dispatchPrompt`/`driveTurn` path).\n // Omit for a run where closing the tab should stop burning tokens.\n detach?: boolean\n}\n\ntype StreamPromptOptions = Parameters<SandboxInstance['streamPrompt']>[1]\n\nexport async function* streamSandboxPrompt(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string | PromptInputPart[],\n options?: StreamSandboxPromptOptions,\n): AsyncGenerator<unknown> {\n const harness = options?.harness ?? 'opencode'\n const model = resolveModel(shell.provider, {\n model: options?.model,\n modelApiKey: options?.modelApiKey,\n })\n\n // Server-side enforcement of the harness↔model policy: a vendor-locked harness\n // (claude-code/codex/kimi-code) must not be sent a foreign-provider model, even\n // if the UI snap was bypassed. Provider-less ids pass (session's own config).\n if (model?.model) assertHarnessModelCompatible(harness, model.model)\n\n const prompt =\n typeof message === 'string'\n ? flattenHistory(message, options?.history)\n : mergeHistoryIntoParts(message, options?.history)\n\n const appToolMcp = options?.appToolMcp ?? {}\n const extraMcp = mergeExtraMcp(appToolMcp, options?.baseProfileMcp ?? {}, options?.extraMcp)\n\n const profile = shell.profile({ systemPrompt: options?.systemPrompt, extraMcp })\n const profileWithEffort = attachReasoningEffort(profile, harness, options?.effort)\n\n const stream = box.streamPrompt(prompt, {\n sessionId: options?.sessionId,\n executionId: options?.executionId,\n lastEventId: options?.lastEventId,\n ...(options?.signal ? { signal: options.signal } : {}),\n ...(options?.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n ...(options?.requireVisibleAssistantOutput !== undefined\n ? { requireVisibleAssistantOutput: options.requireVisibleAssistantOutput }\n : {}),\n ...(options?.detach ? { detach: true } : {}),\n backend: {\n type: harness,\n profile: profileWithEffort,\n ...(model ? { model } : {}),\n ...(options?.interactions ? { interactions: options.interactions } : {}),\n },\n } as StreamPromptOptions)\n\n let severedFinishReason: string | null = null\n for await (const event of stream) {\n const step = classifySeveredStream(event)\n if (step) severedFinishReason = step.kind === 'step-finish' && step.severed ? step.reason : null\n if (severedFinishReason && isTerminalPromptEvent(event)) {\n throw new Error(`sandbox model stream severed mid-turn (reason=\"${severedFinishReason}\")`)\n }\n if (options?.disallowQuestions) {\n const q = detectInteractiveQuestion(event)\n if (q) {\n throw new Error(`sandbox agent asked an interactive question during an autonomous run: ${q}`)\n }\n }\n yield event\n }\n // Reconnect-exhausted path: the stream ended on a severed step without a\n // terminal event. A truncated turn must fail loud, not return silently.\n if (severedFinishReason) {\n throw new Error(`sandbox model stream severed mid-turn (reason=\"${severedFinishReason}\")`)\n }\n}\n\nexport async function runSandboxPrompt(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string | PromptInputPart[],\n options?: StreamSandboxPromptOptions,\n): Promise<string> {\n let fullText = ''\n let firstTextSeen = false\n\n for await (const rawEvent of streamSandboxPrompt(shell, box, message, options)) {\n const event = rawEvent as { type?: string; data?: Record<string, unknown> }\n if (!event.type) continue\n\n if (event.type === 'message.part.updated') {\n const part = event.data?.part as Record<string, unknown> | undefined\n const delta = typeof event.data?.delta === 'string' ? event.data.delta : null\n if (String(part?.type ?? '') === 'text') {\n if (!firstTextSeen) {\n firstTextSeen = true\n continue\n }\n if (delta) fullText += delta\n else if (typeof part?.text === 'string') fullText = part.text\n }\n } else if (event.type === 'result') {\n const finalText = typeof event.data?.finalText === 'string' ? event.data.finalText : null\n if (finalText) fullText = finalText\n }\n }\n\n return fullText\n}\n\n// Mirrors the SDK's PermissionLevel union (not re-exported by\n// @tangle-network/sandbox). The product's role-mapping seam must produce one of\n// these; binding the seam's return type to the union makes a wrong mapping a\n// compile error rather than a runtime 400 from the orchestrator.\nexport type SandboxPermissionLevel = 'owner' | 'admin' | 'developer' | 'viewer'\n\nexport interface MemberSyncSeam {\n roleToSandboxRole: (workspaceRole: string) => SandboxPermissionLevel\n}\n\nexport async function syncSandboxMemberAdd(\n box: SandboxInstance,\n seam: MemberSyncSeam,\n userId: string,\n role: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.add({ userId, role: seam.roleToSandboxRole(role) })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function syncSandboxMemberRemove(\n box: SandboxInstance,\n userId: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.remove(userId, { preserveHomeDir: true })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function syncSandboxMemberRole(\n box: SandboxInstance,\n seam: MemberSyncSeam,\n userId: string,\n role: string,\n): Promise<Outcome<void>> {\n try {\n await box.permissions.update(userId, { role: seam.roleToSandboxRole(role) })\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport interface SecretStore {\n create: (name: string, value: string) => Promise<void>\n update: (name: string, value: string) => Promise<void>\n get: (name: string) => Promise<string>\n delete: (name: string) => Promise<void>\n}\n\nexport function secretStoreFromClient(shell: SandboxRuntimeConfig): SecretStore {\n const client = getClient(shell)\n return {\n create: async (name, value) => {\n await client.secrets.create(name, value)\n },\n update: async (name, value) => {\n await client.secrets.update(name, value)\n },\n get: (name) => client.secrets.get(name),\n delete: async (name) => {\n await client.secrets.delete(name)\n },\n }\n}\n\nexport async function storeSecret(\n store: SecretStore,\n name: string,\n value: string,\n): Promise<Outcome<void>> {\n try {\n await store.create(name, value)\n return ok(undefined)\n } catch {\n try {\n await store.update(name, value)\n return ok(undefined)\n } catch (err) {\n return fail(new Error(`Failed to store sandbox secret ${name}`, { cause: err }))\n }\n }\n}\n\nexport async function readSecret(store: SecretStore, name: string): Promise<Outcome<string>> {\n try {\n return ok(await store.get(name))\n } catch (err) {\n return fail(err)\n }\n}\n\nexport async function deleteSecret(store: SecretStore, name: string): Promise<Outcome<void>> {\n try {\n await store.delete(name)\n return ok(undefined)\n } catch (err) {\n return fail(err)\n }\n}\n\nexport interface ScopedTokenResult {\n token: string\n expiresAt: Date\n scope: ScopedTokenScope\n}\n\n/**\n * Mint a scoped token for an already-provisioned box (e.g. to hand a terminal\n * proxy a narrowed credential). Uses the SDK's native `box.mintScopedToken`,\n * which normalizes `expiresAt` to a Date — no hand-rolled wire call.\n */\nexport async function mintSandboxScopedToken(\n box: SandboxInstance,\n options: { scope: ScopedTokenScope; sessionId?: string; ttlMinutes?: number },\n): Promise<Outcome<ScopedTokenResult>> {\n try {\n const token = await box.mintScopedToken({\n scope: options.scope,\n ...(options.sessionId ? { sessionId: options.sessionId } : {}),\n ...(options.ttlMinutes ? { ttlMinutes: options.ttlMinutes } : {}),\n })\n return ok({ token: token.token, expiresAt: token.expiresAt, scope: token.scope })\n } catch (err) {\n return fail(err)\n }\n}\n\nexport interface DriveSandboxTurnOptions extends StreamSandboxPromptOptions {\n /** Deterministic resume key — required. Every tick for the same logical turn\n * MUST reuse it so a crash + re-drive finds the in-flight session instead of\n * starting a second agent run. */\n sessionId: string\n /** Turn idempotency key for the platform's completed-turn cache. Defaults to\n * `sessionId` (correct for the one-turn-per-session shape detached drivers use). */\n turnId?: string\n /** Wall-clock cap in ms from the session's start. A still-running session past\n * the cap is cancelled and reported `failed` — bounds an unattended run (e.g. a\n * turn that stalled on an interactive question nothing will answer). Omit for no cap. */\n wallCapMs?: number\n}\n\n// One settle → poll → dispatch pass over a detached turn. Delegates to the SDK's\n// `box.driveTurn` (@tangle-network/sandbox ≥ 0.10.5) — the turn runs\n// fire-and-detached server-side and ONE invocation returns immediately with where\n// it stands. It never awaits the whole turn in-process, so it does not hold the\n// worker alive for the run's duration (the durability trap the older box.prompt\n// implementation quietly caused).\n//\n// This is the durable path for cron / mission-step / queue callers: re-invoke on\n// your own schedule (Workflow step, DO alarm, queue tick) with the SAME\n// `sessionId`. Dispatch is idempotent on it, so a crash + re-drive is a lookup,\n// not a second agent run.\n//\n// The Outcome boundary separates a retryable transport failure from a settled\n// turn: `fail` means the drive call itself threw (network blip — retry the tick);\n// `ok` carries the SDK's discriminated `TurnDriveResult` — inspect `.state`:\n// - `running` → the turn is still executing; re-tick after a delay of your choosing.\n// - `completed` → terminal; `.text` / `.result` hold the payload.\n// - `failed` → terminal and deterministic; re-invoking will not change it (do not retry).\nexport async function driveSandboxTurn(\n shell: SandboxRuntimeConfig,\n box: SandboxInstance,\n message: string | PromptInputPart[],\n options: DriveSandboxTurnOptions,\n): Promise<Outcome<TurnDriveResult>> {\n const harness = options.harness ?? 'opencode'\n const model = resolveModel(shell.provider, {\n model: options.model,\n modelApiKey: options.modelApiKey,\n })\n if (model?.model) assertHarnessModelCompatible(harness, model.model)\n const prompt =\n typeof message === 'string'\n ? flattenHistory(message, options.history)\n : mergeHistoryIntoParts(message, options.history)\n const appToolMcp = options.appToolMcp ?? {}\n const extraMcp = mergeExtraMcp(appToolMcp, options.baseProfileMcp ?? {}, options.extraMcp)\n const profile = attachReasoningEffort(\n shell.profile({ systemPrompt: options.systemPrompt, extraMcp }),\n harness,\n options.effort,\n )\n try {\n const drive = await box.driveTurn(prompt, {\n sessionId: options.sessionId,\n ...(options.turnId ? { turnId: options.turnId } : {}),\n ...(options.wallCapMs !== undefined ? { wallCapMs: options.wallCapMs } : {}),\n ...(options.executionId ? { executionId: options.executionId } : {}),\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n ...(options.signal ? { signal: options.signal } : {}),\n // Deliberately NO `interactions` here: detached turns (cron / mission steps) have\n // no consumer to answer a question. Interactive Q&A is streaming-path only.\n backend: { type: harness, profile, ...(model ? { model } : {}) },\n } as Parameters<SandboxInstance['driveTurn']>[1])\n return ok(drive)\n } catch (err) {\n return fail(err)\n }\n}\n\n// Severed-stream classifier. Generic to any router-backed harness: a final step\n// that finished with error/other/unknown is a truncated turn, not a completed one.\nconst SEVERED_FINISH_REASONS = new Set(['error', 'other', 'unknown'])\n\nexport type SandboxStepTransition =\n | { kind: 'step-start' }\n | { kind: 'step-finish'; reason: string; severed: boolean }\n\nfunction asPlainRecord(v: unknown): Record<string, unknown> | null {\n return v && typeof v === 'object' && !Array.isArray(v) ? (v as Record<string, unknown>) : null\n}\n\nexport function classifySeveredStream(event: unknown): SandboxStepTransition | null {\n const root = asPlainRecord(event)\n if (!root || root.type !== 'message.part.updated') return null\n const body = asPlainRecord(root.properties) ?? asPlainRecord(root.data) ?? root\n const part = asPlainRecord(body.part)\n if (!part) return null\n if (part.type === 'step-start') return { kind: 'step-start' }\n if (part.type !== 'step-finish') return null\n const reason = typeof part.reason === 'string' && part.reason ? part.reason : 'unknown'\n return { kind: 'step-finish', reason, severed: SEVERED_FINISH_REASONS.has(reason) }\n}\n\nexport function isTerminalPromptEvent(event: unknown): boolean {\n const t = asPlainRecord(event)?.type\n return t === 'result' || t === 'done'\n}\n\n// Interactive-question detector. Returns the question text or null. Used by\n// streamSandboxPrompt when disallowQuestions is set.\nexport function detectInteractiveQuestion(event: unknown): string | null {\n const root = asPlainRecord(event)\n if (!root) return null\n const type = typeof root.type === 'string' ? root.type : undefined\n const data = asPlainRecord(root.data)\n const props = asPlainRecord(root.properties)\n const body = props ?? data ?? root\n if (type === 'question.asked' || type === 'question') return firstQuestionText(body)\n // Generic structured-interaction event (BackendConfig.interactions kinds surface as\n // `interaction` events with a `kind` discriminator); treat kind:\"question\" as a question.\n if (type === 'interaction' && body.kind === 'question') return firstQuestionText(body)\n const part = asPlainRecord(data?.part) ?? asPlainRecord(body.part)\n const tool =\n (typeof part?.tool === 'string' && part.tool) ||\n (typeof part?.name === 'string' && part.name) ||\n (typeof body.tool === 'string' && body.tool) ||\n undefined\n const isQ =\n type === 'message.part.updated' &&\n (tool === 'question' || asPlainRecord(part)?.type === 'question')\n if (!isQ) return null\n const state = asPlainRecord(asPlainRecord(part)?.state)\n return firstQuestionText(asPlainRecord(state?.input) ?? state ?? part ?? body)\n}\n\nfunction firstQuestionText(value: Record<string, unknown> | null): string {\n const arr = Array.isArray(value?.questions)\n ? value!.questions\n : Array.isArray(asPlainRecord(value?.input)?.questions)\n ? (asPlainRecord(value!.input)!.questions as unknown[])\n : []\n const first = asPlainRecord(arr[0])\n const q =\n (typeof first?.question === 'string' && first.question) ||\n (typeof first?.prompt === 'string' && first.prompt) ||\n undefined\n return q ?? 'interactive question'\n}\n// Workspace sandbox terminal handlers: WebSocket upgrade proxy, connection\n// + runtime-proxy handlers, and scoped terminal-token mint/verify.\nexport * from './terminal-proxy-token'\nexport * from './workspace-terminal'\n","// Shared Outcome triple for the sandbox modules. Lives in a dependency-free\n// leaf so both index.ts and terminal-proxy-token.ts import it instead of\n// re-declaring the type (index.ts re-exports * from terminal-proxy-token, so\n// the token module cannot import from index without a cycle).\nexport type Outcome<T> =\n | { succeeded: true; value: T }\n | { succeeded: false; error: Error }\n\nexport const ok = <T>(value: T): Outcome<T> => ({ succeeded: true, value })\nexport const fail = (error: unknown): Outcome<never> => ({\n succeeded: false,\n error: error instanceof Error ? error : new Error(String(error)),\n})\n","/**\n * Reading arbitrary bytes out of a sandbox over an exec channel that only\n * speaks text.\n *\n * `box.exec` returns stdout as a string, so a binary file has to be encoded to\n * survive the trip: `wc -c` gives the on-disk length, `base64` gives the\n * payload, and the decoded byte count is checked against the stat. That last\n * check is the point of the module — an exec channel that caps or clips its\n * output still reports `exitCode: 0` with a short buffer, which decodes into a\n * perfectly valid but TRUNCATED file. Verifying the length turns that silent\n * corruption into a loud failure at the boundary.\n *\n * Both helpers return typed outcomes; callers must inspect `succeeded` before\n * touching `value`.\n */\n\n/** The `box.exec` surface these helpers use — structural, so a caller can pass\n * the sandbox SDK's `SandboxInstance` directly or a narrower test double. */\nexport interface SandboxExecChannel {\n exec(\n command: string,\n options?: { sessionId?: string },\n ): Promise<{ stdout: string; stderr: string; exitCode: number }>\n}\n\nexport interface SandboxExecOptions {\n /** Run inside a named session rather than the box's default one. */\n sessionId?: string\n}\n\nexport type SandboxFileSizeOutcome =\n | { succeeded: true; value: number }\n | { succeeded: false; error: string }\n\nexport type SandboxFileBytesOutcome =\n | { succeeded: true; value: { bytes: Uint8Array; size: number } }\n | { succeeded: false; error: string }\n\n/** Wraps a value in single quotes for `sh`, closing and reopening the quote\n * around each embedded quote (`'` → `'\"'\"'`). Every path these helpers\n * interpolate into a command goes through this — in-box filenames are\n * arbitrary, so spaces, quotes and `$` are ordinary content, not syntax. */\nexport function shellQuote(value: string): string {\n return `'${value.replaceAll(\"'\", `'\"'\"'`)}'`\n}\n\n/** Decodes with `atob` rather than `Buffer.from(s, 'base64')`: Buffer SKIPS\n * characters outside the alphabet, so a corrupted payload would decode to\n * something plausible instead of throwing. */\nfunction base64ToBytes(base64: string): Uint8Array {\n const binary = atob(base64)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i)\n return bytes\n}\n\nfunction execInSandbox(box: SandboxExecChannel, command: string, options?: SandboxExecOptions) {\n return options?.sessionId ? box.exec(command, { sessionId: options.sessionId }) : box.exec(command)\n}\n\n/** Stats a sandbox file's byte length via `wc -c`. A caller enforcing a size\n * cap must check this BEFORE {@link readSandboxBinaryBytes}, so an oversize\n * file is rejected without paying for a base64 round trip of it. */\nexport async function statSandboxFileSize(\n box: SandboxExecChannel,\n absolutePath: string,\n options?: SandboxExecOptions,\n): Promise<SandboxFileSizeOutcome> {\n const quotedPath = shellQuote(absolutePath)\n let result\n try {\n result = await execInSandbox(box, `wc -c < ${quotedPath}`, options)\n } catch (err) {\n return { succeeded: false, error: err instanceof Error ? err.message : String(err) }\n }\n if (result.exitCode !== 0) {\n return { succeeded: false, error: result.stderr || 'unknown error' }\n }\n const size = Number.parseInt(result.stdout.trim(), 10)\n if (!Number.isFinite(size)) {\n return { succeeded: false, error: `could not parse file size from \"${result.stdout.trim()}\"` }\n }\n return { succeeded: true, value: size }\n}\n\n/** Reads a sandbox file as base64 and decodes it, verifying the decoded byte\n * length against `expectedSize` (from a prior {@link statSandboxFileSize}). A\n * mismatch is reported, never returned as a short buffer. */\nexport async function readSandboxBinaryBytes(\n box: SandboxExecChannel,\n absolutePath: string,\n expectedSize: number,\n options?: SandboxExecOptions,\n): Promise<SandboxFileBytesOutcome> {\n const quotedPath = shellQuote(absolutePath)\n let result\n try {\n result = await execInSandbox(box, `base64 ${quotedPath}`, options)\n } catch (err) {\n return { succeeded: false, error: err instanceof Error ? err.message : String(err) }\n }\n if (result.exitCode !== 0) {\n return { succeeded: false, error: result.stderr || 'unknown error' }\n }\n // GNU coreutils wraps base64 output at 76 columns; BusyBox may not wrap at\n // all. Stripping all whitespace makes both shapes decode identically.\n const cleaned = result.stdout.replace(/\\s+/g, '')\n let bytes: Uint8Array\n try {\n bytes = base64ToBytes(cleaned)\n } catch (err) {\n return {\n succeeded: false,\n error: `could not decode file contents: ${err instanceof Error ? err.message : String(err)}`,\n }\n }\n if (bytes.byteLength !== expectedSize) {\n return {\n succeeded: false,\n error: `read returned ${bytes.byteLength} bytes, expected ${expectedSize} — output truncated in transit`,\n }\n }\n return { succeeded: true, value: { bytes, size: expectedSize } }\n}\n","import {\n base64UrlDecodeText,\n base64UrlEncodeText,\n constantTimeEqual,\n hmacSha256Base64Url,\n} from '../crypto/web-token'\nimport { ok, fail, type Outcome } from './outcome'\n\n// Terminal-proxy HMAC token. Identity tuple is generic; the secret comes from a\n// closure (fail-loud if absent).\nexport interface TerminalProxyIdentity {\n userId: string\n workspaceId: string\n sandboxId: string\n}\n\nconst TERMINAL_PROXY_TOKEN_TTL_MS = 15 * 60 * 1000\n\nexport async function mintTerminalProxyToken(\n secret: string,\n identity: TerminalProxyIdentity,\n ttlMs = TERMINAL_PROXY_TOKEN_TTL_MS,\n now: () => number = Date.now,\n): Promise<Outcome<{ token: string; expiresAt: Date }>> {\n if (!secret) return fail(new Error('mintTerminalProxyToken: secret is required'))\n if (!identity.userId || !identity.workspaceId || !identity.sandboxId) {\n return fail(new Error('mintTerminalProxyToken: userId/workspaceId/sandboxId are required'))\n }\n const expiresAt = new Date(now() + ttlMs)\n const payload = { ...identity, exp: Math.floor(expiresAt.getTime() / 1000) }\n const encoded = base64UrlEncodeText(JSON.stringify(payload))\n const sig = await hmacSha256Base64Url(encoded, secret)\n return ok({ token: `${encoded}.${sig}`, expiresAt })\n}\n\nexport async function verifyTerminalProxyToken(\n secret: string,\n token: string,\n expected: TerminalProxyIdentity,\n now: () => number = Date.now,\n): Promise<boolean> {\n if (!secret) return false\n const [encoded, sig, extra] = token.split('.')\n if (!encoded || !sig || extra !== undefined) return false\n const expectedSig = await hmacSha256Base64Url(encoded, secret)\n if (!constantTimeEqual(sig, expectedSig)) return false\n let payload: TerminalProxyIdentity & { exp: number }\n try {\n payload = JSON.parse(base64UrlDecodeText(encoded))\n } catch {\n return false\n }\n return (\n payload.userId === expected.userId &&\n payload.workspaceId === expected.workspaceId &&\n payload.sandboxId === expected.sandboxId &&\n Number.isFinite(payload.exp) &&\n payload.exp > Math.floor(now() / 1000)\n )\n}\n","import { base64UrlDecodeText } from '../crypto/web-token'\nimport {\n mintTerminalProxyToken,\n verifyTerminalProxyToken,\n type TerminalProxyIdentity,\n} from './terminal-proxy-token'\n\nexport interface WorkspaceSandboxInstanceLike {\n id: string\n name?: string\n status?: string\n connection?: {\n runtimeUrl?: string\n sidecarUrl?: string\n authToken?: string\n sidecarToken?: string\n authTokenExpiresAt?: string\n } | null\n}\n\n// Generic name-keyed sandbox lifecycle manager. A structural, substrate-free\n// helper for products that drive their own SDK/box types (distinct from the\n// concrete `ensureWorkspaceSandbox` in ./index, which is bound to the\n// @tangle-network/sandbox client). Kept as a public export — external\n// consumers compose it; removing it would be a breaking change.\nexport interface WorkspaceSandboxEnsureContext {\n workspaceId: string\n userId: string\n}\n\nexport interface WorkspaceSandboxManagerOptions<TClient, TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void> {\n getClient: (ctx: WorkspaceSandboxEnsureContext) => Promise<TClient> | TClient\n nameForWorkspace: (workspaceId: string, ctx: WorkspaceSandboxEnsureContext) => string\n listSandboxes: (client: TClient, ctx: WorkspaceSandboxEnsureContext) => Promise<TBox[]>\n createSandbox: (args: {\n client: TClient\n ctx: WorkspaceSandboxEnsureContext\n name: string\n options: TEnsureOptions\n listError?: unknown\n }) => Promise<TBox>\n waitForRunning?: (box: TBox, ctx: WorkspaceSandboxEnsureContext) => Promise<void>\n prepareExisting?: (box: TBox, ctx: WorkspaceSandboxEnsureContext, options: TEnsureOptions) => Promise<TBox | void>\n prepareCreated?: (box: TBox, ctx: WorkspaceSandboxEnsureContext, options: TEnsureOptions) => Promise<TBox | void>\n onListError?: (error: unknown, ctx: WorkspaceSandboxEnsureContext) => void\n}\n\nexport interface WorkspaceSandboxManager<TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void> {\n ensureWorkspaceSandbox: (\n workspaceId: string,\n userId: string,\n options?: TEnsureOptions,\n ) => Promise<TBox>\n}\n\nexport function createWorkspaceSandboxManager<TClient, TBox extends WorkspaceSandboxInstanceLike, TEnsureOptions = void>(\n opts: WorkspaceSandboxManagerOptions<TClient, TBox, TEnsureOptions>,\n): WorkspaceSandboxManager<TBox, TEnsureOptions> {\n return {\n async ensureWorkspaceSandbox(workspaceId, userId, options) {\n if (!workspaceId) throw new Error('workspaceId is required')\n if (!userId) throw new Error('userId is required')\n const ctx = { workspaceId, userId }\n const client = await opts.getClient(ctx)\n const name = opts.nameForWorkspace(workspaceId, ctx)\n let listError: unknown\n let existing: TBox[] = []\n\n try {\n existing = await opts.listSandboxes(client, ctx)\n } catch (err) {\n listError = err\n opts.onListError?.(err, ctx)\n }\n\n const found = existing.find((box) => box.name === name)\n if (found) {\n return (await opts.prepareExisting?.(found, ctx, options as TEnsureOptions)) ?? found\n }\n\n const created = await opts.createSandbox({\n client,\n ctx,\n name,\n options: options as TEnsureOptions,\n listError,\n })\n await opts.waitForRunning?.(created, ctx)\n return (await opts.prepareCreated?.(created, ctx, options as TEnsureOptions)) ?? created\n },\n }\n}\n\nexport interface SandboxTerminalTokenOptions {\n secret?: string\n expiresInMs?: number\n now?: () => number\n}\n\nexport type SandboxTerminalTokenSubject = TerminalProxyIdentity\n\nexport interface SandboxTerminalTokenResult {\n token: string\n expiresAt: Date\n}\n\nconst DEFAULT_TERMINAL_TOKEN_TTL_MS = 15 * 60 * 1000\nconst BEARER_SUBPROTOCOL_PREFIX = 'bearer.'\n// Legacy `createSandboxTerminalToken` (pre proxy-token extraction) prefixed\n// minted tokens with `sbxt_` and signed the unprefixed payload. New tokens\n// carry no prefix. Strip it on verify so tokens minted by a prior deploy still\n// validate within their (default 15-min) TTL window — avoids a wave of 403s on\n// in-flight browser terminal sessions right after rollout.\nconst LEGACY_TERMINAL_TOKEN_PREFIX = 'sbxt_'\n\nexport async function createSandboxTerminalToken(\n subject: SandboxTerminalTokenSubject,\n opts: SandboxTerminalTokenOptions,\n): Promise<SandboxTerminalTokenResult> {\n validateTerminalSubject(subject)\n const secret = opts.secret?.trim()\n if (!secret) throw new Error('terminal token secret is required')\n const now = opts.now ?? Date.now\n const expiresInMs = opts.expiresInMs ?? DEFAULT_TERMINAL_TOKEN_TTL_MS\n if (!Number.isFinite(expiresInMs) || expiresInMs <= 0) throw new Error('expiresInMs must be a positive number')\n const minted = await mintTerminalProxyToken(secret, subject, expiresInMs, now)\n if (!minted.succeeded) throw minted.error\n return minted.value\n}\n\nexport async function verifySandboxTerminalToken(\n token: string,\n expected: SandboxTerminalTokenSubject,\n opts: SandboxTerminalTokenOptions,\n): Promise<boolean> {\n validateTerminalSubject(expected)\n const secret = opts.secret?.trim()\n const now = opts.now ?? Date.now\n const normalized = token.startsWith(LEGACY_TERMINAL_TOKEN_PREFIX)\n ? token.slice(LEGACY_TERMINAL_TOKEN_PREFIX.length)\n : token\n return verifyTerminalProxyToken(secret ?? '', normalized, expected, now)\n}\n\nexport interface AuthenticatedSandboxUser {\n id: string\n}\n\nexport interface WorkspaceSandboxConnectionHandlerOptions<TBox extends WorkspaceSandboxInstanceLike> {\n requireUser: (request: Request) => Promise<AuthenticatedSandboxUser>\n requireWorkspaceAccess: (args: { request: Request; userId: string; workspaceId: string }) => Promise<void>\n ensureWorkspaceSandbox: (workspaceId: string, userId: string) => Promise<TBox>\n tokenSecret: string | (() => string | undefined)\n tokenExpiresInMs?: number\n proxyRuntimeUrl?: (args: { request: Request; workspaceId: string; sandboxId: string; box: TBox }) => string\n exposeDirectSidecar?: boolean\n}\n\nexport interface WorkspaceSandboxConnectionArgs {\n request: Request\n params: {\n workspaceId?: string\n }\n}\n\nexport function createWorkspaceSandboxConnectionHandler<TBox extends WorkspaceSandboxInstanceLike>(\n opts: WorkspaceSandboxConnectionHandlerOptions<TBox>,\n) {\n return async function handleWorkspaceSandboxConnection({ request, params }: WorkspaceSandboxConnectionArgs): Promise<Response> {\n const user = await opts.requireUser(request)\n const workspaceId = params.workspaceId\n if (!workspaceId) return Response.json({ error: 'workspaceId is required' }, { status: 400 })\n await opts.requireWorkspaceAccess({ request, userId: user.id, workspaceId })\n\n let box: TBox\n try {\n box = await opts.ensureWorkspaceSandbox(workspaceId, user.id)\n } catch (err) {\n return Response.json(\n { error: err instanceof Error ? err.message : 'Failed to provision workspace sandbox' },\n { status: 500 },\n )\n }\n\n const directSidecarUrl = box.connection?.sidecarUrl ?? box.connection?.runtimeUrl\n const directSidecarToken = box.connection?.authToken ?? box.connection?.sidecarToken\n const directSidecarExpiresAt = box.connection?.authTokenExpiresAt\n if (opts.exposeDirectSidecar && directSidecarUrl && directSidecarToken && directSidecarExpiresAt) {\n return Response.json({\n runtimeUrl: directSidecarUrl,\n sidecarUrl: directSidecarUrl,\n token: directSidecarToken,\n expiresAt: directSidecarExpiresAt,\n status: box.status,\n sandboxId: box.id,\n })\n }\n\n if (!directSidecarUrl) {\n return Response.json(\n {\n error: 'Workspace sandbox runtime not ready. The sandbox is still initializing -- retry in a few seconds.',\n status: box.status,\n },\n { status: 503 },\n )\n }\n\n const secret = typeof opts.tokenSecret === 'function' ? opts.tokenSecret() : opts.tokenSecret\n let scoped: SandboxTerminalTokenResult\n try {\n scoped = await createSandboxTerminalToken(\n { userId: user.id, workspaceId, sandboxId: box.id },\n { secret, expiresInMs: opts.tokenExpiresInMs },\n )\n } catch (err) {\n return Response.json(\n { error: err instanceof Error ? err.message : 'Failed to mint sandbox token' },\n { status: 503 },\n )\n }\n\n const runtimeUrl = opts.proxyRuntimeUrl\n ? opts.proxyRuntimeUrl({ request, workspaceId, sandboxId: box.id, box })\n : `/api/workspaces/${encodeURIComponent(workspaceId)}/sandbox/runtime/${encodeURIComponent(box.id)}`\n\n return Response.json({\n runtimeUrl,\n sidecarUrl: runtimeUrl,\n token: scoped.token,\n expiresAt: scoped.expiresAt.toISOString(),\n status: box.status,\n sandboxId: box.id,\n })\n }\n}\n\nexport interface SandboxApiCredentials {\n baseUrl: string\n apiKey: string\n}\n\nexport interface SandboxRuntimeConnection {\n runtimeUrl: string\n /** Server-side sidecar bearer. Must authorize terminal routes; never expose it to browser code. */\n authToken?: string\n}\n\nexport interface WorkspaceSandboxRuntimeProxyHandlerOptions {\n requireUser: (request: Request) => Promise<AuthenticatedSandboxUser>\n requireWorkspaceAccess: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<void>\n getSandboxApiCredentials: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<SandboxApiCredentials>\n getSandboxRuntimeConnection?: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<SandboxRuntimeConnection | null | undefined>\n tokenSecret: string | (() => string | undefined)\n fetch?: typeof fetch\n forwardHeaders?: string[]\n}\n\nexport interface WorkspaceSandboxRuntimeProxyArgs {\n request: Request\n params: {\n workspaceId?: string\n sandboxId?: string\n '*'?: string\n }\n}\n\nexport function createWorkspaceSandboxRuntimeProxyHandler(opts: WorkspaceSandboxRuntimeProxyHandlerOptions) {\n return async function handleWorkspaceSandboxRuntimeProxy({ request, params }: WorkspaceSandboxRuntimeProxyArgs): Promise<Response> {\n const user = await opts.requireUser(request)\n const workspaceId = params.workspaceId\n const sandboxId = params.sandboxId\n const runtimePath = params['*']\n if (!workspaceId || !sandboxId || !runtimePath) {\n return Response.json({ error: 'workspaceId, sandboxId, and runtime path are required' }, { status: 400 })\n }\n const encodedRuntimePath = encodeSandboxRuntimePath(runtimePath)\n if (!encodedRuntimePath) return Response.json({ error: 'Invalid sandbox runtime path' }, { status: 400 })\n\n await opts.requireWorkspaceAccess({ request, userId: user.id, workspaceId, sandboxId })\n\n const token = terminalTokenFromRequest(request.headers)\n const secret = typeof opts.tokenSecret === 'function' ? opts.tokenSecret() : opts.tokenSecret\n if (!token || !(await verifySandboxTerminalToken(token, { userId: user.id, workspaceId, sandboxId }, { secret }))) {\n return Response.json({ error: 'Invalid terminal token' }, { status: 403 })\n }\n\n const requestUrl = new URL(request.url)\n const runtimeConnection = await opts.getSandboxRuntimeConnection?.({ request, userId: user.id, workspaceId, sandboxId })\n const directRuntimeConnection = runtimeConnection?.runtimeUrl && runtimeConnection.authToken ? runtimeConnection : null\n const credentials = directRuntimeConnection ? null : await opts.getSandboxApiCredentials({ request, userId: user.id, workspaceId, sandboxId })\n const upstreamUrl = directRuntimeConnection\n ? new URL(encodedRuntimePath, `${directRuntimeConnection.runtimeUrl.replace(/\\/+$/, '')}/`)\n : new URL(\n `/v1/sandboxes/${encodeURIComponent(sandboxId)}/runtime/${encodedRuntimePath}`,\n credentials!.baseUrl,\n )\n upstreamUrl.search = requestUrl.search\n\n const headers = buildSandboxRuntimeProxyHeaders(\n request.headers,\n directRuntimeConnection?.authToken ?? credentials!.apiKey,\n opts.forwardHeaders,\n )\n const init: RequestInit & { duplex?: 'half' } = {\n method: request.method,\n headers,\n redirect: 'manual',\n }\n if (request.method !== 'GET' && request.method !== 'HEAD' && request.body) {\n init.body = request.body\n init.duplex = 'half'\n }\n\n const fetchImpl = opts.fetch ?? fetch\n const response = await fetchImpl(upstreamUrl, init)\n const responseHeaders = new Headers(response.headers)\n responseHeaders.delete('set-cookie')\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n })\n }\n}\n\n// ---------------------------------------------------------------------------\n// Terminal WebSocket upgrade\n//\n// The interactive terminal is WebSocket-only on the current sidecar (the REST\n// `POST /terminals` create route was removed in the websocket-first migration).\n// `createWorkspaceSandboxRuntimeProxyHandler` runs inside a React Router\n// loader/action, which can only return a normal Response — never a 101 — so it\n// cannot perform the upgrade. The upgrade must be intercepted at the Worker\n// fetch entry (server.ts) BEFORE React Router, mirroring the session-stream WS\n// interceptor. This handler does exactly that: it auth-gates the upgrade (the\n// scoped terminal token rides in the `bearer.` subprotocol because browsers\n// can't set Authorization on a WS handshake) and forwards it to the sandbox API\n// runtime proxy with the server-to-server credential. Returning the upstream\n// 101 passes the live socket straight through to the browser — the same idiom\n// the sandbox API uses to reach the orchestrator.\n//\n// NOTE: this only runs under a WebSocket-capable runtime (Cloudflare Workers /\n// `wrangler`). `react-router dev` (Vite) never invokes the Worker fetch entry,\n// so the terminal WS is exercised under `wrangler dev` / production.\n// ---------------------------------------------------------------------------\n\nconst SANDBOX_TERMINAL_WS_PATHNAME =\n /^\\/api\\/workspaces\\/([^/]+)\\/sandbox\\/runtime\\/([^/]+)\\/(terminals\\/[^/]+\\/ws)$/\n\nexport interface SandboxTerminalWsMatch {\n workspaceId: string\n sandboxId: string\n subPath: string\n}\n\n/**\n * Parse a same-origin terminal-WS pathname into its parts, or `null` when the\n * path is not a sandbox terminal WebSocket. Matches the default `runtimeUrl`\n * convention emitted by {@link createWorkspaceSandboxConnectionHandler}\n * (`/api/workspaces/:workspaceId/sandbox/runtime/:sandboxId`) with a canonical\n * `terminals/:id/ws` sub-path. `subPath` is left URL-encoded for re-use in the\n * upstream URL; the ids are decoded for auth checks.\n */\nexport function matchSandboxTerminalWsPath(pathname: string): SandboxTerminalWsMatch | null {\n const m = SANDBOX_TERMINAL_WS_PATHNAME.exec(pathname)\n if (!m) return null\n const [, workspaceId, sandboxId, subPath] = m\n if (!workspaceId || !sandboxId || !subPath) return null\n const decodedWorkspaceId = safeDecodeURIComponent(workspaceId)\n const decodedSandboxId = safeDecodeURIComponent(sandboxId)\n if (!decodedWorkspaceId || !decodedSandboxId) return null\n return { workspaceId: decodedWorkspaceId, sandboxId: decodedSandboxId, subPath }\n}\n\n/** True when `request` is a WebSocket upgrade for a sandbox terminal path. */\nexport function isSandboxTerminalWsUpgrade(request: Request): boolean {\n if (request.headers.get('Upgrade')?.toLowerCase() !== 'websocket') return false\n try {\n return matchSandboxTerminalWsPath(new URL(request.url).pathname) !== null\n } catch {\n return false\n }\n}\n\nexport interface WorkspaceSandboxTerminalUpgradeHandlerOptions {\n requireUser: (request: Request) => Promise<AuthenticatedSandboxUser>\n requireWorkspaceAccess: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<void>\n getSandboxApiCredentials: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<SandboxApiCredentials>\n getSandboxRuntimeConnection?: (args: { request: Request; userId: string; workspaceId: string; sandboxId: string }) => Promise<SandboxRuntimeConnection | null | undefined>\n tokenSecret: string | (() => string | undefined)\n fetch?: typeof fetch\n}\n\n/**\n * Build a Worker-entry handler that proxies a sandbox terminal WebSocket\n * upgrade to the sandbox API runtime proxy. Returns `null` when the request is\n * not a terminal WS upgrade, so the caller can fall through to its normal\n * request handler:\n *\n * ```ts\n * const handled = await handleSandboxTerminalUpgrade(request)\n * if (handled) return handled\n * ```\n */\nexport function createWorkspaceSandboxTerminalUpgradeHandler(opts: WorkspaceSandboxTerminalUpgradeHandlerOptions) {\n return async function handleWorkspaceSandboxTerminalUpgrade(request: Request): Promise<Response | null> {\n if (request.headers.get('Upgrade')?.toLowerCase() !== 'websocket') return null\n let url: URL\n try {\n url = new URL(request.url)\n } catch {\n return null\n }\n const match = matchSandboxTerminalWsPath(url.pathname)\n if (!match) return null\n const { workspaceId, sandboxId, subPath } = match\n\n let user: AuthenticatedSandboxUser\n try {\n user = await opts.requireUser(request)\n } catch {\n return new Response('Unauthorized', { status: 401 })\n }\n try {\n await opts.requireWorkspaceAccess({ request, userId: user.id, workspaceId, sandboxId })\n } catch {\n return new Response('Forbidden', { status: 403 })\n }\n\n const token = terminalTokenFromRequest(request.headers)\n const secret = typeof opts.tokenSecret === 'function' ? opts.tokenSecret() : opts.tokenSecret\n if (!token || !(await verifySandboxTerminalToken(token, { userId: user.id, workspaceId, sandboxId }, { secret }))) {\n return new Response('Invalid terminal token', { status: 403 })\n }\n\n const runtimeConnection = await opts.getSandboxRuntimeConnection?.({ request, userId: user.id, workspaceId, sandboxId })\n const directRuntimeConnection = runtimeConnection?.runtimeUrl && runtimeConnection.authToken ? runtimeConnection : null\n const credentials = directRuntimeConnection ? null : await opts.getSandboxApiCredentials({ request, userId: user.id, workspaceId, sandboxId })\n const upstreamUrl = directRuntimeConnection\n ? new URL(subPath, `${directRuntimeConnection.runtimeUrl.replace(/\\/+$/, '')}/`)\n : new URL(`/v1/sandboxes/${encodeURIComponent(sandboxId)}/runtime/${subPath}`, credentials!.baseUrl)\n upstreamUrl.search = url.search\n\n // Forward the upgrade verbatim — keep the Upgrade/Connection + Sec-WebSocket-*\n // headers the handshake needs, but strip the browser-only bearer subprotocol\n // and send the server-to-server sandbox credential only as Authorization.\n // Returning the upstream 101 passes the live socket straight through to the browser.\n const upstreamHeaders = new Headers(request.headers)\n const upstreamBearer = directRuntimeConnection?.authToken ?? credentials!.apiKey\n upstreamHeaders.set('Authorization', `Bearer ${upstreamBearer}`)\n upstreamHeaders.delete('host')\n stripBearerSubprotocol(upstreamHeaders)\n const fetchImpl = opts.fetch ?? fetch\n return fetchImpl(upstreamUrl.toString(), { method: request.method, headers: upstreamHeaders })\n }\n}\n\nconst DEFAULT_RUNTIME_PROXY_HEADERS = ['accept', 'content-type', 'last-event-id', 'x-session-id']\n\nexport function buildSandboxRuntimeProxyHeaders(source: Headers, sandboxApiKey: string, forwardHeaders = DEFAULT_RUNTIME_PROXY_HEADERS): Headers {\n const headers = new Headers()\n headers.set('Authorization', `Bearer ${sandboxApiKey}`)\n for (const name of forwardHeaders) {\n const value = source.get(name)\n if (value) headers.set(name, value)\n }\n return headers\n}\n\nexport function encodeSandboxRuntimePath(runtimePath: string): string | null {\n const segments = runtimePath.split('/')\n if (segments.some((segment) => !segment || segment === '.' || segment === '..')) return null\n return segments.map((segment) => encodeURIComponent(segment)).join('/')\n}\n\nexport function bearerToken(value: string | null): string | null {\n if (!value) return null\n const trimmed = value.trim()\n if (!trimmed) return null\n if (trimmed.toLowerCase() === 'bearer') return null\n if (trimmed.toLowerCase().startsWith('bearer ')) {\n const token = trimmed.slice('bearer '.length).trim()\n return token || null\n }\n return trimmed\n}\n\nexport function bearerSubprotocolToken(value: string | null): string | null {\n if (!value) return null\n for (const part of value.split(',')) {\n const protocol = part.trim()\n if (!protocol.toLowerCase().startsWith(BEARER_SUBPROTOCOL_PREFIX)) continue\n const encoded = protocol.slice(BEARER_SUBPROTOCOL_PREFIX.length)\n if (!encoded) return null\n try {\n const token = base64UrlDecodeText(encoded).trim()\n return token || null\n } catch {\n return null\n }\n }\n return null\n}\n\nexport function terminalTokenFromRequest(headers: Headers): string | null {\n return bearerToken(headers.get('Authorization')) ?? bearerSubprotocolToken(headers.get('Sec-WebSocket-Protocol'))\n}\n\nfunction safeDecodeURIComponent(value: string): string | null {\n try {\n return decodeURIComponent(value)\n } catch {\n return null\n }\n}\n\nfunction stripBearerSubprotocol(headers: Headers): void {\n const value = headers.get('Sec-WebSocket-Protocol')\n if (!value) return\n const protocols = value\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part && !part.toLowerCase().startsWith(BEARER_SUBPROTOCOL_PREFIX))\n if (protocols.length) {\n headers.set('Sec-WebSocket-Protocol', protocols.join(', '))\n } else {\n headers.delete('Sec-WebSocket-Protocol')\n }\n}\n\nfunction validateTerminalSubject(subject: SandboxTerminalTokenSubject): void {\n if (!subject.userId) throw new Error('userId is required')\n if (!subject.workspaceId) throw new Error('workspaceId is required')\n if (!subject.sandboxId) throw new Error('sandboxId is required')\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA,EACE;AAAA,OAWK;AACP,SAAS,kBAAkB;;;ACLpB,IAAM,KAAK,CAAI,WAA0B,EAAE,WAAW,MAAM,MAAM;AAClE,IAAM,OAAO,CAAC,WAAoC;AAAA,EACvD,WAAW;AAAA,EACX,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACjE;;;AC8BO,SAAS,WAAW,OAAuB;AAChD,SAAO,IAAI,MAAM,WAAW,KAAK,OAAO,CAAC;AAC3C;AAKA,SAAS,cAAc,QAA4B;AACjD,QAAM,SAAS,KAAK,MAAM;AAC1B,QAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;AAC1C,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,EAAG,OAAM,CAAC,IAAI,OAAO,WAAW,CAAC;AACzE,SAAO;AACT;AAEA,SAAS,cAAc,KAAyB,SAAiB,SAA8B;AAC7F,SAAO,SAAS,YAAY,IAAI,KAAK,SAAS,EAAE,WAAW,QAAQ,UAAU,CAAC,IAAI,IAAI,KAAK,OAAO;AACpG;AAKA,eAAsB,oBACpB,KACA,cACA,SACiC;AACjC,QAAM,aAAa,WAAW,YAAY;AAC1C,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,cAAc,KAAK,WAAW,UAAU,IAAI,OAAO;AAAA,EACpE,SAAS,KAAK;AACZ,WAAO,EAAE,WAAW,OAAO,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE;AAAA,EACrF;AACA,MAAI,OAAO,aAAa,GAAG;AACzB,WAAO,EAAE,WAAW,OAAO,OAAO,OAAO,UAAU,gBAAgB;AAAA,EACrE;AACA,QAAM,OAAO,OAAO,SAAS,OAAO,OAAO,KAAK,GAAG,EAAE;AACrD,MAAI,CAAC,OAAO,SAAS,IAAI,GAAG;AAC1B,WAAO,EAAE,WAAW,OAAO,OAAO,mCAAmC,OAAO,OAAO,KAAK,CAAC,IAAI;AAAA,EAC/F;AACA,SAAO,EAAE,WAAW,MAAM,OAAO,KAAK;AACxC;AAKA,eAAsB,uBACpB,KACA,cACA,cACA,SACkC;AAClC,QAAM,aAAa,WAAW,YAAY;AAC1C,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,cAAc,KAAK,UAAU,UAAU,IAAI,OAAO;AAAA,EACnE,SAAS,KAAK;AACZ,WAAO,EAAE,WAAW,OAAO,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE;AAAA,EACrF;AACA,MAAI,OAAO,aAAa,GAAG;AACzB,WAAO,EAAE,WAAW,OAAO,OAAO,OAAO,UAAU,gBAAgB;AAAA,EACrE;AAGA,QAAM,UAAU,OAAO,OAAO,QAAQ,QAAQ,EAAE;AAChD,MAAI;AACJ,MAAI;AACF,YAAQ,cAAc,OAAO;AAAA,EAC/B,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,WAAW;AAAA,MACX,OAAO,mCAAmC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC5F;AAAA,EACF;AACA,MAAI,MAAM,eAAe,cAAc;AACrC,WAAO;AAAA,MACL,WAAW;AAAA,MACX,OAAO,iBAAiB,MAAM,UAAU,oBAAoB,YAAY;AAAA,IAC1E;AAAA,EACF;AACA,SAAO,EAAE,WAAW,MAAM,OAAO,EAAE,OAAO,MAAM,aAAa,EAAE;AACjE;;;AC3GA,IAAM,8BAA8B,KAAK,KAAK;AAE9C,eAAsB,uBACpB,QACA,UACA,QAAQ,6BACR,MAAoB,KAAK,KAC6B;AACtD,MAAI,CAAC,OAAQ,QAAO,KAAK,IAAI,MAAM,4CAA4C,CAAC;AAChF,MAAI,CAAC,SAAS,UAAU,CAAC,SAAS,eAAe,CAAC,SAAS,WAAW;AACpE,WAAO,KAAK,IAAI,MAAM,mEAAmE,CAAC;AAAA,EAC5F;AACA,QAAM,YAAY,IAAI,KAAK,IAAI,IAAI,KAAK;AACxC,QAAM,UAAU,EAAE,GAAG,UAAU,KAAK,KAAK,MAAM,UAAU,QAAQ,IAAI,GAAI,EAAE;AAC3E,QAAM,UAAU,oBAAoB,KAAK,UAAU,OAAO,CAAC;AAC3D,QAAM,MAAM,MAAM,oBAAoB,SAAS,MAAM;AACrD,SAAO,GAAG,EAAE,OAAO,GAAG,OAAO,IAAI,GAAG,IAAI,UAAU,CAAC;AACrD;AAEA,eAAsB,yBACpB,QACA,OACA,UACA,MAAoB,KAAK,KACP;AAClB,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,CAAC,SAAS,KAAK,KAAK,IAAI,MAAM,MAAM,GAAG;AAC7C,MAAI,CAAC,WAAW,CAAC,OAAO,UAAU,OAAW,QAAO;AACpD,QAAM,cAAc,MAAM,oBAAoB,SAAS,MAAM;AAC7D,MAAI,CAAC,kBAAkB,KAAK,WAAW,EAAG,QAAO;AACjD,MAAI;AACJ,MAAI;AACF,cAAU,KAAK,MAAM,oBAAoB,OAAO,CAAC;AAAA,EACnD,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SACE,QAAQ,WAAW,SAAS,UAC5B,QAAQ,gBAAgB,SAAS,eACjC,QAAQ,cAAc,SAAS,aAC/B,OAAO,SAAS,QAAQ,GAAG,KAC3B,QAAQ,MAAM,KAAK,MAAM,IAAI,IAAI,GAAI;AAEzC;;;ACJO,SAAS,8BACd,MAC+C;AAC/C,SAAO;AAAA,IACL,MAAM,uBAAuB,aAAa,QAAQ,SAAS;AACzD,UAAI,CAAC,YAAa,OAAM,IAAI,MAAM,yBAAyB;AAC3D,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AACjD,YAAM,MAAM,EAAE,aAAa,OAAO;AAClC,YAAM,SAAS,MAAM,KAAK,UAAU,GAAG;AACvC,YAAM,OAAO,KAAK,iBAAiB,aAAa,GAAG;AACnD,UAAI;AACJ,UAAI,WAAmB,CAAC;AAExB,UAAI;AACF,mBAAW,MAAM,KAAK,cAAc,QAAQ,GAAG;AAAA,MACjD,SAAS,KAAK;AACZ,oBAAY;AACZ,aAAK,cAAc,KAAK,GAAG;AAAA,MAC7B;AAEA,YAAM,QAAQ,SAAS,KAAK,CAAC,QAAQ,IAAI,SAAS,IAAI;AACtD,UAAI,OAAO;AACT,eAAQ,MAAM,KAAK,kBAAkB,OAAO,KAAK,OAAyB,KAAM;AAAA,MAClF;AAEA,YAAM,UAAU,MAAM,KAAK,cAAc;AAAA,QACvC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AACD,YAAM,KAAK,iBAAiB,SAAS,GAAG;AACxC,aAAQ,MAAM,KAAK,iBAAiB,SAAS,KAAK,OAAyB,KAAM;AAAA,IACnF;AAAA,EACF;AACF;AAeA,IAAM,gCAAgC,KAAK,KAAK;AAChD,IAAM,4BAA4B;AAMlC,IAAM,+BAA+B;AAErC,eAAsB,2BACpB,SACA,MACqC;AACrC,0BAAwB,OAAO;AAC/B,QAAM,SAAS,KAAK,QAAQ,KAAK;AACjC,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,mCAAmC;AAChE,QAAM,MAAM,KAAK,OAAO,KAAK;AAC7B,QAAM,cAAc,KAAK,eAAe;AACxC,MAAI,CAAC,OAAO,SAAS,WAAW,KAAK,eAAe,EAAG,OAAM,IAAI,MAAM,uCAAuC;AAC9G,QAAM,SAAS,MAAM,uBAAuB,QAAQ,SAAS,aAAa,GAAG;AAC7E,MAAI,CAAC,OAAO,UAAW,OAAM,OAAO;AACpC,SAAO,OAAO;AAChB;AAEA,eAAsB,2BACpB,OACA,UACA,MACkB;AAClB,0BAAwB,QAAQ;AAChC,QAAM,SAAS,KAAK,QAAQ,KAAK;AACjC,QAAM,MAAM,KAAK,OAAO,KAAK;AAC7B,QAAM,aAAa,MAAM,WAAW,4BAA4B,IAC5D,MAAM,MAAM,6BAA6B,MAAM,IAC/C;AACJ,SAAO,yBAAyB,UAAU,IAAI,YAAY,UAAU,GAAG;AACzE;AAuBO,SAAS,wCACd,MACA;AACA,SAAO,eAAe,iCAAiC,EAAE,SAAS,OAAO,GAAsD;AAC7H,UAAM,OAAO,MAAM,KAAK,YAAY,OAAO;AAC3C,UAAM,cAAc,OAAO;AAC3B,QAAI,CAAC,YAAa,QAAO,SAAS,KAAK,EAAE,OAAO,0BAA0B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAC5F,UAAM,KAAK,uBAAuB,EAAE,SAAS,QAAQ,KAAK,IAAI,YAAY,CAAC;AAE3E,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,KAAK,uBAAuB,aAAa,KAAK,EAAE;AAAA,IAC9D,SAAS,KAAK;AACZ,aAAO,SAAS;AAAA,QACd,EAAE,OAAO,eAAe,QAAQ,IAAI,UAAU,wCAAwC;AAAA,QACtF,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,mBAAmB,IAAI,YAAY,cAAc,IAAI,YAAY;AACvE,UAAM,qBAAqB,IAAI,YAAY,aAAa,IAAI,YAAY;AACxE,UAAM,yBAAyB,IAAI,YAAY;AAC/C,QAAI,KAAK,uBAAuB,oBAAoB,sBAAsB,wBAAwB;AAChG,aAAO,SAAS,KAAK;AAAA,QACnB,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,WAAW;AAAA,QACX,QAAQ,IAAI;AAAA,QACZ,WAAW,IAAI;AAAA,MACjB,CAAC;AAAA,IACH;AAEA,QAAI,CAAC,kBAAkB;AACrB,aAAO,SAAS;AAAA,QACd;AAAA,UACE,OAAO;AAAA,UACP,QAAQ,IAAI;AAAA,QACd;AAAA,QACA,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,SAAS,OAAO,KAAK,gBAAgB,aAAa,KAAK,YAAY,IAAI,KAAK;AAClF,QAAI;AACJ,QAAI;AACF,eAAS,MAAM;AAAA,QACb,EAAE,QAAQ,KAAK,IAAI,aAAa,WAAW,IAAI,GAAG;AAAA,QAClD,EAAE,QAAQ,aAAa,KAAK,iBAAiB;AAAA,MAC/C;AAAA,IACF,SAAS,KAAK;AACZ,aAAO,SAAS;AAAA,QACd,EAAE,OAAO,eAAe,QAAQ,IAAI,UAAU,+BAA+B;AAAA,QAC7E,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,aAAa,KAAK,kBACpB,KAAK,gBAAgB,EAAE,SAAS,aAAa,WAAW,IAAI,IAAI,IAAI,CAAC,IACrE,mBAAmB,mBAAmB,WAAW,CAAC,oBAAoB,mBAAmB,IAAI,EAAE,CAAC;AAEpG,WAAO,SAAS,KAAK;AAAA,MACnB;AAAA,MACA,YAAY;AAAA,MACZ,OAAO,OAAO;AAAA,MACd,WAAW,OAAO,UAAU,YAAY;AAAA,MACxC,QAAQ,IAAI;AAAA,MACZ,WAAW,IAAI;AAAA,IACjB,CAAC;AAAA,EACH;AACF;AAgCO,SAAS,0CAA0C,MAAkD;AAC1G,SAAO,eAAe,mCAAmC,EAAE,SAAS,OAAO,GAAwD;AACjI,UAAM,OAAO,MAAM,KAAK,YAAY,OAAO;AAC3C,UAAM,cAAc,OAAO;AAC3B,UAAM,YAAY,OAAO;AACzB,UAAM,cAAc,OAAO,GAAG;AAC9B,QAAI,CAAC,eAAe,CAAC,aAAa,CAAC,aAAa;AAC9C,aAAO,SAAS,KAAK,EAAE,OAAO,wDAAwD,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC1G;AACA,UAAM,qBAAqB,yBAAyB,WAAW;AAC/D,QAAI,CAAC,mBAAoB,QAAO,SAAS,KAAK,EAAE,OAAO,+BAA+B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAExG,UAAM,KAAK,uBAAuB,EAAE,SAAS,QAAQ,KAAK,IAAI,aAAa,UAAU,CAAC;AAEtF,UAAM,QAAQ,yBAAyB,QAAQ,OAAO;AACtD,UAAM,SAAS,OAAO,KAAK,gBAAgB,aAAa,KAAK,YAAY,IAAI,KAAK;AAClF,QAAI,CAAC,SAAS,CAAE,MAAM,2BAA2B,OAAO,EAAE,QAAQ,KAAK,IAAI,aAAa,UAAU,GAAG,EAAE,OAAO,CAAC,GAAI;AACjH,aAAO,SAAS,KAAK,EAAE,OAAO,yBAAyB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC3E;AAEA,UAAM,aAAa,IAAI,IAAI,QAAQ,GAAG;AACtC,UAAM,oBAAoB,MAAM,KAAK,8BAA8B,EAAE,SAAS,QAAQ,KAAK,IAAI,aAAa,UAAU,CAAC;AACvH,UAAM,0BAA0B,mBAAmB,cAAc,kBAAkB,YAAY,oBAAoB;AACnH,UAAM,cAAc,0BAA0B,OAAO,MAAM,KAAK,yBAAyB,EAAE,SAAS,QAAQ,KAAK,IAAI,aAAa,UAAU,CAAC;AAC7I,UAAM,cAAc,0BAChB,IAAI,IAAI,oBAAoB,GAAG,wBAAwB,WAAW,QAAQ,QAAQ,EAAE,CAAC,GAAG,IACxF,IAAI;AAAA,MACJ,iBAAiB,mBAAmB,SAAS,CAAC,YAAY,kBAAkB;AAAA,MAC5E,YAAa;AAAA,IACf;AACF,gBAAY,SAAS,WAAW;AAEhC,UAAM,UAAU;AAAA,MACd,QAAQ;AAAA,MACR,yBAAyB,aAAa,YAAa;AAAA,MACnD,KAAK;AAAA,IACP;AACA,UAAM,OAA0C;AAAA,MAC9C,QAAQ,QAAQ;AAAA,MAChB;AAAA,MACA,UAAU;AAAA,IACZ;AACA,QAAI,QAAQ,WAAW,SAAS,QAAQ,WAAW,UAAU,QAAQ,MAAM;AACzE,WAAK,OAAO,QAAQ;AACpB,WAAK,SAAS;AAAA,IAChB;AAEA,UAAM,YAAY,KAAK,SAAS;AAChC,UAAM,WAAW,MAAM,UAAU,aAAa,IAAI;AAClD,UAAM,kBAAkB,IAAI,QAAQ,SAAS,OAAO;AACpD,oBAAgB,OAAO,YAAY;AACnC,WAAO,IAAI,SAAS,SAAS,MAAM;AAAA,MACjC,QAAQ,SAAS;AAAA,MACjB,YAAY,SAAS;AAAA,MACrB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF;AAuBA,IAAM,+BACJ;AAgBK,SAAS,2BAA2B,UAAiD;AAC1F,QAAM,IAAI,6BAA6B,KAAK,QAAQ;AACpD,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,CAAC,EAAE,aAAa,WAAW,OAAO,IAAI;AAC5C,MAAI,CAAC,eAAe,CAAC,aAAa,CAAC,QAAS,QAAO;AACnD,QAAM,qBAAqB,uBAAuB,WAAW;AAC7D,QAAM,mBAAmB,uBAAuB,SAAS;AACzD,MAAI,CAAC,sBAAsB,CAAC,iBAAkB,QAAO;AACrD,SAAO,EAAE,aAAa,oBAAoB,WAAW,kBAAkB,QAAQ;AACjF;AAGO,SAAS,2BAA2B,SAA2B;AACpE,MAAI,QAAQ,QAAQ,IAAI,SAAS,GAAG,YAAY,MAAM,YAAa,QAAO;AAC1E,MAAI;AACF,WAAO,2BAA2B,IAAI,IAAI,QAAQ,GAAG,EAAE,QAAQ,MAAM;AAAA,EACvE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAsBO,SAAS,6CAA6C,MAAqD;AAChH,SAAO,eAAe,sCAAsC,SAA4C;AACtG,QAAI,QAAQ,QAAQ,IAAI,SAAS,GAAG,YAAY,MAAM,YAAa,QAAO;AAC1E,QAAI;AACJ,QAAI;AACF,YAAM,IAAI,IAAI,QAAQ,GAAG;AAAA,IAC3B,QAAQ;AACN,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,2BAA2B,IAAI,QAAQ;AACrD,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,EAAE,aAAa,WAAW,QAAQ,IAAI;AAE5C,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,KAAK,YAAY,OAAO;AAAA,IACvC,QAAQ;AACN,aAAO,IAAI,SAAS,gBAAgB,EAAE,QAAQ,IAAI,CAAC;AAAA,IACrD;AACA,QAAI;AACF,YAAM,KAAK,uBAAuB,EAAE,SAAS,QAAQ,KAAK,IAAI,aAAa,UAAU,CAAC;AAAA,IACxF,QAAQ;AACN,aAAO,IAAI,SAAS,aAAa,EAAE,QAAQ,IAAI,CAAC;AAAA,IAClD;AAEA,UAAM,QAAQ,yBAAyB,QAAQ,OAAO;AACtD,UAAM,SAAS,OAAO,KAAK,gBAAgB,aAAa,KAAK,YAAY,IAAI,KAAK;AAClF,QAAI,CAAC,SAAS,CAAE,MAAM,2BAA2B,OAAO,EAAE,QAAQ,KAAK,IAAI,aAAa,UAAU,GAAG,EAAE,OAAO,CAAC,GAAI;AACjH,aAAO,IAAI,SAAS,0BAA0B,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC/D;AAEA,UAAM,oBAAoB,MAAM,KAAK,8BAA8B,EAAE,SAAS,QAAQ,KAAK,IAAI,aAAa,UAAU,CAAC;AACvH,UAAM,0BAA0B,mBAAmB,cAAc,kBAAkB,YAAY,oBAAoB;AACnH,UAAM,cAAc,0BAA0B,OAAO,MAAM,KAAK,yBAAyB,EAAE,SAAS,QAAQ,KAAK,IAAI,aAAa,UAAU,CAAC;AAC7I,UAAM,cAAc,0BAChB,IAAI,IAAI,SAAS,GAAG,wBAAwB,WAAW,QAAQ,QAAQ,EAAE,CAAC,GAAG,IAC7E,IAAI,IAAI,iBAAiB,mBAAmB,SAAS,CAAC,YAAY,OAAO,IAAI,YAAa,OAAO;AACrG,gBAAY,SAAS,IAAI;AAMzB,UAAM,kBAAkB,IAAI,QAAQ,QAAQ,OAAO;AACnD,UAAM,iBAAiB,yBAAyB,aAAa,YAAa;AAC1E,oBAAgB,IAAI,iBAAiB,UAAU,cAAc,EAAE;AAC/D,oBAAgB,OAAO,MAAM;AAC7B,2BAAuB,eAAe;AACtC,UAAM,YAAY,KAAK,SAAS;AAChC,WAAO,UAAU,YAAY,SAAS,GAAG,EAAE,QAAQ,QAAQ,QAAQ,SAAS,gBAAgB,CAAC;AAAA,EAC/F;AACF;AAEA,IAAM,gCAAgC,CAAC,UAAU,gBAAgB,iBAAiB,cAAc;AAEzF,SAAS,gCAAgC,QAAiB,eAAuB,iBAAiB,+BAAwC;AAC/I,QAAM,UAAU,IAAI,QAAQ;AAC5B,UAAQ,IAAI,iBAAiB,UAAU,aAAa,EAAE;AACtD,aAAW,QAAQ,gBAAgB;AACjC,UAAM,QAAQ,OAAO,IAAI,IAAI;AAC7B,QAAI,MAAO,SAAQ,IAAI,MAAM,KAAK;AAAA,EACpC;AACA,SAAO;AACT;AAEO,SAAS,yBAAyB,aAAoC;AAC3E,QAAM,WAAW,YAAY,MAAM,GAAG;AACtC,MAAI,SAAS,KAAK,CAAC,YAAY,CAAC,WAAW,YAAY,OAAO,YAAY,IAAI,EAAG,QAAO;AACxF,SAAO,SAAS,IAAI,CAAC,YAAY,mBAAmB,OAAO,CAAC,EAAE,KAAK,GAAG;AACxE;AAEO,SAAS,YAAY,OAAqC;AAC/D,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,QAAQ,YAAY,MAAM,SAAU,QAAO;AAC/C,MAAI,QAAQ,YAAY,EAAE,WAAW,SAAS,GAAG;AAC/C,UAAM,QAAQ,QAAQ,MAAM,UAAU,MAAM,EAAE,KAAK;AACnD,WAAO,SAAS;AAAA,EAClB;AACA,SAAO;AACT;AAEO,SAAS,uBAAuB,OAAqC;AAC1E,MAAI,CAAC,MAAO,QAAO;AACnB,aAAW,QAAQ,MAAM,MAAM,GAAG,GAAG;AACnC,UAAM,WAAW,KAAK,KAAK;AAC3B,QAAI,CAAC,SAAS,YAAY,EAAE,WAAW,yBAAyB,EAAG;AACnE,UAAM,UAAU,SAAS,MAAM,0BAA0B,MAAM;AAC/D,QAAI,CAAC,QAAS,QAAO;AACrB,QAAI;AACF,YAAM,QAAQ,oBAAoB,OAAO,EAAE,KAAK;AAChD,aAAO,SAAS;AAAA,IAClB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,yBAAyB,SAAiC;AACxE,SAAO,YAAY,QAAQ,IAAI,eAAe,CAAC,KAAK,uBAAuB,QAAQ,IAAI,wBAAwB,CAAC;AAClH;AAEA,SAAS,uBAAuB,OAA8B;AAC5D,MAAI;AACF,WAAO,mBAAmB,KAAK;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,uBAAuB,SAAwB;AACtD,QAAM,QAAQ,QAAQ,IAAI,wBAAwB;AAClD,MAAI,CAAC,MAAO;AACZ,QAAM,YAAY,MACf,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,CAAC,SAAS,QAAQ,CAAC,KAAK,YAAY,EAAE,WAAW,yBAAyB,CAAC;AACrF,MAAI,UAAU,QAAQ;AACpB,YAAQ,IAAI,0BAA0B,UAAU,KAAK,IAAI,CAAC;AAAA,EAC5D,OAAO;AACL,YAAQ,OAAO,wBAAwB;AAAA,EACzC;AACF;AAEA,SAAS,wBAAwB,SAA4C;AAC3E,MAAI,CAAC,QAAQ,OAAQ,OAAM,IAAI,MAAM,oBAAoB;AACzD,MAAI,CAAC,QAAQ,YAAa,OAAM,IAAI,MAAM,yBAAyB;AACnE,MAAI,CAAC,QAAQ,UAAW,OAAM,IAAI,MAAM,uBAAuB;AACjE;;;AJjcA,IAAM,mCAAmC;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AACF;AACA,IAAM,iCAAiC,CAAC,uBAAuB,iBAAiB;AAEhF,SAAS,iBAAiB,OAAuB;AAC/C,SAAO,MAAM,KAAK,EAAE,QAAQ,YAAY,EAAE,EAAE,QAAQ,QAAQ,EAAE;AAChE;AAEA,SAAS,aAAiD;AACxD,SAAO,OAAO,YAAY,cAAc,CAAC,IAAI,QAAQ;AACvD;AAEA,SAAS,4BACP,aACA,OACS;AACT,MAAI,OAAO,UAAU,WAAY,QAAO,MAAM,WAAW;AACzD,MAAI,OAAO,UAAU,UAAW,QAAO;AACvC,SAAO,gBAAgB,iBAAiB,gBAAgB;AAC1D;AAEA,SAAS,sBACP,KACA,OACA,gBACQ;AACR,aAAW,QAAQ,OAAO;AACxB,UAAMA,SAAQ,WAAW,IAAI,IAAI,CAAC;AAClC,QAAIA,OAAO,QAAO,iBAAiBA,MAAK;AAAA,EAC1C;AACA,QAAM,QAAQ,WAAW,cAAc;AACvC,MAAI,MAAO,QAAO,iBAAiB,KAAK;AACxC,QAAM,IAAI;AAAA,IACR,4CAA4C,MAAM,KAAK,IAAI,CAAC;AAAA,EAC9D;AACF;AAEA,SAAS,gCACP,KACA,UACA,cACA,gBACiC;AACjC,aAAW,QAAQ,UAAU;AAC3B,UAAM,SAAS,WAAW,IAAI,IAAI,CAAC;AACnC,QAAI,CAAC,OAAQ;AACb,WAAO;AAAA,MACL;AAAA,MACA,SAAS,sBAAsB,KAAK,cAAc,cAAc;AAAA,IAClE;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,gCACpB,UAAkD,CAAC,GAChB;AACnC,QAAM,MAAM,QAAQ,OAAO,WAAW;AACtC,QAAM,cAAc,QAAQ,eAAe,kCAAkC,GAAG;AAChF,QAAM,WAAW,QAAQ,kBAAkB;AAC3C,QAAM,eAAe,QAAQ,gBAAgB;AAC7C,QAAM,gBAAgB,4BAA4B,aAAa,QAAQ,yBAAyB;AAChG,QAAM,SAAS,MACb,gBACI,gCAAgC,KAAK,UAAU,cAAc,QAAQ,cAAc,IACnF;AAEN,MAAI,gBAAgB,iBAAiB,gBAAgB,QAAQ;AAC3D,UAAMC,eAAc,OAAO;AAC3B,QAAIA,aAAa,QAAOA;AAAA,EAC1B;AAEA,QAAM,cAAc,MAAM,QAAQ,YAAY,EAAE,aAAa,IAAI,CAAC;AAClE,MAAI,aAAa;AACf,WAAO;AAAA,MACL,QAAQ,YAAY;AAAA,MACpB,SAAS,iBAAiB,YAAY,OAAO;AAAA,IAC/C;AAAA,EACF;AAEA,QAAM,cAAc,OAAO;AAC3B,MAAI,YAAa,QAAO;AAExB,QAAM,aAAa,gBACf,kBAAkB,SAAS,KAAK,IAAI,CAAC,KACrC;AACJ,QAAM,IAAI;AAAA,IACR,wCAAwC,WAAW,iCAAiC,UAAU;AAAA,EAChG;AACF;AA4IO,IAAM,4BAAmD;AAAA,EAC9D,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,oBAAoB;AAAA,EACpB,oBAAoB;AACtB;AAOA,IAAI,UAAmC;AAEvC,SAAS,mBAAmB,OAA0C;AACpE,QAAM,cAAc,GAAG,MAAM,MAAM,IAAI,MAAM,OAAO;AACpD,MAAI,WAAW,QAAQ,gBAAgB,YAAa,QAAO,QAAQ;AAEnE,QAAM,SAAS,IAAI,QAAQ,EAAE,QAAQ,MAAM,QAAQ,SAAS,MAAM,QAAQ,CAAC;AAC3E,YAAU,EAAE,QAAQ,YAAY;AAChC,SAAO;AACT;AAKO,SAAS,UAAU,OAAsC;AAC9D,QAAM,QAAQ,MAAM,YAAY;AAChC,MAAI,SAAS,OAAQ,MAA2B,SAAS,YAAY;AACnE,UAAM,IAAI,MAAM,sEAAsE;AAAA,EACxF;AACA,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,mDAAmD;AAC/E,SAAO,mBAAmB,KAAiC;AAC7D;AAEO,SAAS,mBAAyB;AACvC,YAAU;AACZ;AAgBO,SAAS,uBACd,SACuC;AACvC,QAAM,UAAiD,CAAC;AACxD,aAAW,EAAE,MAAM,KAAK,YAAY,KAAK,QAAQ,OAAO;AACtD,YAAQ,GAAG,IAAI,sBAAsB;AAAA,MACnC;AAAA,MACA,SAAS,QAAQ;AAAA,MACjB,OAAO,QAAQ;AAAA,MACf,KAAK,QAAQ;AAAA,MACb;AAAA,MACA,aAAa,QAAQ;AAAA,IACvB,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAwBA,SAAS,iBAAiB,OAAuB;AAC/C,SAAO,IAAI,MAAM,QAAQ,MAAM,OAAO,CAAC;AACzC;AAkBA,IAAM,gCAAgC;AACtC,IAAM,oBAAoB;AAE1B,SAAS,4BAA4B,OAAe,OAAuB;AACzE,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,WAAW,YAAY,OAAO,YAAY,QAAQ,CAAC,kBAAkB,KAAK,OAAO,GAAG;AACvF,UAAM,IAAI,MAAM,GAAG,KAAK,qEAAqE;AAAA,EAC/F;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,OAAe,OAAuB;AACrE,QAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,QAAQ,EAAE;AAC3C,MAAI,CAAC,OAAO,CAAC,IAAI,WAAW,GAAG,KAAK,IAAI,SAAS,IAAI,KAAK,IAAI,SAAS,IAAI,GAAG;AAC5E,UAAM,IAAI,MAAM,GAAG,KAAK,oCAAoC;AAAA,EAC9D;AACA,SAAO,QAAQ,KAAK,MAAM;AAC5B;AAEO,SAAS,mBAAmB,SAAyC;AAC1E,QAAM,UAAU,4BAA4B,QAAQ,SAAS,sBAAsB;AACnF,QAAM,UAAU;AAAA,IACd,QAAQ,WAAW;AAAA,IACnB;AAAA,EACF;AACA,SAAO,GAAG,OAAO,IAAI,OAAO;AAC9B;AAEO,SAAS,kBAAkB,SAAyC;AACzE,8BAA4B,QAAQ,SAAS,sBAAsB;AACnE,MAAI,QAAQ,OAAQ,QAAO,wBAAwB,QAAQ,QAAQ,qBAAqB;AACxF,SAAO,GAAG,mBAAmB,OAAO,CAAC;AACvC;AAEO,SAAS,gBAAgB,SAAgE;AAC9F,QAAM,WAAW,4BAA4B,QAAQ,UAAU,mBAAmB;AAClF,SAAO,GAAG,kBAAkB,OAAO,CAAC,IAAI,QAAQ;AAClD;AAEO,SAAS,2BACd,SACyB;AACzB,SAAO,QAAQ,MAAM,IAAI,CAAC,SAAS;AACjC,UAAM,OAAO,4BAA4B,KAAK,MAAM,mBAAmB;AACvE,WAAO;AAAA,MACL,MAAM,gBAAgB,EAAE,GAAG,SAAS,UAAU,KAAK,CAAC;AAAA,MACpD,UAAU,EAAE,MAAM,UAAmB,MAAM,SAAS,KAAK,QAAQ;AAAA,MACjE,YAAY,KAAK,cAAc;AAAA,IACjC;AAAA,EACF,CAAC;AACH;AAEO,SAAS,gCAAgC,SAAyC;AACvF,QAAM,SAAS,kBAAkB,OAAO;AACxC,QAAM,aAAa,eAAe,MAAM;AACxC,SAAO;AAAA,IACL;AAAA,IACA,YAAY,iBAAiB,MAAM,CAAC;AAAA,IACpC,QAAQ,iBAAiB,MAAM,CAAC;AAAA,IAChC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe,iBAAiB,UAAU,CAAC,oCAAoC,iBAAiB,UAAU,CAAC;AAAA,IAC3G;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,eAAsB,wBACpB,KACA,SACwB;AACxB,MAAI;AACF,UAAM,MAAM,MAAM,IAAI,KAAK,gCAAgC,OAAO,CAAC;AACnE,QAAI,IAAI,aAAa,GAAG;AACtB,aAAO;AAAA,QACL,IAAI;AAAA,UACF,yDAAyD,kBAAkB,OAAO,CAAC,UACxE,IAAI,QAAQ,MAAM,IAAI,OAAO,MAAM,GAAG,GAAG,CAAC;AAAA,QACvD;AAAA,MACF;AAAA,IACF;AACA,WAAO,GAAG,MAAS;AAAA,EACrB,SAAS,KAAK;AACZ,WAAO,KAAK,IAAI,MAAM,wCAAwC,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,EAC/E;AACF;AAQA,SAAS,UAAU,MAAsB;AACvC,MAAI,SAAS,IAAK,QAAO;AACzB,MAAI,KAAK,WAAW,IAAI,GAAG;AACzB,UAAM,OAAO,KAAK,MAAM,CAAC;AACzB,WAAO,OAAO,WAAW,iBAAiB,IAAI,CAAC,KAAK;AAAA,EACtD;AACA,SAAO,iBAAiB,IAAI;AAC9B;AAMO,SAAS,0BACd,SACuE;AACvE,QAAM,QAAQ,QAAQ,WAAW,SAAS,CAAC;AAC3C,QAAM,gBAAyC,CAAC;AAChD,QAAM,YAAqC,CAAC;AAC5C,aAAW,SAAS,OAAO;AACzB,QAAI,MAAM,SAAS,SAAS,SAAU,eAAc,KAAK,KAAK;AAAA,QACzD,WAAU,KAAK,KAAK;AAAA,EAC3B;AACA,MAAI,cAAc,WAAW,EAAG,QAAO,EAAE,aAAa,SAAS,cAAc;AAC7E,QAAM,cAA4B;AAAA,IAChC,GAAG;AAAA,IACH,WAAW,EAAE,GAAI,QAAQ,aAAa,CAAC,GAAI,OAAO,UAAU;AAAA,EAC9D;AACA,SAAO,EAAE,aAAa,cAAc;AACtC;AASA,IAAM,gCAAgC;AAUtC,IAAM,4BAA4B;AAClC,IAAM,8BAA8B;AACpC,IAAM,6BAA6B;AAOnC,IAAM,gCAAgC;AAMtC,IAAM,wBAAwB;AAE9B,IAAM,QAAQ,CAAC,OAA8B,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAI7F,IAAM,qBAAqB;AAK3B,IAAM,+BAAN,cAA2C,MAAM;AAAA,EAC/C,YAAY,WAAmB;AAC7B,UAAM,iBAAiB,SAAS,uBAAuB;AACvD,SAAK,OAAO;AAAA,EACd;AACF;AAOA,SAAS,gBACP,KACA,KACA,WACqB;AACrB,SAAO,IAAI,QAAoB,CAAC,SAAS,WAAW;AAClD,QAAI,UAAU;AACd,UAAM,QAAQ,WAAW,MAAM;AAC7B,UAAI,QAAS;AACb,gBAAU;AACV,aAAO,IAAI,6BAA6B,SAAS,CAAC;AAAA,IACpD,GAAG,SAAS;AACZ,QAAI,KAAK,KAAK,EAAE,UAAU,CAAC,EAAE;AAAA,MAC3B,CAAC,QAAQ;AACP,YAAI,QAAS;AACb,kBAAU;AACV,qBAAa,KAAK;AAClB,gBAAQ,GAAG;AAAA,MACb;AAAA,MACA,CAAC,QAAQ;AACP,YAAI,QAAS;AACb,kBAAU;AACV,qBAAa,KAAK;AAClB,eAAO,GAAG;AAAA,MACZ;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,IAAM,8BAA8B,oBAAI,IAAI,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG,CAAC;AACpF,IAAM,yBAAyB;AAC/B,IAAM,4BACJ;AACF,IAAM,+BAA+B;AAErC,SAAS,YAAY,KAAyF;AAC5G,QAAM,YAAY,IAAI,UAAU,IAAI,eAClC,IAAI,YAAY,OAAO,IAAI,aAAa,WACnC,IAAI,SAAkC,SACvC;AAEN,MAAI,OAAO,cAAc,SAAU,QAAO;AAC1C,MAAI,OAAO,cAAc,YAAY,QAAQ,KAAK,SAAS,EAAG,QAAO,OAAO,SAAS;AACrF,SAAO;AACT;AAEA,SAAS,aAAa,KAAc,OAAO,oBAAI,IAAY,GAAuB;AAChF,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,MAAI,KAAK,IAAI,GAAG,EAAG,QAAO;AAC1B,OAAK,IAAI,GAAG;AACZ,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,iBAAiB,SAAU,QAAO,EAAE;AACjD,SAAO,aAAa,EAAE,OAAO,IAAI;AACnC;AAEA,SAAS,qBAAqB,KAAc,OAAO,oBAAI,IAAY,GAAY;AAC7E,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,MAAI,KAAK,IAAI,GAAG,EAAG,QAAO;AAC1B,OAAK,IAAI,GAAG;AACZ,QAAM,IAAI;AAQV,QAAM,SAAS,YAAY,CAAC;AAC5B,MAAI,WAAW,UAAa,4BAA4B,IAAI,MAAM,EAAG,QAAO;AAC5E,MAAI,OAAO,EAAE,SAAS,UAAU;AAC9B,QAAI,uBAAuB,KAAK,EAAE,IAAI,EAAG,QAAO;AAChD,QAAI,0EAA0E,KAAK,EAAE,IAAI,EAAG,QAAO;AAAA,EACrG;AACA,MAAI,OAAO,EAAE,YAAY,YAAY,0BAA0B,KAAK,EAAE,OAAO,EAAG,QAAO;AACvF,SAAO,qBAAqB,EAAE,OAAO,IAAI;AAC3C;AAEA,SAAS,uBAAuB,KAAc,OAAO,oBAAI,IAAY,GAAY;AAC/E,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,MAAI,KAAK,IAAI,GAAG,EAAG,QAAO;AAC1B,OAAK,IAAI,GAAG;AACZ,QAAM,IAAI;AASV,MAAI,YAAY,CAAC,MAAM,IAAK,QAAO;AACnC,MACE,OAAO,EAAE,SAAS,YAClB,6GAA6G,KAAK,EAAE,IAAI,GACxH;AACA,WAAO;AAAA,EACT;AACA,MACE,OAAO,EAAE,SAAS,YAClB,6FAA6F,KAAK,EAAE,IAAI,GACxG;AACA,WAAO;AAAA,EACT;AACA,SAAO,uBAAuB,EAAE,OAAO,IAAI;AAC7C;AAEA,SAAS,2BAA2B,KAAuB;AACzD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,SACE,uBAAuB,GAAG,KAC1B,YAAY,GAAqE,MAAM;AAE3F;AAOA,SAAS,mBAAmB,KAA6D;AACvF,MAAI,eAAe,6BAA8B,QAAO,EAAE,WAAW,KAAK;AAC1E,MAAI,qBAAqB,GAAG,EAAG,QAAO,EAAE,WAAW,MAAM,cAAc,aAAa,GAAG,EAAE;AACzF,SAAO,EAAE,WAAW,MAAM;AAC5B;AAEA,SAAS,2BAA2B,OAAqC,MAAc,OAAqB;AAC1G,SAAO,IAAI,MAAM,iCAAiC,KAAK,QAAQ,IAAI,KAAK,MAAM,OAAO,IAAI,EAAE,MAAM,CAAC;AACpG;AAIO,IAAM,iCAAN,cAA6C,MAAM;AAAA,EACxD,YAAY,OAAyB,MAAc,QAAgB,OAAiB;AAClF,UAAM,GAAG,KAAK,oCAAoC,IAAI,KAAK,MAAM,IAAI,EAAE,MAAM,CAAC;AAC9E,SAAK,OAAO;AAAA,EACd;AACF;AAqCA,SAAS,cAAc,OAA6C;AAClE,MAAI,MAAM,SAAS,SAAS,SAAU,QAAO;AAC7C,MAAI;AACJ,MAAI,MAAM,KAAK,WAAW,IAAI,EAAG,OAAM,MAAM,KAAK,MAAM,CAAC;AAAA,WAChD,MAAM,KAAK,WAAW,cAAc,EAAG,OAAM,MAAM,KAAK,MAAM,eAAe,MAAM;AAAA,WACnF,MAAM,KAAK,WAAW,GAAG,KAAK,MAAM,KAAK,WAAW,GAAG,EAAG,QAAO;AAAA,MACrE,OAAM,MAAM;AACjB,MAAI,IAAI,WAAW,KAAK,IAAI,WAAW,GAAG,KAAK,IAAI,MAAM,GAAG,EAAE,KAAK,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,UAAU,GAAG;AAC/G,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,OAAuC;AACtE,SAAO,MAAM,cAAc,mBAAmB,KAAK,MAAM,IAAI;AAC/D;AAEA,SAAS,gBAAgB,OAAkD;AACzE,SAAO,wBAAwB,KAAK,IAAI,MAAQ;AAClD;AAEA,SAAS,oBAAoB,KAA+B;AAC1D,QAAM,KAAK,IAAI;AACf,SAAO,IAAI,sBAAsB;AACnC;AAEA,eAAsB,uBACpB,KACA,OACA,UAAoC,CAAC,GACb;AACxB,QAAM,gBAAgB,QAAQ,iBAAiB;AAC/C,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,aAAa,QAAQ,cAAc;AAUzC,QAAM,mBAAmB,OAAO,IAAI,IAAI,cAAc;AACtD,QAAM,mBAAmB,oBAAoB,GAAG;AAChD,QAAM,aAAiE,CAAC;AACxE,QAAM,UAAmC,CAAC;AAC1C,aAAW,SAAS,OAAO;AACzB,QAAI,MAAM,SAAS,SAAS,SAAU;AACtC,UAAM,cAAc,mBAAmB,cAAc,KAAK,IAAI;AAC9D,UAAM,aAAa,wBAAwB,KAAK;AAChD,QAAI,gBAAgB,SAAS,CAAC,cAAc,mBAAmB;AAC7D,YAAM,OAAO,gBAAgB,KAAK;AAClC,iBAAW,KAAK;AAAA,QACd,MAAM;AAAA,QACN,SAAS,MAAM,SAAS,WAAW;AAAA,QACnC,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,MACvC,CAAC;AAAA,IACH,MACK,SAAQ,KAAK,KAAK;AAAA,EACzB;AACA,MAAI,WAAW,SAAS,GAAG;AAIzB,QAAI;AACF,YAAM,IAAI,GAAG,UAAU,YAAY,EAAE,QAAQ,WAAW,CAAC;AAAA,IAC3D,SAAS,KAAK;AACZ,aAAO,KAAK,IAAI,MAAM,uDAAuD,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,IAC9F;AAAA,EACF;AAIA,MAAI,cAAc;AAOlB,QAAM,eAAe,OAAU,KAAuB,SAAsC;AAC1F,aAAS,UAAU,KAAK,WAAW;AACjC,UAAI,eAAe,SAAS,EAAG,OAAM,MAAM,MAAM;AACjD,oBAAc;AACd,UAAI;AACF,eAAO,GAAG,MAAM,IAAI,CAAC;AAAA,MACvB,SAAS,KAAK;AACZ,cAAM,EAAE,WAAW,cAAAC,cAAa,IAAI,mBAAmB,GAAG;AAC1D,YAAI,aAAa,UAAU,YAAY;AACrC,gBAAM,UAAU,KAAK,IAAI,8BAA8B,KAAK,SAAS,0BAA0B;AAC/F,gBAAM,MAAMA,iBAAgB,OAAO;AACnC;AAAA,QACF;AACA,eAAO,KAAK,IAAI,MAAM,2CAA2C,IAAI,IAAI,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,MAC1F;AAAA,IACF;AAAA,EACF;AAEA,aAAW,SAAS,SAAS;AAC3B,QAAI,MAAM,SAAS,SAAS,SAAU;AACtC,UAAM,UAAU,MAAM,SAAS,WAAW;AAC1C,UAAM,OAAO,MAAM;AAEnB,UAAM,MAAM,OAAO,KAAK,SAAS,MAAM,EAAE,SAAS,QAAQ;AAC1D,UAAM,YAAsB,CAAC;AAC7B,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK,+BAA+B;AAClE,gBAAU,KAAK,IAAI,MAAM,GAAG,IAAI,6BAA6B,CAAC;AAAA,IAChE;AACA,UAAM,iBAAiB,WAAW,QAAQ,EAAE,OAAO,SAAS,MAAM,EAAE,OAAO,KAAK;AAChF,UAAM,MAAM,KAAK,QAAQ,YAAY,EAAE;AACvC,UAAM,aAAa,wBAAwB,KAAK;AAChD,UAAM,IAAI,UAAU,IAAI;AACxB,UAAM,OAAO,UAAU,GAAG,IAAI,MAAM;AACpC,UAAM,OAAO,UAAU,GAAG,IAAI,MAAM;AACpC,UAAM,cAAc,UAAU,GAAG,IAAI,YAAY;AAKjD,UAAM,OAAO,OAAO,QAAwC;AAC1D,YAAMC,OAAM,MAAM,aAAa,MAAM,gBAAgB,KAAK,KAAK,aAAa,GAAG,IAAI;AACnF,UAAI,CAACA,KAAI,UAAW,QAAOA;AAC3B,YAAM,OAAOA,KAAI;AACjB,UAAI,KAAK,aAAa,GAAG;AACvB,eAAO;AAAA,UACL,IAAI;AAAA,YACF,2CAA2C,IAAI,UAAU,KAAK,QAAQ,MAAM,KAAK,OAAO,MAAM,GAAG,GAAG,CAAC;AAAA,UACvG;AAAA,QACF;AAAA,MACF;AACA,aAAO,GAAG,MAAS;AAAA,IACrB;AAIA,UAAM,QAAQ,OAAO,QAAQ,OAAO,YAAY,UAAU,GAAG,CAAC,KAAK;AACnE,QAAI,MAAM,MAAM,KAAK,KAAK;AAC1B,QAAI,CAAC,IAAI,UAAW,QAAO;AAK3B,aAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,YAAM,QAAQ,UAAU,CAAC;AACzB,YAAM,MAAM,KAAK,gBAAgB,KAAK,OAAO,UAAU,GAAG,IAAI,aAAa,CAAC,EAAE,CAAC,EAAE;AACjF,UAAI,CAAC,IAAI,UAAW,QAAO;AAAA,IAC7B;AAOA,UAAM,QAAQ,aAAa,YAAY,CAAC,iBAAiB;AACzD,UAAM,mBAAmB,iBAAiB,iDAAiD,IAAI,EAAE;AACjG,UAAM,WACJ,aAAa,cAAc,cAChB,CAAC,wBAAwB,CAAC,+CAClC,KAAK,SAAS,IAAI,IAAI,IAAI,2BAA2B,UAAU,MAAM,gBAAgB,WAAW,yCAC5F,IAAI,6BACc,UAAU,MAAM,cAAc,WAAW,SAAS,IAAI,6CAClE,IAAI,MAAM,IAAI,sBACT,IAAI,mDAAmD,gBAAgB,uBACnF,IAAI,IAAI,CAAC,OACZ,aAAa,YAAY,CAAC,SAAS,EAAE,kBACtB,CAAC,mDAAmD,gBAAgB,0BAC7E,IAAI,IAAI,IAAI,2BAA2B,UAAU,MAAM,gBAAgB,WAAW;AAC7F,UAAM,MAAM,KAAK,QAAQ;AACzB,QAAI,CAAC,IAAI,UAAW,QAAO;AAAA,EAC7B;AACA,SAAO,GAAG,MAAS;AACrB;AASA,IAAM,2BAA2B;AAK1B,SAAS,mBAAmB,OAAwC;AACzE,QAAM,OAAO,MACV,IAAI,CAAC,OAAO;AAAA,IACX,GAAG,EAAE;AAAA,IACL,GAAG,EAAE,SAAS,SAAS,WAAa,EAAE,SAAkC,WAAW,KAAM,OAAO,EAAE,SAAS,IAAI;AAAA,EACjH,EAAE,EACD,KAAK,CAAC,GAAG,MAAO,EAAE,IAAI,EAAE,IAAI,KAAK,EAAE,IAAI,EAAE,IAAI,IAAI,CAAE;AACtD,SAAO,WAAW,QAAQ,EAAE,OAAO,KAAK,UAAU,IAAI,GAAG,MAAM,EAAE,OAAO,KAAK;AAC/E;AAEA,eAAe,uCACb,OACA,QACA,KACA,OACA,MACA,aACA,QACmC;AACnC,MAAI,CAAC,MAAM,kBAAmB,QAAO,GAAG,GAAG;AAC3C,QAAM,0BAA0B,MAAM,MAAM,wBAAwB,WAAW;AAC/E,QAAM,WAAgC;AAAA,IACpC;AAAA,IACA;AAAA,IACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,EAC7B;AACA,QAAM,QAAQ,MAAM,MAAM,MAAM,QAAQ;AACxC,QAAM,cAAc,MAAM,QAAQ,EAAE,YAAY,MAAM,CAAC;AACvD,QAAM,EAAE,cAAc,IAAI,0BAA0B,WAAW;AAC/D,MAAI,cAAc,WAAW,EAAG,QAAO,GAAG,GAAG;AAS7C,QAAM,cAAe,IAAI,WAAmD,wBAAwB;AACpG,MAAI,OAAO,gBAAgB,YAAY,gBAAgB,mBAAmB,aAAa,EAAG,QAAO,GAAG,GAAG;AACvG,SAAO,yCAAyC,QAAQ,KAAK,eAAe,OAAO,IAAI;AACzF;AAEA,eAAe,YACb,QACA,MAC0C;AAC1C,MAAI;AACF,UAAM,UAAU,MAAM,OAAO,KAAK,EAAE,QAAQ,UAAU,CAAC;AACvD,WAAO,GAAG,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,KAAK,IAAI;AAAA,EACxD,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAEA,eAAe,YACb,QACA,MAC0C;AAC1C,MAAI;AACF,UAAM,UAAU,MAAM,OAAO,KAAK,EAAE,QAAQ,UAAU,CAAC;AACvD,WAAO,GAAG,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,KAAK,IAAI;AAAA,EACxD,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAEA,eAAe,UAAU,KAA8C;AACrE,MAAI;AACF,UAAM,IAAI,OAAO;AACjB,WAAO,GAAG,MAAS;AAAA,EACrB,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAoBO,IAAM,8BAA8B;AAKpC,IAAM,sBAAsB;AAI5B,IAAM,sBAAsB;AAEnC,SAAS,eAAe,OAAwB;AAC9C,SAAO,IAAI,YAAY,EAAE,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,SAAS,IAAI,CAAC,EAC9F;AACL;AA0BO,SAAS,gCAAgC,SAAyC;AACvF,QAAM,QAAQ,eAAe,OAAO;AACpC,MAAI,SAAS,4BAA6B;AAC1C,QAAM,UAAU,QAAQ,SAAS;AACjC,QAAM,SAAS,OAAO,YAAY,WAAW,SAAY,SAAS,WAAW,UAAU,CAAC;AACxF,QAAM,YACJ,WAAW,eAAe,WAAW,IAAI,CAAC,YAChC,eAAe,KAAK,CAAC,WACxB,eAAe,QAAQ,OAAO,CAAC,CAAC,CAAC,cAC7B,eAAe,QAAQ,WAAW,CAAC,CAAC,CAAC;AAClD,QAAM,IAAI;AAAA,IACR,gCAAgC,KAAK,0BAAqB,2BAA2B,yHAErE,SAAS;AAAA,EAE3B;AACF;AAQO,SAAS,sBAAsB,KAAmC;AACvE,MAAI,QAAQ;AACZ,MAAI,UAAkD;AACtD,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC/C,UAAM,QAAQ,eAAe,GAAG,IAAI,IAAI,KAAK,EAAE;AAC/C,aAAS;AACT,QAAI,CAAC,WAAW,QAAQ,QAAQ,MAAO,WAAU,EAAE,MAAM,MAAM;AAC/D,QAAI,QAAQ,qBAAqB;AAC/B,YAAM,IAAI;AAAA,QACR,mBAAmB,IAAI,OAAO,KAAK,0BAAqB,mBAAmB;AAAA,MAG7E;AAAA,IACF;AAAA,EACF;AACA,MAAI,QAAQ,qBAAqB;AAC/B,UAAM,QAAQ,UAAU,aAAa,QAAQ,IAAI,KAAK,QAAQ,KAAK,QAAQ;AAC3E,UAAM,IAAI;AAAA,MACR,wBAAwB,KAAK,gCAA2B,mBAAmB,cAAc,KAAK;AAAA,IAEhG;AAAA,EACF;AACF;AAMA,eAAe,WACb,KACA,SACA,OACkB;AAClB,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,cAAc,MAAM,iBAAiB;AAC3C,QAAM,YAAY,MAAM,eAAe;AACvC,QAAM,OAAO,CAAI,GAAe,IAAY,UAC1C,QAAQ,KAAK;AAAA,IACX;AAAA,IACA,IAAI,QAAW,CAAC,GAAG,WAAW,WAAW,MAAM,OAAO,IAAI,MAAM,KAAK,CAAC,GAAG,EAAE,CAAC;AAAA,EAC9E,CAAC;AACH,MAAI;AACF,UAAM,QAAQ,MAAM,KAAK,IAAI,KAAK,YAAY,GAAG,aAAa,qBAAqB;AACnF,QAAI,CAAC,MAAM,OAAO,SAAS,OAAO,EAAG,QAAO;AAC5C,UAAM,UAAU,MAAM,sBAAsB,OAAO;AACnD,QAAI;AACF,YAAM,KAAK,MAAM;AAAA,QACf,IAAI,KAAK,YAAY,iBAAiB,OAAO,CAAC,qBAAqB;AAAA,QACnE;AAAA,QACA;AAAA,MACF;AACA,UAAI,GAAG,OAAO,SAAS,YAAY,EAAG,QAAO;AAAA,IAC/C,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AAgBnC,SAAS,kBAAkB,KAA0C;AACnE,QAAM,aAAkD,IAAI;AAC5D,SAAO,YAAY,cAAc,YAAY;AAC/C;AAEA,SAAS,uBAAuB,OAA+D;AAC7F,MAAI,iBAAiB,KAAM,QAAO,MAAM,QAAQ;AAChD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,GAAI,QAAO;AAC7D,QAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,SAAO,OAAO,MAAM,MAAM,IAAI,SAAY;AAC5C;AAEA,SAAS,wBAAwB,KAAsB,MAAM,KAAK,IAAI,GAAY;AAChF,QAAM,aAAkD,IAAI;AAC5D,QAAM,QAAQ,YAAY,aAAa,YAAY;AACnD,MAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC,MAAO,QAAO;AAC9C,QAAM,YAAY;AAAA,IAChB,YAAY,sBAAsB,YAAY;AAAA,EAChD;AACA,SAAO,cAAc,UAAa,YAAY,MAAM;AACtD;AAEA,SAAS,kBAAkB,KAA+B;AAExD,QAAM,aAAa,IAAI;AACvB,SAAO,YAAY,eAAe,YAAY,QAAQ,YAAY,SAAS;AAC7E;AAEA,eAAe,yBACb,QACA,KAC0B;AAC1B,MAAI,UAAU;AACd,MAAI,kBAAkB,OAAO,EAAG,QAAO;AAEvC,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,SAAO,KAAK,IAAI,IAAI,UAAU;AAM5B,QAAI;AACF,YAAM,QAAQ,QAAQ;AACtB,UAAI,kBAAkB,OAAO,EAAG,QAAO;AAEvC,YAAM,SAAS,MAAM,OAAO,IAAI,QAAQ,EAAE;AAC1C,UAAI,OAAQ,WAAU;AACtB,UAAI,kBAAkB,OAAO,EAAG,QAAO;AAAA,IACzC,QAAQ;AAAA,IAER;AAEA,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,0BAA0B,CAAC;AAAA,EAChF;AAEA,SAAO;AACT;AAEA,eAAe,iCACb,QACA,KACA,OACA,MACmC;AACnC,MAAI,UAAU;AAEd,MAAI;AACF,UAAM,QAAQ,QAAQ;AACtB,QAAI,wBAAwB,OAAO,EAAG,QAAO,GAAG,OAAO;AAAA,EACzD,SAAS,KAAK;AACZ,QAAI,2BAA2B,GAAG,GAAG;AACnC,aAAO;AAAA,QACL,IAAI;AAAA,UACF;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AACF,UAAM,SAAS,MAAM,OAAO,IAAI,QAAQ,EAAE;AAC1C,QAAI,OAAQ,WAAU;AACtB,QAAI,wBAAwB,OAAO,EAAG,QAAO,GAAG,OAAO;AAAA,EACzD,SAAS,KAAK;AACZ,QAAI,2BAA2B,GAAG,GAAG;AACnC,aAAO;AAAA,QACL,IAAI;AAAA,UACF;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,GAAG,OAAO;AACnB;AAEA,eAAe,uBACb,QACA,KACA,OACA,MACmC;AACnC,MAAI,UAAU;AACd,MAAI;AACJ,QAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,SAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,QAAI;AACF,YAAM,QAAQ,QAAQ;AACtB,UAAI,wBAAwB,OAAO,EAAG,QAAO,GAAG,OAAO;AAEvD,YAAM,SAAS,MAAM,OAAO,IAAI,QAAQ,EAAE;AAC1C,UAAI,OAAQ,WAAU;AACtB,UAAI,wBAAwB,OAAO,EAAG,QAAO,GAAG,OAAO;AAAA,IACzD,SAAS,KAAK;AACZ,kBAAY;AAAA,IACd;AAEA,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,0BAA0B,CAAC;AAAA,EAChF;AAEA,QAAM,SAAS,kBAAkB,OAAO,IACpC,kEACA;AACJ,SAAO,KAAK,IAAI,+BAA+B,OAAO,MAAM,QAAQ,SAAS,CAAC;AAChF;AAEA,eAAe,yCACb,QACA,KACA,OACA,OACA,MACmC;AACnC,MAAI,WAAW;AAEf,MAAI,CAAC,wBAAwB,QAAQ,GAAG;AACtC,UAAMC,aAAY,MAAM,iCAAiC,QAAQ,UAAU,OAAO,IAAI;AACtF,QAAI,CAACA,WAAU,UAAW,QAAO,KAAKA,WAAU,KAAK;AACrD,eAAWA,WAAU;AAAA,EACvB;AAEA,QAAM,QAAQ,MAAM,uBAAuB,UAAU,KAAK;AAC1D,MAAI,MAAM,UAAW,QAAO,GAAG,QAAQ;AACvC,MAAI,CAAC,uBAAuB,MAAM,KAAK,EAAG,QAAO,KAAK,MAAM,KAAK;AAEjE,QAAM,YAAY,MAAM,uBAAuB,QAAQ,UAAU,OAAO,IAAI;AAC5E,MAAI,CAAC,UAAU,UAAW,QAAO,KAAK,UAAU,KAAK;AAErD,QAAM,SAAS,MAAM,uBAAuB,UAAU,OAAO,KAAK;AAClE,MAAI,OAAO,UAAW,QAAO,GAAG,UAAU,KAAK;AAC/C,MAAI,CAAC,uBAAuB,OAAO,KAAK,EAAG,QAAO,KAAK,OAAO,KAAK;AAEnE,SAAO;AAAA,IACL,IAAI;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAQA,eAAe,cACb,KACA,SACA,OACkB;AAClB,MAAI,kBAAkB,GAAG,EAAG,QAAO;AACnC,MAAI,CAAC,kBAAkB,GAAG,EAAG,QAAO;AACpC,SAAO,WAAW,KAAK,SAAS,KAAK;AACvC;AAGA,eAAe,iBACb,KACA,WACA,YACmC;AACnC,MAAI;AACF,UAAM,IAAI,OAAO;AACjB,UAAM,IAAI,QAAQ,WAAW,EAAE,WAAW,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC,EAAG,CAAC;AACjF,WAAO,GAAG,GAAG;AAAA,EACf,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAKA,eAAe,8BACb,OACA,aACA,QACiE;AACjE,QAAM,QAAsB,EAAE,aAAa,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC,EAAG;AACzE,QAAM,QAAQ,MAAM,MAAM,YAAY,KAAK;AAC3C,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,mDAAmD;AAC/E,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,mBAAmB,KAAK;AAAA,IAChC,MAAM,MAAM,SAAS,MAAM,OAAO,KAAK,IAAI,MAAM,KAAK,WAAW;AAAA,EACnE;AACF;AAyCA,eAAsB,qBACpB,OACA,SACsC;AACtC,QAAM,EAAE,QAAQ,KAAK,IAAI,MAAM,8BAA8B,OAAO,QAAQ,aAAa,QAAQ,MAAM;AACvG,QAAM,cAAc,MAAM,KAAK,QAAQ,WAAW;AAClD,QAAM,QAAQ,MAAM,OAAO,KAAK;AAChC,QAAM,QAAQ,MAAM,KAAK,CAAC,QAAQ,IAAI,SAAS,IAAI,KAAK,MAAM,KAAK,CAAC,QAAQ,IAAI,SAAS,WAAW;AACpG,MAAI,CAAC,MAAO,QAAO,EAAE,QAAQ,SAAS;AACtC,MAAI,MAAM,WAAW,UAAW,QAAO,EAAE,QAAQ,eAAe,OAAO,MAAM,QAAQ,KAAK,MAAM;AAChG,SAAO,EAAE,QAAQ,WAAW,KAAK,MAAM;AACzC;AAEA,eAAsB,uBACpB,OACA,SAC0B;AAC1B,QAAM,EAAE,aAAa,QAAQ,SAAS,UAAU,YAAY,eAAe,IAAI;AAC/E,QAAM,WAAW,MAAM,8BAA8B,OAAO,aAAa,MAAM;AAC/E,QAAM,EAAE,OAAO,OAAO,IAAI;AAC1B,MAAI,OAAO,SAAS;AACpB,MAAI;AACJ,QAAM,YAAY,MAAM,aAAa;AACrC,QAAM,gBAAgB;AAGtB,QAAM,WAAW,MAAM,YAAY,QAAQ,IAAI;AAC/C,MAAI,SAAS,aAAa,SAAS,OAAO;AACxC,UAAM,QAAQ,SAAS;AACvB,QAAI,UAAU;AACZ,YAAM,UAAU,MAAM,UAAU,KAAK;AACrC,UAAI,CAAC,QAAQ,WAAW;AACtB,cAAM,IAAI,MAAM,qBAAqB,IAAI,yBAAyB,EAAE,OAAO,QAAQ,MAAM,CAAC;AAAA,MAC5F;AAAA,IACF,WAAW,MAAM,UAAU,YAAY,SAAS;AAC9C,YAAM,QAAQ,MAAM,yBAAyB,QAAQ,KAAK;AAC1D,UAAI,MAAM,cAAc,OAAO,SAAS,MAAM,aAAa,GAAG;AAC5D,cAAM,UAAU,MAAM;AAAA,UACpB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,YAAI,CAAC,QAAQ,WAAW;AACtB,gBAAM,2BAA2B,UAAU,MAAM,QAAQ,KAAK;AAAA,QAChE;AACA,cAAM,YAAY,QAAQ;AAC1B,YAAI,MAAM,WAAW;AACnB,gBAAM,OAAO,MAAM,MAAM,UAAU,WAAW,KAAK;AACnD,cAAI,CAAC,KAAK,WAAW;AACnB,kBAAM,IAAI,MAAM,kCAAkC,IAAI,IAAI,EAAE,OAAO,KAAK,MAAM,CAAC;AAAA,UACjF;AAAA,QACF;AACA,eAAO;AAAA,MACT;AACA,YAAM,UAAU,MAAM,UAAU,KAAK;AACrC,UAAI,CAAC,QAAQ,WAAW;AACtB,cAAM,IAAI;AAAA,UACR,WAAW,IAAI,SACL,OAAO,MAAM,UAAU,WAAW,SAAS,CAAC,UAAU,OAAO;AAAA,UAEvE,EAAE,OAAO,QAAQ,MAAM;AAAA,QACzB;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,UAAU,MAAM,UAAU,KAAK;AACrC,UAAI,CAAC,QAAQ,WAAW;AACtB,cAAM,IAAI;AAAA,UACR,WAAW,IAAI,SACL,OAAO,MAAM,UAAU,WAAW,SAAS,CAAC,UAAU,OAAO;AAAA,UAEvE,EAAE,OAAO,QAAQ,MAAM;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,CAAC,YAAY,MAAM,kBAAkB,OAAO;AAC9C,UAAM,UAAU,MAAM,YAAY,QAAQ,IAAI;AAC9C,QAAI,CAAC,QAAQ,UAAW,OAAM,QAAQ;AACtC,QAAI,QAAQ,OAAO;AACjB,YAAM,UAAU,MAAM,iBAAiB,QAAQ,OAAO,eAAe,UAAU;AAC/E,UAAI,CAAC,QAAQ,WAAW;AACtB,YAAI,CAAC,MAAM,sBAAuB,OAAM,QAAQ;AAChD,cAAM,WAAW,MAAM,MAAM,sBAAsB;AAAA,UACjD,KAAK,QAAQ;AAAA,UACb,OAAO,QAAQ;AAAA,UACf;AAAA,UACA,QAAQ;AAAA,QACV,CAAC;AACD,YAAI,CAAC,SAAS,UAAW,OAAM,SAAS;AACxC,YAAI,CAAC,SAAS,MAAO,OAAM,QAAQ;AACnC,cAAM,oBAAoB,SAAS,MAAM,kBAAkB,KAAK;AAChE,YAAI,CAAC,qBAAqB,sBAAsB,MAAM;AACpD,gBAAM,IAAI;AAAA,YACR,wEAAwE,IAAI;AAAA,YAC5E,EAAE,OAAO,QAAQ,MAAM;AAAA,UACzB;AAAA,QACF;AACA,eAAO;AACP,0BAAkB,SAAS,MAAM;AAAA,MACnC,OAAO;AACL,cAAMC,OAAM,MAAM,yBAAyB,QAAQ,QAAQ,KAAK;AAChE,YAAI,MAAM,cAAcA,MAAK,SAAS,MAAM,aAAa,GAAG;AAC1D,gBAAM,UAAU,MAAM;AAAA,YACpB;AAAA,YACA;AAAA,YACAA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AACA,cAAI,CAAC,QAAQ,WAAW;AACtB,kBAAM,2BAA2B,WAAW,MAAM,QAAQ,KAAK;AAAA,UACjE;AACA,gBAAM,aAAa,QAAQ;AAC3B,cAAI,MAAM,WAAW;AACnB,kBAAM,OAAO,MAAM,MAAM,UAAU,YAAY,KAAK;AACpD,gBAAI,CAAC,KAAK,WAAW;AACnB,oBAAM,IAAI,MAAM,mCAAmC,IAAI,IAAI,EAAE,OAAO,KAAK,MAAM,CAAC;AAAA,YAClF;AAAA,UACF;AACA,iBAAO;AAAA,QACT;AACA,cAAM,UAAU,MAAM,UAAUA,IAAG;AACnC,YAAI,CAAC,QAAQ,WAAW;AACtB,gBAAM,IAAI;AAAA,YACR,mBAAmB,IAAI,SACb,OAAOA,KAAI,UAAU,WAAW,SAAS,CAAC,UAAU,OAAO;AAAA,YAErE,EAAE,OAAO,QAAQ,MAAM;AAAA,UACzB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,0BAA0B,MAAM,MAAM,wBAAwB,WAAW;AAC/E,QAAM,WAAgC;AAAA,IACpC;AAAA,IACA;AAAA,IACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,EAC7B;AACA,QAAM,CAAC,SAAS,KAAK,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC9C,MAAM,QAAQ,WAAW;AAAA,IACzB,MAAM,IAAI,QAAQ;AAAA,IAClB,MAAM,MAAM,QAAQ;AAAA,EACtB,CAAC;AACD,QAAM,cAAc,MAAM,QAAQ,EAAE,YAAY,MAAM,CAAC;AAIvD,QAAM,EAAE,aAAa,cAAc,IAAI,MAAM,oBACzC,0BAA0B,WAAW,IACrC,EAAE,aAAa,aAAa,eAAe,CAAC,EAA6B;AAC7E,QAAM,UAAU;AAEhB,QAAM,OAAO,UAAU,MAAM,iBAAiB,MAAM,eAAe,WAAW,IAAI;AAIlF,MAAI,QAAQ,MAAM,uBAAuB,aAAa,MAAM,QAAQ,IAAI;AACxE,MAAI,SAAS,MAAM,gBAAgB,MAAM,aAAa,iBAAiB;AACrE,UAAM,SAAS,MAAM,MAAM,aAAa,KAAK;AAC7C,QAAI,OAAO,UAAW,SAAQ,EAAE,GAAG,OAAO,QAAQ,OAAO,MAAM;AAAA,SAC1D;AACH,cAAQ;AAAA,QACN,qCAAqC,WAAW;AAAA,QAChD,OAAO,MAAM;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,UAAU,QAAQ;AACxC,QAAM,UAAU,oBAAoB,SAAY,MAAM,UAAU,QAAQ,IAAI;AAE5E,QAAM,UAAU;AAAA,IACd;AAAA,IACA,OAAO,UAAU;AAAA;AAAA;AAAA,IAGjB,UAAU;AAAA,MACR,GAAG,MAAM,SAAS,OAAO;AAAA,MACzB,GAAI,cAAc,SAAS,IAAI,EAAE,CAAC,wBAAwB,GAAG,mBAAmB,aAAa,EAAE,IAAI,CAAC;AAAA,IACtG;AAAA,IACA,gBAAgB;AAAA;AAAA;AAAA,IAGhB,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;AAAA,IAC3C,GAAI,SAAS,EAAE,aAAa,EAAE,cAAc,CAAC,EAAE,QAAQ,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC;AAAA,IACtE;AAAA,IACA;AAAA,IACA,SAAS,EAAE,MAAM,SAAS,SAAS,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC,EAAG;AAAA,IAC/D,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAI,UAAU,UAAU,CAAC;AAAA,IACzB,GAAI,MAAM,qBAAqB,EAAE,oBAAoB,KAAK,IAAI,CAAC;AAAA,IAC/D,oBAAoB,UAAU;AAAA,IAC9B,oBAAoB,UAAU;AAAA,IAC9B,WAAW;AAAA,MACT,UAAU,UAAU;AAAA,MACpB,UAAU,UAAU;AAAA,MACpB,QAAQ,UAAU;AAAA,IACpB;AAAA,EACF;AAKA,wBAAsB,GAAG;AAGzB,kCAAgC,WAAW,CAAC,CAAC;AAE7C,MAAI,MAAM,MAAM,OAAO,OAAO,OAAO;AAErC,QAAM,IAAI,QAAQ,WAAW,EAAE,WAAW,MAAS,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC,EAAG,CAAC;AAC1F,QAAM,MAAM,yBAAyB,QAAQ,GAAG;AAEhD,MAAI,cAAc,SAAS,GAAG;AAC5B,UAAM,UAAU,MAAM,uBAAuB,KAAK,aAAa;AAC/D,QAAI,CAAC,QAAQ,WAAW;AACtB,YAAM,2BAA2B,OAAO,MAAM,QAAQ,KAAK;AAAA,IAC7D;AAAA,EACF;AAEA,MAAI,MAAM,WAAW;AACnB,UAAM,OAAO,MAAM,MAAM,UAAU,KAAK,KAAK;AAC7C,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,IAAI,MAAM,+BAA+B,IAAI,IAAI,EAAE,OAAO,KAAK,MAAM,CAAC;AAAA,IAC9E;AAAA,EACF;AACA,SAAO;AACT;AAWO,SAAS,aACd,QACA,UAC2B;AAC3B,QAAM,IAAI,UAAU,CAAC;AACrB,QAAM,kBAAkB,EAAE;AAC1B,QAAM,iBAAiB,UAAU,eAAe,EAAE;AAClD,QAAM,WACJ,EAAE,iBAAiB,iBAAiB,kBAAkB,EAAE,eAAe,WAAW;AACpF,QAAM,YACJ,UAAU,SACV,EAAE,cACD,aAAa,YAAY,aAAa,kBAAkB,EAAE,eAAe;AAC5E,QAAM,SAAS,mBAAmB,aAAa,WAAW,EAAE,eAAe;AAC3E,MAAI,CAAC,YAAY,CAAC,UAAW,QAAO;AACpC,MAAI,CAAC,UAAU,CAAC,EAAE,kBAAmB,QAAO;AAC5C,SAAO;AAAA,IACL,OAAO;AAAA,IACP;AAAA,IACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,kBAAkB,EAAE,SAAS,gBAAgB,IAAI,CAAC;AAAA,EACxD;AACF;AAWA,SAAS,kBACP,SACQ;AACR,SAAO,QACJ,IAAI,CAAC,UAAU,GAAG,MAAM,SAAS,cAAc,cAAc,MAAM,KAAK,MAAM,OAAO,EAAE,EACvF,KAAK,MAAM;AAChB;AAEO,SAAS,eACd,SACA,SACQ;AACR,MAAI,CAAC,SAAS,OAAQ,QAAO;AAC7B,SAAO,GAAG,kBAAkB,OAAO,CAAC;AAAA;AAAA,QAAa,OAAO;AAC1D;AAOO,SAAS,sBACd,OACA,SACmB;AACnB,MAAI,CAAC,SAAS,OAAQ,QAAO;AAC7B,QAAM,YAAY,MAAM,UAAU,CAAC,SAAS,KAAK,SAAS,MAAM;AAChE,MAAI,cAAc,IAAI;AACpB,UAAM,IAAI,MAAM,4EAA4E;AAAA,EAC9F;AACA,QAAM,WAAW,MAAM,SAAS;AAChC,QAAM,SAAS,CAAC,GAAG,KAAK;AACxB,SAAO,SAAS,IAAI,EAAE,GAAG,UAAU,MAAM,GAAG,kBAAkB,OAAO,CAAC;AAAA;AAAA,QAAa,SAAS,IAAI,GAAG;AACnG,SAAO;AACT;AAEO,SAAS,cACd,YACA,gBACA,OACuC;AACvC,aAAW,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,GAAG;AAC1C,QAAI,OAAO,cAAc,OAAO,gBAAgB;AAC9C,YAAM,IAAI,MAAM,iBAAiB,GAAG,gDAAgD;AAAA,IACtF;AAAA,EACF;AACA,SAAO,EAAE,GAAG,YAAY,GAAI,SAAS,CAAC,EAAG;AAC3C;AAEO,SAAS,sBACd,SACA,SACA,QACc;AACd,MAAI,CAAC,UAAU,WAAW,OAAQ,QAAO;AACzC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,YAAY;AAAA,MACV,GAAI,QAAQ,cAAc,CAAC;AAAA,MAC3B,CAAC,OAAO,GAAG;AAAA,QACT,GAAI,QAAQ,aAAa,OAAO,KAAK,CAAC;AAAA,QACtC,iBAAiB;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;AAuCA,gBAAuB,oBACrB,OACA,KACA,SACA,SACyB;AACzB,QAAM,UAAU,SAAS,WAAW;AACpC,QAAM,QAAQ,aAAa,MAAM,UAAU;AAAA,IACzC,OAAO,SAAS;AAAA,IAChB,aAAa,SAAS;AAAA,EACxB,CAAC;AAKD,MAAI,OAAO,MAAO,8BAA6B,SAAS,MAAM,KAAK;AAEnE,QAAM,SACJ,OAAO,YAAY,WACf,eAAe,SAAS,SAAS,OAAO,IACxC,sBAAsB,SAAS,SAAS,OAAO;AAErD,QAAM,aAAa,SAAS,cAAc,CAAC;AAC3C,QAAM,WAAW,cAAc,YAAY,SAAS,kBAAkB,CAAC,GAAG,SAAS,QAAQ;AAE3F,QAAM,UAAU,MAAM,QAAQ,EAAE,cAAc,SAAS,cAAc,SAAS,CAAC;AAC/E,QAAM,oBAAoB,sBAAsB,SAAS,SAAS,SAAS,MAAM;AAEjF,QAAM,SAAS,IAAI,aAAa,QAAQ;AAAA,IACtC,WAAW,SAAS;AAAA,IACpB,aAAa,SAAS;AAAA,IACtB,aAAa,SAAS;AAAA,IACtB,GAAI,SAAS,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,IACpD,GAAI,SAAS,cAAc,SAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,IAC3E,GAAI,SAAS,kCAAkC,SAC3C,EAAE,+BAA+B,QAAQ,8BAA8B,IACvE,CAAC;AAAA,IACL,GAAI,SAAS,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;AAAA,IAC1C,SAAS;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA,MACT,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,MACzB,GAAI,SAAS,eAAe,EAAE,cAAc,QAAQ,aAAa,IAAI,CAAC;AAAA,IACxE;AAAA,EACF,CAAwB;AAExB,MAAI,sBAAqC;AACzC,mBAAiB,SAAS,QAAQ;AAChC,UAAM,OAAO,sBAAsB,KAAK;AACxC,QAAI,KAAM,uBAAsB,KAAK,SAAS,iBAAiB,KAAK,UAAU,KAAK,SAAS;AAC5F,QAAI,uBAAuB,sBAAsB,KAAK,GAAG;AACvD,YAAM,IAAI,MAAM,kDAAkD,mBAAmB,IAAI;AAAA,IAC3F;AACA,QAAI,SAAS,mBAAmB;AAC9B,YAAM,IAAI,0BAA0B,KAAK;AACzC,UAAI,GAAG;AACL,cAAM,IAAI,MAAM,yEAAyE,CAAC,EAAE;AAAA,MAC9F;AAAA,IACF;AACA,UAAM;AAAA,EACR;AAGA,MAAI,qBAAqB;AACvB,UAAM,IAAI,MAAM,kDAAkD,mBAAmB,IAAI;AAAA,EAC3F;AACF;AAEA,eAAsB,iBACpB,OACA,KACA,SACA,SACiB;AACjB,MAAI,WAAW;AACf,MAAI,gBAAgB;AAEpB,mBAAiB,YAAY,oBAAoB,OAAO,KAAK,SAAS,OAAO,GAAG;AAC9E,UAAM,QAAQ;AACd,QAAI,CAAC,MAAM,KAAM;AAEjB,QAAI,MAAM,SAAS,wBAAwB;AACzC,YAAM,OAAO,MAAM,MAAM;AACzB,YAAM,QAAQ,OAAO,MAAM,MAAM,UAAU,WAAW,MAAM,KAAK,QAAQ;AACzE,UAAI,OAAO,MAAM,QAAQ,EAAE,MAAM,QAAQ;AACvC,YAAI,CAAC,eAAe;AAClB,0BAAgB;AAChB;AAAA,QACF;AACA,YAAI,MAAO,aAAY;AAAA,iBACd,OAAO,MAAM,SAAS,SAAU,YAAW,KAAK;AAAA,MAC3D;AAAA,IACF,WAAW,MAAM,SAAS,UAAU;AAClC,YAAM,YAAY,OAAO,MAAM,MAAM,cAAc,WAAW,MAAM,KAAK,YAAY;AACrF,UAAI,UAAW,YAAW;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AACT;AAYA,eAAsB,qBACpB,KACA,MACA,QACA,MACwB;AACxB,MAAI;AACF,UAAM,IAAI,YAAY,IAAI,EAAE,QAAQ,MAAM,KAAK,kBAAkB,IAAI,EAAE,CAAC;AACxE,WAAO,GAAG,MAAS;AAAA,EACrB,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAEA,eAAsB,wBACpB,KACA,QACwB;AACxB,MAAI;AACF,UAAM,IAAI,YAAY,OAAO,QAAQ,EAAE,iBAAiB,KAAK,CAAC;AAC9D,WAAO,GAAG,MAAS;AAAA,EACrB,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAEA,eAAsB,sBACpB,KACA,MACA,QACA,MACwB;AACxB,MAAI;AACF,UAAM,IAAI,YAAY,OAAO,QAAQ,EAAE,MAAM,KAAK,kBAAkB,IAAI,EAAE,CAAC;AAC3E,WAAO,GAAG,MAAS;AAAA,EACrB,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AASO,SAAS,sBAAsB,OAA0C;AAC9E,QAAM,SAAS,UAAU,KAAK;AAC9B,SAAO;AAAA,IACL,QAAQ,OAAO,MAAM,UAAU;AAC7B,YAAM,OAAO,QAAQ,OAAO,MAAM,KAAK;AAAA,IACzC;AAAA,IACA,QAAQ,OAAO,MAAM,UAAU;AAC7B,YAAM,OAAO,QAAQ,OAAO,MAAM,KAAK;AAAA,IACzC;AAAA,IACA,KAAK,CAAC,SAAS,OAAO,QAAQ,IAAI,IAAI;AAAA,IACtC,QAAQ,OAAO,SAAS;AACtB,YAAM,OAAO,QAAQ,OAAO,IAAI;AAAA,IAClC;AAAA,EACF;AACF;AAEA,eAAsB,YACpB,OACA,MACA,OACwB;AACxB,MAAI;AACF,UAAM,MAAM,OAAO,MAAM,KAAK;AAC9B,WAAO,GAAG,MAAS;AAAA,EACrB,QAAQ;AACN,QAAI;AACF,YAAM,MAAM,OAAO,MAAM,KAAK;AAC9B,aAAO,GAAG,MAAS;AAAA,IACrB,SAAS,KAAK;AACZ,aAAO,KAAK,IAAI,MAAM,kCAAkC,IAAI,IAAI,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,IACjF;AAAA,EACF;AACF;AAEA,eAAsB,WAAW,OAAoB,MAAwC;AAC3F,MAAI;AACF,WAAO,GAAG,MAAM,MAAM,IAAI,IAAI,CAAC;AAAA,EACjC,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAEA,eAAsB,aAAa,OAAoB,MAAsC;AAC3F,MAAI;AACF,UAAM,MAAM,OAAO,IAAI;AACvB,WAAO,GAAG,MAAS;AAAA,EACrB,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAaA,eAAsB,uBACpB,KACA,SACqC;AACrC,MAAI;AACF,UAAM,QAAQ,MAAM,IAAI,gBAAgB;AAAA,MACtC,OAAO,QAAQ;AAAA,MACf,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,MAC5D,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,IACjE,CAAC;AACD,WAAO,GAAG,EAAE,OAAO,MAAM,OAAO,WAAW,MAAM,WAAW,OAAO,MAAM,MAAM,CAAC;AAAA,EAClF,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAkCA,eAAsB,iBACpB,OACA,KACA,SACA,SACmC;AACnC,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,QAAQ,aAAa,MAAM,UAAU;AAAA,IACzC,OAAO,QAAQ;AAAA,IACf,aAAa,QAAQ;AAAA,EACvB,CAAC;AACD,MAAI,OAAO,MAAO,8BAA6B,SAAS,MAAM,KAAK;AACnE,QAAM,SACJ,OAAO,YAAY,WACf,eAAe,SAAS,QAAQ,OAAO,IACvC,sBAAsB,SAAS,QAAQ,OAAO;AACpD,QAAM,aAAa,QAAQ,cAAc,CAAC;AAC1C,QAAM,WAAW,cAAc,YAAY,QAAQ,kBAAkB,CAAC,GAAG,QAAQ,QAAQ;AACzF,QAAM,UAAU;AAAA,IACd,MAAM,QAAQ,EAAE,cAAc,QAAQ,cAAc,SAAS,CAAC;AAAA,IAC9D;AAAA,IACA,QAAQ;AAAA,EACV;AACA,MAAI;AACF,UAAM,QAAQ,MAAM,IAAI,UAAU,QAAQ;AAAA,MACxC,WAAW,QAAQ;AAAA,MACnB,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,MACnD,GAAI,QAAQ,cAAc,SAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,MAC1E,GAAI,QAAQ,cAAc,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,MAClE,GAAI,QAAQ,cAAc,SAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,MAC1E,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA;AAAA;AAAA,MAGnD,SAAS,EAAE,MAAM,SAAS,SAAS,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC,EAAG;AAAA,IACjE,CAAgD;AAChD,WAAO,GAAG,KAAK;AAAA,EACjB,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;AAIA,IAAM,yBAAyB,oBAAI,IAAI,CAAC,SAAS,SAAS,SAAS,CAAC;AAMpE,SAAS,cAAc,GAA4C;AACjE,SAAO,KAAK,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,CAAC,IAAK,IAAgC;AAC5F;AAEO,SAAS,sBAAsB,OAA8C;AAClF,QAAM,OAAO,cAAc,KAAK;AAChC,MAAI,CAAC,QAAQ,KAAK,SAAS,uBAAwB,QAAO;AAC1D,QAAM,OAAO,cAAc,KAAK,UAAU,KAAK,cAAc,KAAK,IAAI,KAAK;AAC3E,QAAM,OAAO,cAAc,KAAK,IAAI;AACpC,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,KAAK,SAAS,aAAc,QAAO,EAAE,MAAM,aAAa;AAC5D,MAAI,KAAK,SAAS,cAAe,QAAO;AACxC,QAAM,SAAS,OAAO,KAAK,WAAW,YAAY,KAAK,SAAS,KAAK,SAAS;AAC9E,SAAO,EAAE,MAAM,eAAe,QAAQ,SAAS,uBAAuB,IAAI,MAAM,EAAE;AACpF;AAEO,SAAS,sBAAsB,OAAyB;AAC7D,QAAM,IAAI,cAAc,KAAK,GAAG;AAChC,SAAO,MAAM,YAAY,MAAM;AACjC;AAIO,SAAS,0BAA0B,OAA+B;AACvE,QAAM,OAAO,cAAc,KAAK;AAChC,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AACzD,QAAM,OAAO,cAAc,KAAK,IAAI;AACpC,QAAM,QAAQ,cAAc,KAAK,UAAU;AAC3C,QAAM,OAAO,SAAS,QAAQ;AAC9B,MAAI,SAAS,oBAAoB,SAAS,WAAY,QAAO,kBAAkB,IAAI;AAGnF,MAAI,SAAS,iBAAiB,KAAK,SAAS,WAAY,QAAO,kBAAkB,IAAI;AACrF,QAAM,OAAO,cAAc,MAAM,IAAI,KAAK,cAAc,KAAK,IAAI;AACjE,QAAM,OACH,OAAO,MAAM,SAAS,YAAY,KAAK,QACvC,OAAO,MAAM,SAAS,YAAY,KAAK,QACvC,OAAO,KAAK,SAAS,YAAY,KAAK,QACvC;AACF,QAAM,MACJ,SAAS,2BACR,SAAS,cAAc,cAAc,IAAI,GAAG,SAAS;AACxD,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,QAAQ,cAAc,cAAc,IAAI,GAAG,KAAK;AACtD,SAAO,kBAAkB,cAAc,OAAO,KAAK,KAAK,SAAS,QAAQ,IAAI;AAC/E;AAEA,SAAS,kBAAkB,OAA+C;AACxE,QAAM,MAAM,MAAM,QAAQ,OAAO,SAAS,IACtC,MAAO,YACP,MAAM,QAAQ,cAAc,OAAO,KAAK,GAAG,SAAS,IACjD,cAAc,MAAO,KAAK,EAAG,YAC9B,CAAC;AACP,QAAM,QAAQ,cAAc,IAAI,CAAC,CAAC;AAClC,QAAM,IACH,OAAO,OAAO,aAAa,YAAY,MAAM,YAC7C,OAAO,OAAO,WAAW,YAAY,MAAM,UAC5C;AACF,SAAO,KAAK;AACd;","names":["value","credentials","retryAfterMs","res","refreshed","box"]}